Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/lib/core/gui.py
2989 views
1
#!/usr/bin/env python
2
3
"""
4
Copyright (c) 2006-2025 sqlmap developers (https://sqlmap.org)
5
See the file 'LICENSE' for copying permission
6
"""
7
8
import os
9
import re
10
import socket
11
import subprocess
12
import sys
13
import tempfile
14
import threading
15
import webbrowser
16
17
from lib.core.common import getSafeExString
18
from lib.core.common import saveConfig
19
from lib.core.data import paths
20
from lib.core.defaults import defaults
21
from lib.core.enums import MKSTEMP_PREFIX
22
from lib.core.exception import SqlmapMissingDependence
23
from lib.core.exception import SqlmapSystemException
24
from lib.core.settings import DEV_EMAIL_ADDRESS
25
from lib.core.settings import IS_WIN
26
from lib.core.settings import ISSUES_PAGE
27
from lib.core.settings import GIT_PAGE
28
from lib.core.settings import SITE
29
from lib.core.settings import VERSION_STRING
30
from lib.core.settings import WIKI_PAGE
31
from thirdparty.six.moves import queue as _queue
32
33
alive = None
34
line = ""
35
process = None
36
queue = None
37
38
def runGui(parser):
39
try:
40
from thirdparty.six.moves import tkinter as _tkinter
41
from thirdparty.six.moves import tkinter_scrolledtext as _tkinter_scrolledtext
42
from thirdparty.six.moves import tkinter_ttk as _tkinter_ttk
43
from thirdparty.six.moves import tkinter_messagebox as _tkinter_messagebox
44
except ImportError as ex:
45
raise SqlmapMissingDependence("missing dependence ('%s')" % getSafeExString(ex))
46
47
# Reference: https://www.reddit.com/r/learnpython/comments/985umy/limit_user_input_to_only_int_with_tkinter/e4dj9k9?utm_source=share&utm_medium=web2x
48
class ConstrainedEntry(_tkinter.Entry):
49
def __init__(self, master=None, **kwargs):
50
self.var = _tkinter.StringVar()
51
self.regex = kwargs["regex"]
52
del kwargs["regex"]
53
_tkinter.Entry.__init__(self, master, textvariable=self.var, **kwargs)
54
self.old_value = ''
55
self.var.trace('w', self.check)
56
self.get, self.set = self.var.get, self.var.set
57
58
def check(self, *args):
59
if re.search(self.regex, self.get()):
60
self.old_value = self.get()
61
else:
62
self.set(self.old_value)
63
64
# Reference: https://code.activestate.com/recipes/580726-tkinter-notebook-that-fits-to-the-height-of-every-/
65
class AutoresizableNotebook(_tkinter_ttk.Notebook):
66
def __init__(self, master=None, **kw):
67
_tkinter_ttk.Notebook.__init__(self, master, **kw)
68
self.bind("<<NotebookTabChanged>>", self._on_tab_changed)
69
70
def _on_tab_changed(self, event):
71
event.widget.update_idletasks()
72
73
tab = event.widget.nametowidget(event.widget.select())
74
event.widget.configure(height=tab.winfo_reqheight())
75
76
try:
77
window = _tkinter.Tk()
78
except Exception as ex:
79
errMsg = "unable to create GUI window ('%s')" % getSafeExString(ex)
80
raise SqlmapSystemException(errMsg)
81
82
window.title(VERSION_STRING)
83
84
# Reference: https://www.holadevs.com/pregunta/64750/change-selected-tab-color-in-ttknotebook
85
style = _tkinter_ttk.Style()
86
settings = {"TNotebook.Tab": {"configure": {"padding": [5, 1], "background": "#fdd57e"}, "map": {"background": [("selected", "#C70039"), ("active", "#fc9292")], "foreground": [("selected", "#ffffff"), ("active", "#000000")]}}}
87
style.theme_create("custom", parent="alt", settings=settings)
88
style.theme_use("custom")
89
90
# Reference: https://stackoverflow.com/a/10018670
91
def center(window):
92
window.update_idletasks()
93
width = window.winfo_width()
94
frm_width = window.winfo_rootx() - window.winfo_x()
95
win_width = width + 2 * frm_width
96
height = window.winfo_height()
97
titlebar_height = window.winfo_rooty() - window.winfo_y()
98
win_height = height + titlebar_height + frm_width
99
x = window.winfo_screenwidth() // 2 - win_width // 2
100
y = window.winfo_screenheight() // 2 - win_height // 2
101
window.geometry('{}x{}+{}+{}'.format(width, height, x, y))
102
window.deiconify()
103
104
def onKeyPress(event):
105
global line
106
global queue
107
108
if process:
109
if event.char == '\b':
110
line = line[:-1]
111
else:
112
line += event.char
113
114
def onReturnPress(event):
115
global line
116
global queue
117
118
if process:
119
try:
120
process.stdin.write(("%s\n" % line.strip()).encode())
121
process.stdin.flush()
122
except socket.error:
123
line = ""
124
event.widget.master.master.destroy()
125
return "break"
126
except:
127
return
128
129
event.widget.insert(_tkinter.END, "\n")
130
131
return "break"
132
133
def run():
134
global alive
135
global process
136
global queue
137
138
config = {}
139
140
for key in window._widgets:
141
dest, type = key
142
widget = window._widgets[key]
143
144
if hasattr(widget, "get") and not widget.get():
145
value = None
146
elif type == "string":
147
value = widget.get()
148
elif type == "float":
149
value = float(widget.get())
150
elif type == "int":
151
value = int(widget.get())
152
else:
153
value = bool(widget.var.get())
154
155
config[dest] = value
156
157
for option in parser.option_list:
158
config[option.dest] = defaults.get(option.dest, None)
159
160
handle, configFile = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.CONFIG, text=True)
161
os.close(handle)
162
163
saveConfig(config, configFile)
164
165
def enqueue(stream, queue):
166
global alive
167
168
for line in iter(stream.readline, b''):
169
queue.put(line)
170
171
alive = False
172
stream.close()
173
174
alive = True
175
176
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)
177
178
# Reference: https://stackoverflow.com/a/4896288
179
queue = _queue.Queue()
180
thread = threading.Thread(target=enqueue, args=(process.stdout, queue))
181
thread.daemon = True
182
thread.start()
183
184
top = _tkinter.Toplevel()
185
top.title("Console")
186
187
# Reference: https://stackoverflow.com/a/13833338
188
text = _tkinter_scrolledtext.ScrolledText(top, undo=True)
189
text.bind("<Key>", onKeyPress)
190
text.bind("<Return>", onReturnPress)
191
text.pack()
192
text.focus()
193
194
center(top)
195
196
while True:
197
line = ""
198
try:
199
# line = queue.get_nowait()
200
line = queue.get(timeout=.1)
201
text.insert(_tkinter.END, line)
202
except _queue.Empty:
203
text.see(_tkinter.END)
204
text.update_idletasks()
205
206
if not alive:
207
break
208
209
menubar = _tkinter.Menu(window)
210
211
filemenu = _tkinter.Menu(menubar, tearoff=0)
212
filemenu.add_command(label="Open", state=_tkinter.DISABLED)
213
filemenu.add_command(label="Save", state=_tkinter.DISABLED)
214
filemenu.add_separator()
215
filemenu.add_command(label="Exit", command=window.quit)
216
menubar.add_cascade(label="File", menu=filemenu)
217
218
menubar.add_command(label="Run", command=run)
219
220
helpmenu = _tkinter.Menu(menubar, tearoff=0)
221
helpmenu.add_command(label="Official site", command=lambda: webbrowser.open(SITE))
222
helpmenu.add_command(label="Github pages", command=lambda: webbrowser.open(GIT_PAGE))
223
helpmenu.add_command(label="Wiki pages", command=lambda: webbrowser.open(WIKI_PAGE))
224
helpmenu.add_command(label="Report issue", command=lambda: webbrowser.open(ISSUES_PAGE))
225
helpmenu.add_separator()
226
helpmenu.add_command(label="About", command=lambda: _tkinter_messagebox.showinfo("About", "Copyright (c) 2006-2025\n\n (%s)" % DEV_EMAIL_ADDRESS))
227
menubar.add_cascade(label="Help", menu=helpmenu)
228
229
window.config(menu=menubar)
230
window._widgets = {}
231
232
notebook = AutoresizableNotebook(window)
233
234
first = None
235
frames = {}
236
237
for group in parser.option_groups:
238
frame = frames[group.title] = _tkinter.Frame(notebook, width=200, height=200)
239
notebook.add(frames[group.title], text=group.title)
240
241
_tkinter.Label(frame).grid(column=0, row=0, sticky=_tkinter.W)
242
243
row = 1
244
if group.get_description():
245
_tkinter.Label(frame, text="%s:" % group.get_description()).grid(column=0, row=1, columnspan=3, sticky=_tkinter.W)
246
_tkinter.Label(frame).grid(column=0, row=2, sticky=_tkinter.W)
247
row += 2
248
249
for option in group.option_list:
250
_tkinter.Label(frame, text="%s " % parser.formatter._format_option_strings(option)).grid(column=0, row=row, sticky=_tkinter.W)
251
252
if option.type == "string":
253
widget = _tkinter.Entry(frame)
254
elif option.type == "float":
255
widget = ConstrainedEntry(frame, regex=r"\A\d*\.?\d*\Z")
256
elif option.type == "int":
257
widget = ConstrainedEntry(frame, regex=r"\A\d*\Z")
258
else:
259
var = _tkinter.IntVar()
260
widget = _tkinter.Checkbutton(frame, variable=var)
261
widget.var = var
262
263
first = first or widget
264
widget.grid(column=1, row=row, sticky=_tkinter.W)
265
266
window._widgets[(option.dest, option.type)] = widget
267
268
default = defaults.get(option.dest)
269
if default:
270
if hasattr(widget, "insert"):
271
widget.insert(0, default)
272
273
_tkinter.Label(frame, text=" %s" % option.help).grid(column=2, row=row, sticky=_tkinter.W)
274
275
row += 1
276
277
_tkinter.Label(frame).grid(column=0, row=row, sticky=_tkinter.W)
278
279
notebook.pack(expand=1, fill="both")
280
notebook.enable_traversal()
281
282
first.focus()
283
284
window.mainloop()
285
286