2019-11-20 18:46:24 +03:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
|
|
"""
|
|
|
|
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
|
|
|
|
See the file 'LICENSE' for copying permission
|
|
|
|
"""
|
|
|
|
|
2019-11-21 13:41:46 +03:00
|
|
|
import re
|
2019-11-22 16:39:44 +03:00
|
|
|
import socket
|
|
|
|
import subprocess
|
|
|
|
import sys
|
|
|
|
import threading
|
2019-11-21 13:36:13 +03:00
|
|
|
import webbrowser
|
|
|
|
|
2019-11-21 15:58:46 +03:00
|
|
|
from lib.core.common import getSafeExString
|
2019-11-21 13:41:46 +03:00
|
|
|
from lib.core.defaults import defaults
|
2019-11-21 15:58:46 +03:00
|
|
|
from lib.core.exception import SqlmapMissingDependence
|
2019-11-21 13:36:13 +03:00
|
|
|
from lib.core.settings import DEV_EMAIL_ADDRESS
|
|
|
|
from lib.core.settings import ISSUES_PAGE
|
|
|
|
from lib.core.settings import GIT_PAGE
|
|
|
|
from lib.core.settings import SITE
|
|
|
|
from lib.core.settings import VERSION_STRING
|
|
|
|
from lib.core.settings import WIKI_PAGE
|
|
|
|
from thirdparty.six.moves import tkinter_messagebox as _tkinter_messagebox
|
2019-11-22 16:39:44 +03:00
|
|
|
from thirdparty.six.moves import queue as _queue
|
|
|
|
|
|
|
|
line = ""
|
|
|
|
process = None
|
|
|
|
queue = None
|
2019-11-21 13:36:13 +03:00
|
|
|
|
2019-11-20 18:46:24 +03:00
|
|
|
def runGui(parser):
|
2019-11-21 15:58:46 +03:00
|
|
|
try:
|
|
|
|
import tkinter
|
2019-11-22 16:39:44 +03:00
|
|
|
import tkinter.scrolledtext
|
2019-11-21 15:58:46 +03:00
|
|
|
import tkinter.ttk
|
|
|
|
except ImportError as ex:
|
|
|
|
raise SqlmapMissingDependence("missing dependence ('%s')" % getSafeExString(ex))
|
|
|
|
|
2019-11-20 18:46:24 +03:00
|
|
|
# Reference: https://www.reddit.com/r/learnpython/comments/985umy/limit_user_input_to_only_int_with_tkinter/e4dj9k9?utm_source=share&utm_medium=web2x
|
2019-11-21 15:58:46 +03:00
|
|
|
class ConstrainedEntry(tkinter.Entry):
|
2019-11-20 18:46:24 +03:00
|
|
|
def __init__(self, master=None, **kwargs):
|
2019-11-21 15:58:46 +03:00
|
|
|
self.var = tkinter.StringVar()
|
2019-11-20 18:46:24 +03:00
|
|
|
self.regex = kwargs["regex"]
|
|
|
|
del kwargs["regex"]
|
2019-11-21 15:58:46 +03:00
|
|
|
tkinter.Entry.__init__(self, master, textvariable=self.var, **kwargs)
|
2019-11-20 18:46:24 +03:00
|
|
|
self.old_value = ''
|
|
|
|
self.var.trace('w', self.check)
|
|
|
|
self.get, self.set = self.var.get, self.var.set
|
|
|
|
|
|
|
|
def check(self, *args):
|
|
|
|
if re.search(self.regex, self.get()):
|
|
|
|
self.old_value = self.get()
|
|
|
|
else:
|
|
|
|
self.set(self.old_value)
|
|
|
|
|
|
|
|
# Reference: https://code.activestate.com/recipes/580726-tkinter-notebook-that-fits-to-the-height-of-every-/
|
2019-11-21 15:58:46 +03:00
|
|
|
class AutoresizableNotebook(tkinter.ttk.Notebook):
|
2019-11-20 18:46:24 +03:00
|
|
|
def __init__(self, master=None, **kw):
|
2019-11-21 15:58:46 +03:00
|
|
|
tkinter.ttk.Notebook.__init__(self, master, **kw)
|
2019-11-20 18:46:24 +03:00
|
|
|
self.bind("<<NotebookTabChanged>>", self._on_tab_changed)
|
|
|
|
|
|
|
|
def _on_tab_changed(self,event):
|
|
|
|
event.widget.update_idletasks()
|
|
|
|
|
|
|
|
tab = event.widget.nametowidget(event.widget.select())
|
|
|
|
event.widget.configure(height=tab.winfo_reqheight())
|
|
|
|
|
2019-11-21 15:58:46 +03:00
|
|
|
window = tkinter.Tk()
|
2019-11-21 13:36:13 +03:00
|
|
|
window.title(VERSION_STRING)
|
2019-11-20 18:46:24 +03:00
|
|
|
|
|
|
|
# Reference: https://www.holadevs.com/pregunta/64750/change-selected-tab-color-in-ttknotebook
|
2019-11-21 15:58:46 +03:00
|
|
|
style = tkinter.ttk.Style()
|
2019-11-20 18:46:24 +03:00
|
|
|
settings = {"TNotebook.Tab": {"configure": {"padding": [5, 1], "background": "#fdd57e" }, "map": {"background": [("selected", "#C70039"), ("active", "#fc9292")], "foreground": [("selected", "#ffffff"), ("active", "#000000")]}}}
|
|
|
|
style.theme_create("custom", parent="alt", settings=settings)
|
|
|
|
style.theme_use("custom")
|
|
|
|
|
2019-11-22 16:39:44 +03:00
|
|
|
# Reference: https://stackoverflow.com/a/10018670
|
|
|
|
def center(window):
|
|
|
|
window.update_idletasks()
|
|
|
|
width = window.winfo_width()
|
|
|
|
frm_width = window.winfo_rootx() - window.winfo_x()
|
|
|
|
win_width = width + 2 * frm_width
|
|
|
|
height = window.winfo_height()
|
|
|
|
titlebar_height = window.winfo_rooty() - window.winfo_y()
|
|
|
|
win_height = height + titlebar_height + frm_width
|
|
|
|
x = window.winfo_screenwidth() // 2 - win_width // 2
|
|
|
|
y = window.winfo_screenheight() // 2 - win_height // 2
|
|
|
|
window.geometry('{}x{}+{}+{}'.format(width, height, x, y))
|
|
|
|
window.deiconify()
|
|
|
|
|
|
|
|
def onKeyPress(event):
|
|
|
|
global line
|
|
|
|
global queue
|
|
|
|
|
|
|
|
if process:
|
|
|
|
if event.char == '\b':
|
|
|
|
line = line[:-1]
|
|
|
|
else:
|
|
|
|
line += event.char
|
|
|
|
|
|
|
|
def onReturnPress(event):
|
|
|
|
global line
|
|
|
|
global queue
|
|
|
|
|
|
|
|
if process:
|
|
|
|
try:
|
|
|
|
process.stdin.write(("%s\n" % line.strip()).encode())
|
|
|
|
process.stdin.flush()
|
|
|
|
except socket.error:
|
|
|
|
line = ""
|
|
|
|
event.widget.master.master.destroy()
|
|
|
|
return "break"
|
|
|
|
|
|
|
|
event.widget.insert(tkinter.END, "\n")
|
|
|
|
|
|
|
|
counter = 0
|
|
|
|
while True:
|
|
|
|
line = ""
|
|
|
|
try:
|
|
|
|
#line = queue.get_nowait()
|
|
|
|
line = queue.get(timeout=.1)
|
|
|
|
event.widget.insert(tkinter.END, line)
|
|
|
|
counter = 0
|
|
|
|
except _queue.Empty:
|
|
|
|
event.widget.see(tkinter.END)
|
|
|
|
event.widget.update_idletasks()
|
|
|
|
if counter > 3:
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
counter += 1
|
|
|
|
|
|
|
|
return "break"
|
|
|
|
|
2019-11-21 17:58:04 +03:00
|
|
|
def run():
|
2019-11-22 16:39:44 +03:00
|
|
|
global process
|
|
|
|
global queue
|
|
|
|
|
|
|
|
ON_POSIX = "posix" in sys.builtin_module_names
|
|
|
|
|
|
|
|
def enqueue(stream, queue):
|
|
|
|
for line in iter(stream.readline, b''):
|
|
|
|
queue.put(line)
|
|
|
|
stream.close()
|
|
|
|
|
|
|
|
process = subprocess.Popen("/bin/bash", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, bufsize=1, close_fds=ON_POSIX)
|
|
|
|
|
|
|
|
# Reference: https://stackoverflow.com/a/4896288
|
|
|
|
queue = _queue.Queue()
|
|
|
|
thread = threading.Thread(target=enqueue, args=(process.stdout, queue))
|
|
|
|
thread.daemon = True
|
|
|
|
thread.start()
|
|
|
|
|
|
|
|
|
2019-11-21 17:58:04 +03:00
|
|
|
options = {}
|
|
|
|
|
|
|
|
for key in window._widgets:
|
|
|
|
dest, type = key
|
|
|
|
widget = window._widgets[key]
|
|
|
|
|
|
|
|
if hasattr(widget, "get") and not widget.get():
|
|
|
|
value = None
|
|
|
|
elif type == "string":
|
|
|
|
value = widget.get()
|
|
|
|
elif type == "float":
|
|
|
|
value = float(widget.get())
|
|
|
|
elif type == "int":
|
|
|
|
value = int(widget.get())
|
|
|
|
else:
|
2019-11-22 16:39:44 +03:00
|
|
|
value = bool(widget.var.get())
|
2019-11-21 17:58:04 +03:00
|
|
|
|
|
|
|
options[dest] = value
|
|
|
|
|
|
|
|
for option in parser.option_list:
|
|
|
|
options[option.dest] = defaults.get(option.dest, None)
|
|
|
|
|
|
|
|
parser._args = options
|
2019-11-22 16:39:44 +03:00
|
|
|
|
|
|
|
top = tkinter.Toplevel()
|
|
|
|
top.title("Console")
|
|
|
|
|
|
|
|
# Reference: https://stackoverflow.com/a/13833338
|
|
|
|
text = tkinter.scrolledtext.ScrolledText(top, undo=True)
|
|
|
|
text.bind("<Key>", onKeyPress)
|
|
|
|
text.bind("<Return>", onReturnPress)
|
|
|
|
text.pack()
|
|
|
|
text.focus()
|
|
|
|
|
|
|
|
center(top)
|
2019-11-20 18:46:24 +03:00
|
|
|
|
2019-11-21 15:58:46 +03:00
|
|
|
menubar = tkinter.Menu(window)
|
2019-11-20 18:46:24 +03:00
|
|
|
|
2019-11-21 15:58:46 +03:00
|
|
|
filemenu = tkinter.Menu(menubar, tearoff=0)
|
2019-11-21 17:58:04 +03:00
|
|
|
filemenu.add_command(label="Open", state=tkinter.DISABLED)
|
|
|
|
filemenu.add_command(label="Save", state=tkinter.DISABLED)
|
2019-11-20 18:46:24 +03:00
|
|
|
filemenu.add_separator()
|
|
|
|
filemenu.add_command(label="Exit", command=window.quit)
|
|
|
|
menubar.add_cascade(label="File", menu=filemenu)
|
|
|
|
|
2019-11-21 17:58:04 +03:00
|
|
|
menubar.add_command(label="Run", command=run)
|
2019-11-20 18:46:24 +03:00
|
|
|
|
2019-11-21 15:58:46 +03:00
|
|
|
helpmenu = tkinter.Menu(menubar, tearoff=0)
|
2019-11-21 13:36:13 +03:00
|
|
|
helpmenu.add_command(label="Official site", command=lambda: webbrowser.open(SITE))
|
|
|
|
helpmenu.add_command(label="Github pages", command=lambda: webbrowser.open(GIT_PAGE))
|
|
|
|
helpmenu.add_command(label="Wiki pages", command=lambda: webbrowser.open(WIKI_PAGE))
|
|
|
|
helpmenu.add_command(label="Report issue", command=lambda: webbrowser.open(ISSUES_PAGE))
|
2019-11-20 18:46:24 +03:00
|
|
|
helpmenu.add_separator()
|
2019-11-21 13:36:13 +03:00
|
|
|
helpmenu.add_command(label="About", command=lambda: _tkinter_messagebox.showinfo("About", "Copyright (c) 2006-2019\n\n (%s)" % DEV_EMAIL_ADDRESS))
|
2019-11-20 18:46:24 +03:00
|
|
|
menubar.add_cascade(label="Help", menu=helpmenu)
|
|
|
|
|
|
|
|
window.config(menu=menubar)
|
2019-11-21 17:58:04 +03:00
|
|
|
window._widgets = {}
|
2019-11-20 18:46:24 +03:00
|
|
|
|
|
|
|
notebook = AutoresizableNotebook(window)
|
|
|
|
|
2019-11-21 13:36:13 +03:00
|
|
|
first = None
|
2019-11-20 18:46:24 +03:00
|
|
|
frames = {}
|
2019-11-21 17:58:04 +03:00
|
|
|
|
2019-11-20 18:46:24 +03:00
|
|
|
for group in parser.option_groups:
|
2019-11-21 15:58:46 +03:00
|
|
|
frame = frames[group.title] = tkinter.Frame(notebook, width=200, height=200)
|
2019-11-20 18:46:24 +03:00
|
|
|
notebook.add(frames[group.title], text=group.title)
|
|
|
|
|
2019-11-21 15:58:46 +03:00
|
|
|
tkinter.Label(frame).grid(column=0, row=0, sticky=tkinter.W)
|
2019-11-20 18:46:24 +03:00
|
|
|
|
|
|
|
row = 1
|
2019-11-20 19:28:25 +03:00
|
|
|
if group.get_description():
|
2019-11-21 15:58:46 +03:00
|
|
|
tkinter.Label(frame, text="%s:" % group.get_description()).grid(column=0, row=1, columnspan=3, sticky=tkinter.W)
|
|
|
|
tkinter.Label(frame).grid(column=0, row=2, sticky=tkinter.W)
|
2019-11-20 19:28:25 +03:00
|
|
|
row += 2
|
|
|
|
|
2019-11-20 18:46:24 +03:00
|
|
|
for option in group.option_list:
|
2019-11-21 15:58:46 +03:00
|
|
|
tkinter.Label(frame, text="%s " % parser.formatter._format_option_strings(option)).grid(column=0, row=row, sticky=tkinter.W)
|
2019-11-20 18:46:24 +03:00
|
|
|
|
|
|
|
if option.type == "string":
|
2019-11-21 15:58:46 +03:00
|
|
|
widget = tkinter.Entry(frame)
|
2019-11-20 18:46:24 +03:00
|
|
|
elif option.type == "float":
|
|
|
|
widget = ConstrainedEntry(frame, regex=r"\A\d*\.?\d*\Z")
|
|
|
|
elif option.type == "int":
|
|
|
|
widget = ConstrainedEntry(frame, regex=r"\A\d*\Z")
|
|
|
|
else:
|
2019-11-21 15:58:46 +03:00
|
|
|
var = tkinter.IntVar()
|
|
|
|
widget = tkinter.Checkbutton(frame, variable=var)
|
2019-11-20 18:46:24 +03:00
|
|
|
widget.var = var
|
|
|
|
|
2019-11-21 13:36:13 +03:00
|
|
|
first = first or widget
|
2019-11-21 15:58:46 +03:00
|
|
|
widget.grid(column=1, row=row, sticky=tkinter.W)
|
2019-11-20 18:46:24 +03:00
|
|
|
|
2019-11-21 17:58:04 +03:00
|
|
|
window._widgets[(option.dest, option.type)] = widget
|
|
|
|
|
2019-11-20 18:46:24 +03:00
|
|
|
default = defaults.get(option.dest)
|
|
|
|
if default:
|
|
|
|
if hasattr(widget, "insert"):
|
|
|
|
widget.insert(0, default)
|
|
|
|
|
2019-11-21 15:58:46 +03:00
|
|
|
tkinter.Label(frame, text=" %s" % option.help).grid(column=2, row=row, sticky=tkinter.W)
|
2019-11-20 18:46:24 +03:00
|
|
|
|
|
|
|
row += 1
|
|
|
|
|
2019-11-21 15:58:46 +03:00
|
|
|
tkinter.Label(frame).grid(column=0, row=row, sticky=tkinter.W)
|
2019-11-20 18:46:24 +03:00
|
|
|
|
|
|
|
notebook.pack(expand=1, fill="both")
|
|
|
|
notebook.enable_traversal()
|
|
|
|
|
2019-11-21 13:36:13 +03:00
|
|
|
first.focus()
|
|
|
|
|
2019-11-20 18:46:24 +03:00
|
|
|
window.mainloop()
|