Skip to content

Commit 2b4d8d8

Browse files
author
netevert
committed
added investigation save feature
1 parent 0efbb6e commit 2b4d8d8

File tree

2 files changed

+143
-24
lines changed

2 files changed

+143
-24
lines changed

pockint.py

Lines changed: 113 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ class CreditsTool(tk.Toplevel):
1515
def __init__(self, master=None, *args, **kwargs):
1616
"""Initializes Toplevel object and builds credit interface."""
1717
super().__init__(master, *args, **kwargs)
18-
# hide window in background during drawing and load, to prevent flickering and glitches as per
19-
# https://stackoverflow.com/questions/48492273/preloading-windows-to-avoid-tkinter-visual-glitches-during-frame-load
18+
# hide window in background during drawing and load, to prevent flickering and glitches during frame load
19+
#
2020
self.withdraw()
2121
# build and draw the window
2222
self.build()
@@ -40,23 +40,82 @@ def build(self):
4040
self.lbl_author.grid(row=1, column=0, sticky='w', padx=1, pady=1)
4141
self.lbl_author.bind("<Button-1>", lambda e: callback("https://twitter.com/netevert"))
4242

43+
class SaveTool(tk.Toplevel):
44+
"""Opens a window to store investigation data"""
45+
def __init__(self, master=None, investigation_id=None, data=None, *args, **kwargs):
46+
"""Initializes Toplevel object and builds interface"""
47+
super().__init__(master, *args, **kwargs)
48+
# initialize variables
49+
self.investigation_id = investigation_id
50+
self.data = data
51+
# initialize database
52+
self.db_handler = Database()
53+
# hide window in background during drawing and load, to prevent flickering and glitches during frame load
54+
self.withdraw()
55+
# build and draw the window
56+
self.build()
57+
# unhide the Toplevel window immediately after draw and load
58+
self.after(0, self.deiconify)
59+
60+
def build(self):
61+
"""Initializes and builds application widgets"""
62+
# create input labelframe
63+
labelframe_1 = tk.LabelFrame(self, fg='brown')
64+
labelframe_1.pack(side="top", expand='yes', fill='both', padx=2, pady=2, anchor="n")
65+
66+
# create explanation label
67+
self.label = tk.Label(labelframe_1, text='Save As...')
68+
self.label.pack(expand=True, fill='x', side="left", padx=2, pady=2)
69+
70+
# create data input entry widget
71+
self.entry = tk.Entry(labelframe_1)
72+
self.entry.pack(expand=True, fill='x', side="left", padx=2, pady=2)
73+
74+
# create save button
75+
self.save_button = tk.Button(labelframe_1, text="Save", command=self.save_data)
76+
self.save_button.pack(expand=False, side="left", padx=2, pady=2, anchor="e")
77+
78+
# create cancel button
79+
self.cancel_button = tk.Button(labelframe_1, text="Cancel", command=self.quit_save)
80+
self.cancel_button.pack(expand=False, side="left", padx=2, pady=2, anchor="e")
81+
82+
self.entry.insert(0, self.investigation_id)
83+
84+
def save_data(self):
85+
"""Stores investigation data within database"""
86+
if self.data:
87+
try:
88+
self.db_handler.store_investigation(self.investigation_id, self.data)
89+
messagebox.showinfo("Success", "Successfully saved investigation")
90+
self.quit_save()
91+
92+
except Exception:
93+
messagebox.showerror("Error saving data", "Failed to save data!")
94+
self.quit_save()
95+
else:
96+
messagebox.showinfo("No data", "There is no data to save")
97+
98+
def quit_save(self):
99+
"""Quits the save window"""
100+
self.db_handler.close_connection()
101+
self.destroy()
102+
43103
class ApiTool(tk.Toplevel):
44104
"""Opens a new window providing users ability to input api keys"""
45105

46106
def __init__(self, master=None, *args, **kwargs):
47-
"""Initializes Toplevel object and builds credit interface."""
107+
"""Initializes Toplevel object and builds interface"""
48108
super().__init__(master, *args, **kwargs)
49109
self.db_handler = Database()
50-
# hide window in background during drawing and load, to prevent flickering and glitches as per
51-
# https://stackoverflow.com/questions/48492273/preloading-windows-to-avoid-tkinter-visual-glitches-during-frame-load
110+
# hide window in background during drawing and load, to prevent flickering and glitches during frame load
52111
self.withdraw()
53112
# build and draw the window
54113
self.build()
55114
# unhide the Toplevel window immediately after draw and load
56115
self.after(0, self.deiconify)
57116

58117
def build(self):
59-
"""Initializes and builds application widgets."""
118+
"""Initializes and builds application widgets"""
60119
# create input labelframe
61120
labelframe_1 = tk.LabelFrame(self, text="api key manager", fg='brown')
62121
labelframe_1.pack(side="top", expand='yes', fill='both', padx=2, pady=2, anchor="n")
@@ -120,27 +179,36 @@ def __init__(self, master=None, *args, **kwargs):
120179
self.build_interface()
121180
self.id_tracker = dict()
122181
self.transforms_tracker = set()
182+
self.investigation_id_tracker = ""
123183

124184
def build_menu(self):
125185
"""Initializes and builds program menu bar"""
126186
self.top = tk.Menu(self)
127187

128-
# create run menu
129-
self.run = tk.Menu(self.top, tearoff=False)
130-
self.run.add_checkbutton(label="Multi-Select", onvalue=True, offvalue=False, variable=self.multi_select, command=self.config_menu)
131-
self.run.add_command(label='Run Transform', accelerator='Ctrl+R',
132-
command=self.run_data_mining, compound=tk.LEFT, underline=0)
133-
self.run.add_separator()
134-
self.run.add_command(label='Exit', command=self.quit_program,
188+
# create file menu
189+
self.file = tk.Menu(self.top, tearoff=False)
190+
self.file.add_command(label="Open investigation...", compound=tk.LEFT, underline=0, command=None)
191+
self.file.add_command(label="Save investigation...", compound=tk.LEFT, underline=0, command=self.save_investigation)
192+
self.file.add_separator()
193+
self.file.add_command(label='Exit', command=self.quit_program,
135194
underline=0)
136-
self.top.add_cascade(label='Run', menu=self.run, underline=0)
195+
196+
self.top.add_cascade(label="File", menu=self.file, underline=0)
137197

138198
# create edit menu
139199
self.edit = tk.Menu(self.top, tearoff=False)
140200
self.edit.add_command(label='API keys', command=self.manage_apis,
141201
compound=tk.LEFT, underline=0)
142202
self.top.add_cascade(label='Edit', menu=self.edit, underline=0)
143203

204+
# create run menu
205+
self.run = tk.Menu(self.top, tearoff=False)
206+
self.run.add_checkbutton(label="Multi-Select", onvalue=True, offvalue=False, variable=self.multi_select, command=self.config_menu)
207+
self.run.add_command(label='Run Transform', accelerator='Ctrl+R',
208+
command=self.run_data_mining, compound=tk.LEFT, underline=0)
209+
210+
self.top.add_cascade(label='Run', menu=self.run, underline=0)
211+
144212
# create about menu
145213
self.info = tk.Menu(self.top, tearoff=False)
146214
self.info.add_command(label='About ...', command=self.view_credits,
@@ -167,12 +235,6 @@ def build_interface(self):
167235
self.selector = ttk.Combobox(labelframe_1, values=[""], state="readonly")
168236
self.selector.pack(expand=True, fill='x', side="top", padx=2, pady=2)
169237

170-
#self.checkBox1 = tk.Checkbutton(labelframe_1, variable=None, onvalue=1, offvalue=0, text="Multi-select")
171-
#self.checkBox1.pack(expand=False, side="left", padx=2, pady=2, anchor="w")
172-
173-
#self.entry2 = tk.Entry(labelframe_1)
174-
#self.entry2.pack(expand=True, fill='x', side="left", padx=2, pady=2, anchor="w")
175-
176238
# create results frame
177239
frame_2 = tk.Frame()
178240
frame_2.pack(expand=True, fill='both', anchor="n")
@@ -261,10 +323,6 @@ def run_data_mining(self, event=None):
261323
data = self.validator.execute_transform(i, transform)
262324
for item in data:
263325
self.treeview.insert(self.getID(i), "end", values=(transform, item))
264-
# todo: focus on last treeview output to be able to hit enter and iterate
265-
# item = self.treeview.insert('', 'end', text=_input, values=(transform, data))
266-
# self.treeview.focus_set()
267-
# self.treeview.selection_set(item)
268326
self.entry.focus()
269327
self.status['text'] = "ready"
270328
self.transforms_tracker.clear()
@@ -332,6 +390,37 @@ def manage_apis(self):
332390
# start mainloop
333391
self.api_tool.mainloop()
334392

393+
def grab_investigation_data(self):
394+
""""Stores investigation data"""
395+
data = {}
396+
for Parent in self.treeview.get_children():
397+
data[self.treeview.item(Parent)["text"]]=[]
398+
for child in self.treeview.get_children(Parent):
399+
if self.treeview.item(child)["values"] not in data[self.treeview.item(Parent)["text"]]:
400+
data[self.treeview.item(Parent)["text"]].append(self.treeview.item(child)["values"])
401+
return data
402+
403+
def save_investigation(self):
404+
"""Saves investigation data"""
405+
if not self.investigation_id_tracker:
406+
self.investigation_id_tracker = datetime.datetime.now().strftime("%Y%m%d%H%M")
407+
data = self.grab_investigation_data()
408+
409+
self.save = SaveTool(investigation_id=self.investigation_id_tracker, data=data)
410+
self.save.title('Save investigation')
411+
self.save.geometry('+%d+%d' % (root.winfo_x() +
412+
20, root.winfo_y() + 20))
413+
if sys.platform == "win32":
414+
self.save.iconbitmap(self.icon)
415+
self.save.resizable(width=False, height=False)
416+
self.save.protocol('WM_DELETE_WINDOW', self.save.quit_save)
417+
# set focus on window
418+
self.save.grab_set()
419+
self.save.focus()
420+
421+
# start mainloop
422+
self.save.mainloop()
423+
335424
@staticmethod
336425
def quit_program():
337426
"""Quits main program window"""

utils.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import base64
44
import dns.resolver
5+
import json
56
import os
67
import re
78
import requests
@@ -39,6 +40,8 @@ def create_database(self):
3940
try:
4041
cursor.execute('''CREATE TABLE api_keys(id INTEGER PRIMARY KEY, api_name TEXT,
4142
api_key TEXT, status INTEGER)''')
43+
cursor.execute('''CREATE TABLE json_data (id INTEGER PRIMARY KEY,
44+
investigation_id TEXT, json TEXT)''')
4245
init_data = [("virustotal", "", 0), ("shodan", "", 0)]
4346
cursor.executemany(''' INSERT INTO api_keys(api_name, api_key, status) VALUES(?,?,?)''', init_data)
4447
db.commit()
@@ -82,6 +85,33 @@ def get_apis(self):
8285
except sqlite3.Error:
8386
self.db.rollback()
8487

88+
def store_investigation(self, investigation_id, data):
89+
"""Stores investigation data in tab by investigation_id"""
90+
data = json.dumps(data)
91+
try:
92+
self.cursor.execute('''SELECT * FROM json_data WHERE investigation_id=?''', (investigation_id,))
93+
if not self.cursor.fetchone():
94+
# insert fresh data
95+
self.cursor.execute('''INSERT INTO json_data(investigation_id, json) Values (?,?)''',
96+
(investigation_id, data))
97+
else:
98+
# update data
99+
self.cursor.execute('''UPDATE json_data SET json=? WHERE investigation_id=?''',
100+
(data, investigation_id))
101+
self.db.commit()
102+
except sqlite3.Error:
103+
self.db.rollback()
104+
105+
def retrieve_investigation(self, investigation_id):
106+
"""Retrieves investigation data by investigation_id returning"""
107+
try:
108+
self.cursor.execute('''''')
109+
data = self.cursor.fetchone()[2]
110+
except sqlite3.Error:
111+
self.db.rollback()
112+
113+
return json.loads(data)
114+
85115
def close_connection(self):
86116
"""Closes the connection to the local database file"""
87117
self.db.close()

0 commit comments

Comments
 (0)