Пример #1
0
    def notify(self, db, collection, iid, action, _parent):
        """
        Callback for the observer implemented in mongo.py.
        Each time an object is inserted, updated or deleted the standard way, this function will be called.

        Args:
            collection: the collection that has been modified
            iid: the mongo ObjectId _id that was modified/inserted/deleted
            action: string "update" or "insert" or "delete". It was the action performed on the iid
            _parent: Not used. the mongo ObjectId of the parent. Only if action in an insert. Not used anymore
        """
        apiclient = APIClient.getInstance()
        if not apiclient.getCurrentPentest() != "":
            return
        if apiclient.getCurrentPentest() != db:
            return
        if action == "update":
            if collection == "defects":
                defect_m = Defect.fetchObject({"_id": ObjectId(iid)})
                self.updateDefectInTreevw(defect_m, )
        elif action == "insert":
            view = None
            res = Defect.fetchObject({"_id": ObjectId(iid)})
            # Defect insertion takes place in calendarTreeview,
            # Remarks don't appear in the treeview, only in this module, so must notify here
            if collection == "remarks":
                self.addRemark(Remark.fetchObject({"_id": ObjectId(iid)}))
Пример #2
0
 def fillWithDefects(self):
     """
     Fetch defects that are global (not assigned to an ip) and fill the defect table with them.
     """
     table = Defect.getDefectTable()
     for line in table:
         self.addDefect(Defect(line))
Пример #3
0
 def removeItem(self, toDeleteIid):
     """
     Remove defect from given iid in defect treeview
     Args:
         toDeleteIid: database ID of defect to delete
     """
     try:
         item = self.treevw.item(toDeleteIid)
     except tk.TclError:
         return
     dialog = ChildDialogQuestion(
         self.parent, "DELETE WARNING",
         "Are you sure you want to delete defect " + str(item["text"]) +
         " ?", ["Delete", "Cancel"])
     self.parent.wait_window(dialog.app)
     if dialog.rvalue != "Delete":
         return
     self.treevw.delete(toDeleteIid)
     defectToDelete = Defect.fetchObject({
         "title": item["text"],
         "ip": "",
         "port": "",
         "proto": ""
     })
     if defectToDelete is not None:
         defectToDelete.delete()
         self.resizeDefectTreeview()
Пример #4
0
 def findDefectTemplateByTitle(self, title, multi=False):
     apiclient = APIClient.getInstance()
     defects_matching, msg = apiclient.searchDefect(title)
     if defects_matching is not None:
         if len(defects_matching) >= 1 and not multi:
             return Defect(defects_matching[0])
         else:
             return defects_matching
Пример #5
0
 def _insertChildrenDefects(self):
     """Insert every children defect in database as DefectView under this node"""
     defects = self.controller.getDefects()
     for defect in defects:
         defect_o = DefectController(Defect(defect))
         defect_vw = DefectView(self.appliTw, self.appliViewFrame,
                                self.mainApp, defect_o)
         defect_vw.addInTreeview(str(self.controller.getDbId()))
Пример #6
0
 def updateRiskBox(self, _event=None):
     """Callback when ease or impact is modified.
     Calculate new resulting risk value
     Args
         _event: mandatory but not used
     """
     ease = self.easeForm.getValue()
     impact = self.impactForm.getValue()
     risk = Defect.getRisk(ease, impact)
     self.riskForm.setValue(risk)
Пример #7
0
 def createDefectCallback(self, _event=None):
     """Callback for tool click #TODO move to ToolController
     Creates an empty defect view and open it's insert window with notes = tools notes.
     """
     modelData = self.controller.getData()
     toExport = modelData["notes"]
     for widget in self.appliViewFrame.winfo_children():
         widget.destroy()
     dv = DefectView(self.appliTw, self.appliViewFrame, self.mainApp,
                     DefectController(Defect(modelData)))
     dv.openInsertWindow(toExport)
Пример #8
0
 def setMainRedactor(self):
     """Sets a main redactor for a pentest. Each not assigned defect will be assigned to him/her"""
     self.settings.reloadSettings()
     dialog = ChildDialogCombo(self.parent,
                               self.settings.getPentesters() + ["N/A"],
                               "Set main redactor", "N/A")
     newVal = self.parent.wait_window(dialog.app)
     if newVal is None:
         return
     if not newVal or newVal.strip() == "":
         return
     columnRedactor = self.treevw['columns'].index("redactor")
     for it in self.treevw.get_children():
         oldValues = self.treevw.item(it)["values"]
         if oldValues[columnRedactor] == "N/A":
             oldValues[columnRedactor] = newVal
             self.treevw.item(it, values=oldValues)
             d_o = Defect({"_id": it})
             d_o.update({"redactor": newVal})
     self.mainRedac = newVal
Пример #9
0
    def addDefectCallback(self, _event):
        """
        Create an empty defect model and its attached view. Open this view insert window.

        Args:
            event: Automatically generated with a button Callback, not used but mandatory.
        """
        for widget in self.appliViewFrame.winfo_children():
            widget.destroy()
        modelData = self.controller.getData()
        dv = DefectView(self.appliTw, self.appliViewFrame, self.mainApp,
                        DefectController(Defect(modelData)))
        dv.openInsertWindow()
Пример #10
0
 def OnDoubleClick(self, event):
     """
     Callback for double click on treeview.
     Opens a window to update the double clicked defect view.
     Args:
         event: automatically created with the event catch. stores data about line in treeview that was double clicked.
     """
     item = self.treevw.identify("item", event.x, event.y)
     if item is None or item == '':
         return
     defect_m = Defect.fetchObject({"_id": ObjectId(item)})
     dialog = ChildDialogDefectView(self.tkApp, self.settings, defect_m)
     self.parent.wait_window(dialog.app)
     self.updateDefectInTreevw(defect_m)
Пример #11
0
    def addInTreeview(self, parentNode=None, addChildren=True):
        """Add this view in treeview. Also stores infos in application treeview.
        Args:
            parentNode: if None, will calculate the parent. If setted, forces the node to be inserted inside given parentNode.
            addChildren: If False, skip the tool and defects insert. Useful when displaying search results
        """
        if parentNode is None:
            parentNode = self.getParentNode()
            nodeText = str(self.controller.getModelRepr())
        elif parentNode == '':
            nodeText = self.controller.getDetailedString()
        else:
            nodeText = str(self.controller.getModelRepr())
        self.appliTw.views[str(self.controller.getDbId())] = {"view": self}
        try:
            self.appliTw.insert(parentNode,
                                "end",
                                str(self.controller.getDbId()),
                                text=nodeText,
                                tags=self.controller.getTags(),
                                image=self.getClassIcon())
        except TclError:
            pass
        if addChildren:
            defects = self.controller.getDefects()
            for defect in defects:
                defect_o = DefectController(Defect(defect))
                defect_vw = DefectView(self.appliTw, self.appliViewFrame,
                                       self.mainApp, defect_o)
                defect_vw.addInTreeview(str(self.controller.getDbId()))

            tools = self.controller.getTools()
            for tool in tools:
                tool_o = ToolController(Tool(tool))
                tool_vw = ToolView(self.appliTw, self.appliViewFrame,
                                   self.mainApp, tool_o)
                tool_vw.addInTreeview(str(self.controller.getDbId()))

        self.appliTw.sort(parentNode)
        if "hidden" in self.controller.getTags():
            self.hide()
Пример #12
0
 def multi_insert(self):
     values = self.browse_down_treevw.getValue()
     for title in values:
         results, msg = APIClient.searchDefect(title)
         if results is not None:
             result = results[0]
             d_o = Defect()
             types = result["type"].split(",")
             d_o.initialize("", "", "", result["title"],
                            result["synthesis"], result["description"],
                            result["ease"], result["impact"],
                            result["risk"], "N/A", types,
                            result["language"], "", result["fixes"])
             d_o.addInDb()
         else:
             tk.messagebox.showerror("Could not saerch defect", msg)
     return True
    def __init__(self, parent, settings, defectModel=None, multi=False):
        """
        Open a child dialog of a tkinter application to choose autoscan settings.

        Args:
            parent: the tkinter parent view to use for this window construction.
            defectModel : A Defect Model object to load default values. None to have empty fields, default is None.
        """
        self.app = tk.Toplevel(parent)
        if defectModel is not None:
            if defectModel.isTemplate:
                self.app.title("Edit a security defect template")
            else:
                self.app.title("Edit a security defect")
        else:
            self.app.title("Add a security defect")
        self.app.resizable(True, True)
        self.app.geometry("800x600")
        container = ttk.Frame(self.app)
        container.columnconfigure(0, weight=1)
        container.rowconfigure(0, weight=1)
        self.rvalue = None
        self.canvas = tk.Canvas(container, bg="white")
        self.appFrame = ttk.Frame(self.canvas)
        self.myscrollbar = tk.Scrollbar(container,
                                        orient="vertical",
                                        command=self.canvas.yview)
        self.canvas.bind('<Enter>', self.boundToMousewheel)
        self.canvas.bind('<Leave>', self.unboundToMousewheel)
        self.canvas.bind(
            '<Configure>', lambda e: self.canvas.configure(scrollregion=self.
                                                           canvas.bbox("all")))
        self.canvas_main_frame = self.canvas.create_window(
            (0, 0), window=self.appFrame, anchor='nw')
        self.canvas.configure(yscrollcommand=self.myscrollbar.set)

        self.isInsert = defectModel is None
        self.multi = multi
        if self.isInsert:
            defectModel = Defect()

        self.defect_vw = DefectView(None, self.appFrame, parent,
                                    DefectController(defectModel))
        if self.isInsert:
            if multi:
                self.defect_vw.openMultiInsertWindow(addButtons=False)
            else:
                self.defect_vw.openInsertWindow(addButtons=False)
        else:
            self.defect_vw.openModifyWindow(addButtons=False)

        ok_button = ttk.Button(self.appFrame, text="OK")
        ok_button.pack(side="right", padx=5, pady=10)
        ok_button.bind('<Button-1>', self.okCallback)
        cancel_button = ttk.Button(self.appFrame, text="Cancel")
        cancel_button.pack(side="right", padx=5, pady=10, ipadx=10)
        cancel_button.bind('<Button-1>', self.cancel)
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))
        self.canvas.bind("<Configure>", self.resizeAppFrame)
        self.canvas.grid(column=0, row=0, sticky="nsew")
        self.myscrollbar.grid(column=1, row=0, sticky="ns")
        container.pack(fill=tk.BOTH, ipady=10, ipadx=10, expand=True)

        # self.appFrame.pack(fill=tk.X, ipady=10, ipadx=10, expand=True) this break the canvas drawing with scrollbar
        try:
            self.app.wait_visibility()
            self.app.transient(parent)
            self.app.grab_set()
            self.app.focus_force()
            self.app.lift()
        except tk.TclError:
            pass
Пример #14
0
    def _load(self):
        """
        Load the treeview with database information
        """
        apiclient = APIClient.getInstance()
        dialog = ChildDialogProgress(
            self.appli, "Loading " + str(apiclient.getCurrentPentest()),
            "Opening " + str(apiclient.getCurrentPentest()) +
            ". Please wait for a few seconds.", 200, "determinate")
        step = 0
        dialog.show(100)
        nbObjects = apiclient.count("waves", )
        nbObjects += apiclient.count("scopes")
        nbObjects += apiclient.count("intervals")
        nbObjects += apiclient.count("scopes")
        nbObjects += apiclient.count("ips")
        nbObjects += apiclient.count("ports")
        nbObjects += apiclient.count("tools")
        nbObjects += apiclient.count("commands")
        onePercentNbObject = nbObjects // 100 if nbObjects > 100 else 1
        nbObjectTreated = 0
        self.delete(*self.get_children())
        self._hidden = []
        self._detached = []
        self.waves_node = self.insert("",
                                      "end",
                                      str("waves"),
                                      text="Waves",
                                      image=WaveView.getClassIcon())
        # Loading every category separatly is faster than recursivly.
        # This is due to cursor.next function calls in pymongo
        # Adding wave objects

        self.commands_node = self.insert("",
                                         "end",
                                         "commands",
                                         text="Commands",
                                         image=CommandView.getClassIcon())
        self.group_command_node = self.insert(
            "",
            "end",
            "groupcommands",
            text="Command Groups",
            image=CommandGroupView.getClassIcon())
        self.my_group_command_node = self.insert(
            self.group_command_node,
            "end",
            "mygroupcommands",
            text="My Command Groups",
            image=CommandGroupView.getClassIcon())
        self.worker_group_command_node = self.insert(
            self.group_command_node,
            "end",
            "workergroupcommands",
            text="Worker Command Groups",
            image=CommandGroupView.getClassIcon())
        self.my_commands_node = self.insert(self.commands_node,
                                            "end",
                                            "mycommands",
                                            text="My commands",
                                            image=CommandView.getClassIcon())
        self.worker_commands_node = self.insert(
            self.commands_node,
            "end",
            "workercommands",
            text="Worker commands",
            image=CommandView.getClassIcon())
        self.others_commands_node = self.insert(
            self.commands_node,
            "end",
            "otherscommands",
            text="Others commands",
            image=CommandView.getClassIcon())
        commands = Command.fetchObjects({}, apiclient.getCurrentPentest())
        for command in commands:
            command_vw = CommandView(self, self.appli.viewframe, self.appli,
                                     CommandController(command))
            command_vw.addInTreeview()
        group_commands = CommandGroup.fetchObjects(
            {}, apiclient.getCurrentPentest())
        for command_groupe_vw in group_commands:
            command_groupe_vw = CommandGroupView(
                self, self.appli.viewframe, self.appli,
                CommandGroupController(command_groupe_vw))
            command_groupe_vw.addInTreeview()
        waves = Wave.fetchObjects({})
        for wave in waves:
            wave_o = WaveController(wave)
            wave_vw = WaveView(self, self.appli.viewframe, self.appli, wave_o)
            wave_vw.addInTreeview(self.waves_node, False)
            nbObjectTreated += 1
            if nbObjectTreated % onePercentNbObject == 0:
                step += 1
                dialog.update(step)
        scopes = Scope.fetchObjects({})
        for scope in scopes:
            scope_o = ScopeController(scope)
            scope_vw = ScopeView(self, self.appli.viewframe, self.appli,
                                 scope_o)
            scope_vw.addInTreeview(None, False)
            nbObjectTreated += 1
            if nbObjectTreated % onePercentNbObject == 0:
                step += 1
                dialog.update(step)
        intervals = Interval.fetchObjects({})
        for interval in intervals:
            interval_o = IntervalController(interval)
            interval_vw = IntervalView(self, self.appli.viewframe, self.appli,
                                       interval_o)
            interval_vw.addInTreeview(None, False)
            nbObjectTreated += 1
            if nbObjectTreated % onePercentNbObject == 0:
                step += 1
                dialog.update(step)
        #Adding ip objects
        self.ips_node = self.insert("",
                                    "end",
                                    str("ips"),
                                    text="IPs",
                                    image=IpView.getClassIcon())
        ips = Ip.fetchObjects({})
        for ip in ips:
            ip_o = IpController(ip)
            ip_vw = IpView(self, self.appli.viewframe, self.appli, ip_o)
            ip_vw.addInTreeview(None, False)
            self.appli.statusbar.notify(ip_vw.controller.getTags())
            nbObjectTreated += 1
            if nbObjectTreated % onePercentNbObject == 0:
                step += 1
                dialog.update(step)
        # Adding port objects
        ports = Port.fetchObjects({})
        for port in ports:
            port_o = PortController(port)
            port_vw = PortView(self, self.appli.viewframe, self.appli, port_o)
            port_vw.addInTreeview(None, False)
            self.appli.statusbar.notify(port_vw.controller.getTags())
            nbObjectTreated += 1
            if nbObjectTreated % onePercentNbObject == 0:
                step += 1
                dialog.update(step)
        # Adding defect objects
        defects = Defect.fetchObjects({"ip": {"$ne": ""}})
        for defect in defects:
            defect_o = DefectController(defect)
            defect_vw = DefectView(self, self.appli.viewframe, self.appli,
                                   defect_o)
            defect_vw.addInTreeview(None)
            nbObjectTreated += 1
            if nbObjectTreated % onePercentNbObject == 0:
                step += 1
                dialog.update(step)
        # Adding tool objects
        tools = Tool.fetchObjects({})
        for tool in tools:
            tool_o = ToolController(tool)
            tool_vw = ToolView(self, self.appli.viewframe, self.appli, tool_o)
            tool_vw.addInTreeview(None, False)
            self.appli.statusbar.notify(tool_vw.controller.getTags())
            nbObjectTreated += 1
            if nbObjectTreated % onePercentNbObject == 0:
                step += 1
                dialog.update(step)
        self.sort(self.ips_node)
        self.appli.statusbar.update()
        dialog.destroy()
Пример #15
0
    def notify(self, db, collection, iid, action, _parent):
        """
        Callback for the observer implemented in mongo.py.
        Each time an object is inserted, updated or deleted the standard way, this function will be called.

        Args:
            collection: the collection that has been modified
            iid: the mongo ObjectId _id that was modified/inserted/deleted
            action: string "update" or "insert" or "delete". It was the action performed on the iid
            _parent: Not used. the mongo ObjectId of the parent. Only if action in an insert. Not used anymore
        """
        apiclient = APIClient.getInstance()
        if not apiclient.getCurrentPentest() != "":
            return
        if db == "pollenisator":
            if collection == "settings":
                self.configureTags()
                return
        if apiclient.getCurrentPentest() != db:
            return
        # Delete
        if action == "delete":
            if collection == "defects":
                view = self.getViewFromId(str(iid))
                if view is not None:
                    self.appli.statusbar.notify([], view.controller.getTags())
            try:
                self.delete(ObjectId(iid))
            except tk.TclError:
                pass  # item was not inserted in the treeview

        # Insert
        if action == "insert":
            view = None
            res = apiclient.find(collection, {"_id": ObjectId(iid)}, False)
            if collection == "tools":
                view = ToolView(self, self.appli.viewframe, self.appli,
                                ToolController(Tool(res)))
            elif collection == "waves":
                view = WaveView(self, self.appli.viewframe, self.appli,
                                WaveController(Wave(res)))
            elif collection == "scopes":
                view = ScopeView(self, self.appli.viewframe, self.appli,
                                 ScopeController(Scope(res)))
            elif collection == "ports":
                view = PortView(self, self.appli.viewframe, self.appli,
                                PortController(Port(res)))
            elif collection == "ips":
                view = IpView(self, self.appli.viewframe, self.appli,
                              IpController(Ip(res)))
            elif collection == "intervals":
                view = IntervalView(self, self.appli.viewframe, self.appli,
                                    IntervalController(Interval(res)))
            elif collection == "defects":
                view = DefectView(self, self.appli.viewframe, self.appli,
                                  DefectController(Defect(res)))
            elif collection == "commands":
                view = CommandView(self, self.appli.viewframe, self.appli,
                                   CommandController(Command(res)))
            elif collection == "group_commands":
                view = CommandGroupView(
                    self, self.appli.viewframe, self.appli,
                    CommandGroupController(CommandGroup(res)))
            try:
                if view is not None:
                    view.addInTreeview()
                    view.insertReceived()
                    self.appli.statusbar.notify(view.controller.getTags())
            except tk.TclError:
                pass

        if action == "update":
            try:
                view = self.getViewFromId(str(iid))
                if view is not None:
                    item = self.item(str(iid))
                    oldTags = item["tags"]
                    view.controller.actualize()
                    self.appli.statusbar.notify(view.controller.getTags(),
                                                oldTags)
                    self.item(str(iid),
                              text=str(view.controller.getModelRepr()),
                              image=view.getIcon())
            except tk.TclError:
                if view is not None:
                    view.addInTreeview()
            if str(self.appli.openedViewFrameId) == str(iid):
                for widget in self.appli.viewframe.winfo_children():
                    widget.destroy()
                view.openModifyWindow()
            if view is not None:
                view.updateReceived()
        self.appli.statusbar.update()
Пример #16
0
    def openInsertWindow(self, notes="", addButtons=True):
        """
        Creates a tkinter form using Forms classes. This form aims to insert a new Defect
        Args:
            notes: default notes to be written in notes text input. Default is ""
            addButtons: boolean value indicating that insertion buttons should be visible. Default to True
        """
        settings = self.mainApp.settings
        settings.reloadSettings()
        modelData = self.controller.getData()
        topPanel = self.form.addFormPanel(grid=True)
        s = topPanel.addFormSearchBar("Search Defect",
                                      APIClient.searchDefect,
                                      self.form,
                                      row=0,
                                      column=0)
        topPanel.addFormLabel("Search Language", row=0, column=1)
        lang = topPanel.addFormStr("lang", row=0, column=2)
        s.addOptionForm(lang)
        topPanel = self.form.addFormPanel(grid=True)
        topPanel.addFormLabel("Title")
        topPanel.addFormStr("Title", r".+", "", column=1, width=50)
        topPanel = self.form.addFormPanel(grid=True)
        topPanel.addFormLabel("Ease")
        self.easeForm = topPanel.addFormCombo(
            "Ease",
            Defect.getEases(),
            width=10,
            column=1,
            binds={"<<ComboboxSelected>>": self.updateRiskBox})
        topPanel.addFormHelper(
            "0: Trivial to exploit, no tool required\n1: Simple technics and public tools needed to exploit\n2: public vulnerability exploit requiring security skills and/or the development of simple tools.\n3: Use of non-public exploits requiring strong skills in security and/or the development of targeted tools",
            column=2)
        topPanel.addFormLabel("Impact", column=3)
        self.impactForm = topPanel.addFormCombo(
            "Impact",
            Defect.getImpacts(),
            width=10,
            column=4,
            binds={"<<ComboboxSelected>>": self.updateRiskBox})
        topPanel.addFormHelper(
            "0: No direct impact on system security\n1: Impact isolated on precise locations of pentested system security\n2: Impact restricted to a part of the system security.\n3: Global impact on the pentested system security.",
            column=5)
        topPanel.addFormLabel("Risk", column=6)
        self.riskForm = topPanel.addFormCombo("Risk",
                                              Defect.getRisks(),
                                              modelData["risk"],
                                              width=10,
                                              column=7)
        topPanel.addFormHelper(
            "0: small risk that might be fixed\n1: moderate risk that need a planed fix\n2: major risk that need to be fixed quickly.\n3: critical risk that need an immediate fix or an immediate interruption.",
            column=8)
        topPanel = self.form.addFormPanel(grid=True)
        topPanel.addFormLabel("Redactor", row=1)
        topPanel.addFormCombo("Redactor",
                              self.mainApp.settings.getPentesters() + ["N/A"],
                              "N/A",
                              row=1,
                              column=1)
        topPanel.addFormLabel("Language", row=1, column=2)
        topPanel.addFormStr("Language", "", "en", row=1, column=3)

        chklistPanel = self.form.addFormPanel(grid=True)
        defectTypes = settings.getPentestTypes()
        if defectTypes is not None:
            defectTypes = defectTypes.get(settings.getPentestType(), [])
            if len(defectTypes) == 0:
                defectTypes = ["N/A"]
        else:
            defectTypes = ["N/A"]
        chklistPanel.addFormChecklist("Type", defectTypes, ["N/A"])
        proofsPanel = self.form.addFormPanel(grid=True)
        proofsPanel.addFormFile("Proof",
                                r"",
                                text="Add proof",
                                width=90,
                                height=4)
        topPanel = self.form.addFormPanel()
        topPanel.addFormText(
            "Synthesis",
            r"",
            "Synthesis",
            state="readonly" if self.controller.isAssigned() else "",
            height=2,
            side="top")
        if not self.controller.isAssigned():
            topPanel.addFormText("Description", r"", "Description", side="top")
        else:
            topPanel.addFormHidden("Description",
                                   modelData.get("description", ""))
            notesPanel = self.form.addFormPanel()
            notesPanel.addFormLabel("Notes", side="top")
            notesPanel.addFormText("Notes", r"", notes, None, side="top")
        self.form.addFormHidden("ip", modelData["ip"])
        self.form.addFormHidden("proto", modelData["proto"])
        self.form.addFormHidden("port", modelData["port"])
        self.form.addFormHidden("Fixes", [])
        if addButtons:
            self.completeInsertWindow()
        else:
            self.showForm()
Пример #17
0
 def openModifyWindow(self, addButtons=True):
     """
     Creates a tkinter form using Forms classes.
     This form aims to update or delete an existing Defect
     Args:
         addButtons: boolean value indicating that insertion buttons should be visible. Default to True
     """
     modelData = self.controller.getData()
     settings = self.mainApp.settings
     settings.reloadSettings()
     globalPanel = self.form.addFormPanel(side=tk.TOP, fill=tk.X, pady=5)
     topPanel = globalPanel.addFormPanel(grid=True)
     row = 0
     if modelData.get("ip", "") != "":
         topPanel.addFormLabel("IP", row=row, column=0)
         topPanel.addFormStr("IP",
                             '',
                             modelData["ip"],
                             None,
                             column=1,
                             row=row,
                             state="readonly")
         row += 1
         if modelData.get("port",
                          "") != "" and modelData["proto"] is not None:
             topPanel.addFormLabel("Port", row=row, column=0)
             port_str = modelData["proto"] + \
                 "/" if modelData["proto"] != "tcp" else ""
             port_str += modelData["port"]
             topPanel.addFormStr("Port",
                                 '',
                                 port_str,
                                 None,
                                 column=1,
                                 row=row,
                                 state="readonly")
             row += 1
     if not self.controller.isAssigned():
         if not self.controller.model.isTemplate:
             topPanel.addFormSearchBar("Search Defect",
                                       APIClient.searchDefect,
                                       globalPanel,
                                       row=row,
                                       column=1,
                                       autofocus=False)
             row += 1
         topPanel.addFormLabel("Title", row=row, column=0)
         topPanel.addFormStr("Title",
                             ".+",
                             modelData["title"],
                             width=50,
                             row=row,
                             column=1)
         row += 1
         topPanel = globalPanel.addFormPanel(grid=True)
         row = 0
         topPanel.addFormLabel("Ease", row=row)
         self.easeForm = topPanel.addFormCombo(
             "Ease",
             Defect.getEases(),
             modelData["ease"],
             width=10,
             row=row,
             column=1,
             binds={"<<ComboboxSelected>>": self.updateRiskBox})
         topPanel.addFormHelper(
             "0: Trivial to exploit, no tool required\n1: Simple technics and public tools needed to exploit\n2: public vulnerability exploit requiring security skills and/or the development of simple tools.\n3: Use of non-public exploits requiring strong skills in security and/or the development of targeted tools",
             row=row,
             column=2)
         topPanel.addFormLabel("Impact", row=row, column=3)
         self.impactForm = topPanel.addFormCombo(
             "Impact",
             Defect.getImpacts(),
             modelData["impact"],
             width=10,
             row=row,
             column=4,
             binds={"<<ComboboxSelected>>": self.updateRiskBox})
         topPanel.addFormHelper(
             "0: No direct impact on system security\n1: Impact isolated on precise locations of pentested system security\n2: Impact restricted to a part of the system security.\n3: Global impact on the pentested system security.",
             row=row,
             column=5)
         topPanel.addFormLabel("Risk", row=row, column=6)
         self.riskForm = topPanel.addFormCombo("Risk",
                                               Defect.getRisks(),
                                               modelData["risk"],
                                               width=10,
                                               row=row,
                                               column=7)
         topPanel.addFormHelper(
             "0: small risk that might be fixed\n1: moderate risk that need a planed fix\n2: major risk that need to be fixed quickly.\n3: critical risk that need an immediate fix or an immediate interruption.",
             row=row,
             column=8)
         row += 1
         chklistPanel = globalPanel.addFormPanel(grid=True)
         defect_types = settings.getPentestTypes()[
             settings.getPentestType()]
         for savedType in modelData["type"]:
             if savedType.strip() not in defect_types:
                 defect_types.insert(0, savedType)
         chklistPanel.addFormChecklist("Type", defect_types,
                                       modelData["type"])
         topPanel = globalPanel.addFormPanel(grid=True)
         row = 0
         if not self.controller.model.isTemplate:
             topPanel.addFormLabel("Redactor", row=row)
             topPanel.addFormCombo(
                 "Redactor",
                 list(
                     set(self.mainApp.settings.getPentesters() + ["N/A"] +
                         [modelData["redactor"]])),
                 modelData["redactor"],
                 row=row,
                 column=1)
         topPanel.addFormLabel("Language", row=row, column=2)
         topPanel.addFormStr("Language",
                             "",
                             modelData["language"],
                             row=row,
                             column=3)
         row += 1
         topPanel = globalPanel.addFormPanel()
         topPanel.addFormText(
             "Synthesis",
             r"",
             modelData.get("synthesis", "Synthesis"),
             state="readonly" if self.controller.isAssigned() else "",
             height=2,
             side="top")
         topPanel.addFormText("Description",
                              r"",
                              modelData.get("description", "Description"),
                              side="top")
         topPanel.addFormButton("Edit fixes", self.openFixesWindow)
     else:
         topPanel.addFormHidden("Title", modelData.get("title", ""))
         topPanel.addFormHidden("Ease", modelData.get("ease", ""))
         topPanel.addFormHidden("Impact", modelData.get("impact", ""))
         topPanel.addFormHidden("Risk", modelData.get("risk", ""))
         types = modelData.get("type", [])
         type_dict = dict()
         for type in types:
             type_dict[type] = 1
         topPanel.addFormHidden("Type", type_dict)
         topPanel.addFormHidden("Language", modelData.get("language", ""))
         topPanel.addFormHidden("Synthesis", modelData.get("synthesis", ""))
         topPanel.addFormHidden("Description",
                                modelData.get("description", ""))
         notesPanel = globalPanel.addFormPanel()
         notesPanel.addFormLabel("Notes", side="top")
         notesPanel.addFormText("Notes",
                                r"",
                                modelData["notes"],
                                None,
                                side="top",
                                height=10)
     if not self.controller.model.isTemplate:
         proofPanel = globalPanel.addFormPanel(grid=True)
         i = 0
         for proof in modelData["proofs"]:
             proofPanel.addFormLabel("Proof " + str(i),
                                     proof,
                                     row=i,
                                     column=0)
             proofPanel.addFormButton(
                 "View",
                 lambda event, obj=i: self.viewProof(event, obj),
                 row=i,
                 column=1)
             proofPanel.addFormButton(
                 "Delete",
                 lambda event, obj=i: self.deleteProof(event, obj),
                 row=i,
                 column=2)
             i += 1
         proofPanel = globalPanel.addFormPanel()
         self.formFile = proofPanel.addFormFile("Add proofs",
                                                r"",
                                                "",
                                                width=100,
                                                height=3)
     self.formFixes = globalPanel.addFormHidden("Fixes", modelData["fixes"])
     if not self.controller.model.isTemplate:
         actionsPan = globalPanel.addFormPanel()
         actionsPan.addFormButton("Create defect template from this",
                                  self.saveAsDefectTemplate)
     if addButtons:
         self.completeModifyWindow(addTags=False)
     else:
         self.showForm()