sqlmap/lib/core/gui.py

285 lines
9.8 KiB
Python
Raw Normal View History

2019-11-20 18:46:24 +03:00
#!/usr/bin/env python
"""
2022-01-03 13:30:34 +03:00
Copyright (c) 2006-2022 sqlmap developers (https://sqlmap.org/)
2019-11-20 18:46:24 +03:00
See the file 'LICENSE' for copying permission
"""
import os
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 tempfile
2019-11-22 16:39:44 +03:00
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
from lib.core.common import saveConfig
from lib.core.data import paths
2019-11-21 13:41:46 +03:00
from lib.core.defaults import defaults
from lib.core.enums import MKSTEMP_PREFIX
2019-11-21 15:58:46 +03:00
from lib.core.exception import SqlmapMissingDependence
2021-03-07 23:15:59 +03:00
from lib.core.exception import SqlmapSystemException
2019-11-21 13:36:13 +03:00
from lib.core.settings import DEV_EMAIL_ADDRESS
from lib.core.settings import IS_WIN
2019-11-21 13:36:13 +03:00
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
2019-11-22 16:39:44 +03:00
from thirdparty.six.moves import queue as _queue
2020-01-09 15:19:54 +03:00
alive = None
2019-11-22 16:39:44 +03:00
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:
2019-12-06 00:45:57 +03:00
from thirdparty.six.moves import tkinter as _tkinter
from thirdparty.six.moves import tkinter_scrolledtext as _tkinter_scrolledtext
from thirdparty.six.moves import tkinter_ttk as _tkinter_ttk
from thirdparty.six.moves import tkinter_messagebox as _tkinter_messagebox
2019-11-21 15:58:46 +03:00
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-12-06 00:45:57 +03:00
class ConstrainedEntry(_tkinter.Entry):
2019-11-20 18:46:24 +03:00
def __init__(self, master=None, **kwargs):
2019-12-06 00:45:57 +03:00
self.var = _tkinter.StringVar()
2019-11-20 18:46:24 +03:00
self.regex = kwargs["regex"]
del kwargs["regex"]
2019-12-06 00:45:57 +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-12-06 00:45:57 +03:00
class AutoresizableNotebook(_tkinter_ttk.Notebook):
2019-11-20 18:46:24 +03:00
def __init__(self, master=None, **kw):
2019-12-06 00:45:57 +03:00
_tkinter_ttk.Notebook.__init__(self, master, **kw)
2019-11-20 18:46:24 +03:00
self.bind("<<NotebookTabChanged>>", self._on_tab_changed)
2019-12-10 00:13:52 +03:00
def _on_tab_changed(self, event):
2019-11-20 18:46:24 +03:00
event.widget.update_idletasks()
tab = event.widget.nametowidget(event.widget.select())
event.widget.configure(height=tab.winfo_reqheight())
2021-03-07 23:15:59 +03:00
try:
window = _tkinter.Tk()
except Exception as ex:
errMsg = "unable to create GUI window ('%s')" % getSafeExString(ex)
raise SqlmapSystemException(errMsg)
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-12-06 00:45:57 +03:00
style = _tkinter_ttk.Style()
2019-12-10 00:13:52 +03:00
settings = {"TNotebook.Tab": {"configure": {"padding": [5, 1], "background": "#fdd57e"}, "map": {"background": [("selected", "#C70039"), ("active", "#fc9292")], "foreground": [("selected", "#ffffff"), ("active", "#000000")]}}}
2019-11-20 18:46:24 +03:00
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"
except:
return
2019-11-22 16:39:44 +03:00
2019-12-06 00:45:57 +03:00
event.widget.insert(_tkinter.END, "\n")
2019-11-22 16:39:44 +03:00
return "break"
2019-11-21 17:58:04 +03:00
def run():
global alive
2019-11-22 16:39:44 +03:00
global process
global queue
config = {}
2019-11-21 17:58:04 +03:00
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
config[dest] = value
2019-11-21 17:58:04 +03:00
for option in parser.option_list:
config[option.dest] = defaults.get(option.dest, None)
handle, configFile = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.CONFIG, text=True)
os.close(handle)
2019-11-21 17:58:04 +03:00
saveConfig(config, configFile)
def enqueue(stream, queue):
global alive
for line in iter(stream.readline, b''):
queue.put(line)
alive = False
stream.close()
alive = True
process = subprocess.Popen([sys.executable or "python", os.path.join(paths.SQLMAP_ROOT_PATH, "sqlmap.py"), "-c", configFile], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, bufsize=1, close_fds=not IS_WIN)
# 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-22 16:39:44 +03:00
2019-12-06 00:45:57 +03:00
top = _tkinter.Toplevel()
2019-11-22 16:39:44 +03:00
top.title("Console")
# Reference: https://stackoverflow.com/a/13833338
2019-12-06 00:45:57 +03:00
text = _tkinter_scrolledtext.ScrolledText(top, undo=True)
2019-11-22 16:39:44 +03:00
text.bind("<Key>", onKeyPress)
text.bind("<Return>", onReturnPress)
text.pack()
text.focus()
center(top)
2019-11-20 18:46:24 +03:00
2020-01-09 15:19:54 +03:00
while True:
line = ""
try:
2019-12-10 00:13:52 +03:00
# line = queue.get_nowait()
line = queue.get(timeout=.1)
2019-12-06 00:45:57 +03:00
text.insert(_tkinter.END, line)
except _queue.Empty:
2019-12-06 00:45:57 +03:00
text.see(_tkinter.END)
text.update_idletasks()
2020-01-09 15:19:54 +03:00
if not alive:
break
2019-12-06 00:45:57 +03:00
menubar = _tkinter.Menu(window)
2019-11-20 18:46:24 +03:00
2019-12-06 00:45:57 +03:00
filemenu = _tkinter.Menu(menubar, tearoff=0)
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-12-06 00:45:57 +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()
2022-01-03 13:30:34 +03:00
helpmenu.add_command(label="About", command=lambda: _tkinter_messagebox.showinfo("About", "Copyright (c) 2006-2022\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-12-06 00:45:57 +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-12-06 00:45:57 +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-12-06 00:45:57 +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-12-06 00:45:57 +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-12-06 00:45:57 +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-12-06 00:45:57 +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-12-06 00:45:57 +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-12-06 00:45:57 +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-12-06 00:45:57 +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()
window.mainloop()