1
1
#!/usr/bin/env python
2
2
3
3
import datetime
4
+ from threading import Thread
4
5
import tkinter as tk
5
6
from tkinter import messagebox
6
7
import tkinter .ttk as ttk
7
8
from utils import InputValidator , Database , load_icon , callback
8
9
import sys
9
10
10
- __version__ = '1.0 .0'
11
+ __version__ = '1.1 .0'
11
12
12
13
class CreditsTool (tk .Toplevel ):
13
14
"""Opens a new window providing credits"""
@@ -16,7 +17,6 @@ def __init__(self, master=None, *args, **kwargs):
16
17
"""Initializes Toplevel object and builds credit interface."""
17
18
super ().__init__ (master , * args , ** kwargs )
18
19
# hide window in background during drawing and load, to prevent flickering and glitches during frame load
19
- #
20
20
self .withdraw ()
21
21
# build and draw the window
22
22
self .build ()
@@ -85,7 +85,7 @@ def save_data(self):
85
85
"""Stores investigation data within database"""
86
86
if self .data :
87
87
try :
88
- self .db_handler .store_investigation (self .investigation_id , self .data )
88
+ self .db_handler .store_investigation (self .entry . get () , self .data )
89
89
messagebox .showinfo ("Success" , "Successfully saved investigation" )
90
90
self .quit_save ()
91
91
@@ -100,6 +100,130 @@ def quit_save(self):
100
100
self .db_handler .close_connection ()
101
101
self .destroy ()
102
102
103
+ class OpenTool (tk .Toplevel ):
104
+ """Opens a window to retrieve investigation data"""
105
+ def __init__ (self , master = None , * args , ** kwargs ):
106
+ """Initializes Toplevel object and builds interface"""
107
+ super ().__init__ (master , * args , ** kwargs )
108
+ # initialize variables
109
+ self .selection = tk .StringVar (self )
110
+ # initialize database
111
+ self .db_handler = Database ()
112
+ # hide window in background during drawing and load, to prevent flickering and glitches during frame load
113
+ self .withdraw ()
114
+ # build and draw the window
115
+ self .build ()
116
+ # unhide the Toplevel window immediately after draw and load
117
+ self .after (0 , self .deiconify )
118
+
119
+ def build (self ):
120
+ """Initializes and builds application widgets"""
121
+ # create input labelframe
122
+ labelframe_1 = tk .LabelFrame (self , fg = 'brown' )
123
+ labelframe_1 .pack (side = "top" , expand = 'yes' , fill = 'both' , padx = 2 , pady = 2 , anchor = "n" )
124
+
125
+ # create explanation label
126
+ self .label = tk .Label (labelframe_1 , text = 'Load...' )
127
+ self .label .pack (expand = True , fill = 'x' , side = "left" , padx = 2 , pady = 2 )
128
+
129
+ # create data input entry widget
130
+ self .options = tk .OptionMenu (labelframe_1 , self .selection , * self .db_handler .retrieve_investigation_ids (),
131
+ command = self .open_data )
132
+ self .options .pack (expand = True , fill = 'x' , side = "left" , padx = 2 , pady = 2 )
133
+ self .selection .set (self .db_handler .retrieve_investigation_ids ()[0 ])
134
+
135
+ # create save button
136
+ self .save_button = tk .Button (labelframe_1 , text = "Open" , command = self .open_data )
137
+ self .save_button .pack (expand = False , side = "left" , padx = 2 , pady = 2 , anchor = "e" )
138
+
139
+ # create cancel button
140
+ self .cancel_button = tk .Button (labelframe_1 , text = "Cancel" , command = self .quit_open )
141
+ self .cancel_button .pack (expand = False , side = "left" , padx = 2 , pady = 2 , anchor = "e" )
142
+
143
+ def open_data (self , value = None ):
144
+ """Retrieves investigation data from database"""
145
+ pockint .treeview .delete (* pockint .treeview .get_children ())
146
+ pockint .id_tracker = {}
147
+ if value :
148
+ investigation_id = value
149
+ else :
150
+ investigation_id = self .selection .get ()
151
+ try :
152
+ iid , data = self .db_handler .open_investigation (investigation_id )
153
+ for target in data :
154
+ for transform in data [target ]:
155
+ pockint .treeview .insert (pockint .getID (target ), "end" , values = (transform [0 ], transform [1 ]))
156
+ pockint .investigation_id_tracker = iid
157
+ self .quit_open ()
158
+
159
+ except Exception as e :
160
+ print ("[*] Error: " , e )
161
+ self .quit_open ()
162
+
163
+ def quit_open (self ):
164
+ """Quits the open window"""
165
+ self .db_handler .close_connection ()
166
+ self .destroy ()
167
+
168
+ class DeleteTool (tk .Toplevel ):
169
+ """Opens a window to retrieve investigation data"""
170
+ def __init__ (self , master = None , * args , ** kwargs ):
171
+ """Initializes Toplevel object and builds interface"""
172
+ super ().__init__ (master , * args , ** kwargs )
173
+ # initialize variables
174
+ self .selection = tk .StringVar (self )
175
+ # initialize database
176
+ self .db_handler = Database ()
177
+ # hide window in background during drawing and load, to prevent flickering and glitches during frame load
178
+ self .withdraw ()
179
+ # build and draw the window
180
+ self .build ()
181
+ # unhide the Toplevel window immediately after draw and load
182
+ self .after (0 , self .deiconify )
183
+
184
+ def build (self ):
185
+ """Initializes and builds application widgets"""
186
+ # create input labelframe
187
+ labelframe_1 = tk .LabelFrame (self , fg = 'brown' )
188
+ labelframe_1 .pack (side = "top" , expand = 'yes' , fill = 'both' , padx = 2 , pady = 2 , anchor = "n" )
189
+
190
+ # create explanation label
191
+ self .label = tk .Label (labelframe_1 , text = 'Delete...' )
192
+ self .label .pack (expand = True , fill = 'x' , side = "left" , padx = 2 , pady = 2 )
193
+
194
+ # create data input entry widget
195
+ self .options = tk .OptionMenu (labelframe_1 , self .selection , * self .db_handler .retrieve_investigation_ids (),
196
+ command = self .delete_data )
197
+ self .options .pack (expand = True , fill = 'x' , side = "left" , padx = 2 , pady = 2 )
198
+ self .selection .set (self .db_handler .retrieve_investigation_ids ()[0 ])
199
+
200
+ # create save button
201
+ self .save_button = tk .Button (labelframe_1 , text = "Delete" , command = self .delete_data )
202
+ self .save_button .pack (expand = False , side = "left" , padx = 2 , pady = 2 , anchor = "e" )
203
+
204
+ # create cancel button
205
+ self .cancel_button = tk .Button (labelframe_1 , text = "Cancel" , command = self .quit )
206
+ self .cancel_button .pack (expand = False , side = "left" , padx = 2 , pady = 2 , anchor = "e" )
207
+
208
+ def delete_data (self , value = None ):
209
+ """Deletes investigation data from database"""
210
+ if value :
211
+ investigation_id = value
212
+ else :
213
+ investigation_id = self .selection .get ()
214
+ try :
215
+ self .db_handler .delete_investigation (investigation_id )
216
+ self .quit ()
217
+
218
+ except Exception as e :
219
+ print ("[*] Error: " , e )
220
+ self .quit ()
221
+
222
+ def quit (self ):
223
+ """Quits the open window"""
224
+ self .db_handler .close_connection ()
225
+ self .destroy ()
226
+
103
227
class ApiTool (tk .Toplevel ):
104
228
"""Opens a new window providing users ability to input api keys"""
105
229
@@ -187,8 +311,9 @@ def build_menu(self):
187
311
188
312
# create file menu
189
313
self .file = tk .Menu (self .top , tearoff = False )
190
- self .file .add_command (label = "Open investigation..." , compound = tk .LEFT , underline = 0 , command = None )
314
+ self .file .add_command (label = "Load investigation..." , compound = tk .LEFT , underline = 0 , command = self . open_investigation )
191
315
self .file .add_command (label = "Save investigation..." , compound = tk .LEFT , underline = 0 , command = self .save_investigation )
316
+ self .file .add_command (label = "Delete investigation..." , compound = tk .LEFT , underline = 0 , command = self .delete_investigation )
192
317
self .file .add_separator ()
193
318
self .file .add_command (label = 'Exit' , command = self .quit_program ,
194
319
underline = 0 )
@@ -197,6 +322,8 @@ def build_menu(self):
197
322
198
323
# create edit menu
199
324
self .edit = tk .Menu (self .top , tearoff = False )
325
+ self .edit .add_command (label = "Clear data" , compound = tk .LEFT , underline = 0 , command = self .clear_investigation_data )
326
+ self .edit .add_separator ()
200
327
self .edit .add_command (label = 'API keys' , command = self .manage_apis ,
201
328
compound = tk .LEFT , underline = 0 )
202
329
self .top .add_cascade (label = 'Edit' , menu = self .edit , underline = 0 )
@@ -308,6 +435,7 @@ def validate_input(self, event=None):
308
435
309
436
def run_data_mining (self , event = None ):
310
437
"""Performs the select OSINT data mining operation"""
438
+ self .finished = False
311
439
if self .multi_select .get ():
312
440
self .transforms_tracker .add (self .selector .get ())
313
441
self .status ['text' ] = "multi-select: [{}]" .format (" - " .join ([transform for transform in self .transforms_tracker ]))
@@ -318,18 +446,31 @@ def run_data_mining(self, event=None):
318
446
transform = self .selector .get ()
319
447
self .transforms_tracker .add (transform )
320
448
try :
321
- for i in _input :
322
- for transform in self .transforms_tracker :
323
- data = self .validator .execute_transform (i , transform )
324
- for item in data :
325
- self .treeview .insert (self .getID (i ), "end" , values = (transform , item ))
449
+ t = Thread (target = self .run_transform , args = (_input , self .transforms_tracker ,))
450
+ t .daemon = True
451
+ t .start ()
452
+ self .check_status ()
326
453
self .entry .focus ()
327
454
self .status ['text' ] = "ready"
328
455
self .transforms_tracker .clear ()
329
456
except Exception as e :
330
457
messagebox .showerror ("Error" , "Error message:" + str (e ))
331
458
else :
332
459
self .status ['text' ] = "no inputs"
460
+
461
+ def run_transform (self , _input , transforms ):
462
+ """Run lisf of transforms on input data"""
463
+ for i in _input :
464
+ for transform in transforms :
465
+ data = self .validator .execute_transform (i , transform )
466
+ for item in data :
467
+ self .treeview .insert (self .getID (i ), "end" , values = (transform , item ))
468
+ self .finished = True
469
+
470
+ def check_status (self ):
471
+ """Checks if the transform thread has finished executing"""
472
+ while self .finished is False :
473
+ root .update ()
333
474
334
475
def getID (self , item ):
335
476
"""Grabs the ID of the queried treeview item"""
@@ -362,6 +503,7 @@ def view_credits(self):
362
503
self .win_credits .title ('Credits' )
363
504
self .win_credits .geometry ('+%d+%d' % (root .winfo_x () +
364
505
20 , root .winfo_y () + 20 ))
506
+ self .win_credits .geometry ("160x100" )
365
507
if sys .platform == "win32" :
366
508
self .win_credits .iconbitmap (self .icon )
367
509
self .win_credits .resizable (width = False , height = False )
@@ -403,7 +545,7 @@ def grab_investigation_data(self):
403
545
def save_investigation (self ):
404
546
"""Saves investigation data"""
405
547
if not self .investigation_id_tracker :
406
- self .investigation_id_tracker = datetime .datetime .now ().strftime ("%Y%m%d%H %M" )
548
+ self .investigation_id_tracker = datetime .datetime .now ().strftime ("%Y-%m-%d_%H: %M" )
407
549
data = self .grab_investigation_data ()
408
550
409
551
self .save = SaveTool (investigation_id = self .investigation_id_tracker , data = data )
@@ -421,6 +563,56 @@ def save_investigation(self):
421
563
# start mainloop
422
564
self .save .mainloop ()
423
565
566
+ def open_investigation (self ):
567
+ """Open investigation data"""
568
+ db = Database ()
569
+ investigation_ids = db .retrieve_investigation_ids ()
570
+ if not investigation_ids :
571
+ messagebox .showinfo ("No saved investigations" , "Please save an investigation before loading data" )
572
+ db .close_connection ()
573
+ if investigation_ids :
574
+ # clear investigation id
575
+ self .investigation_id_tracker = ""
576
+
577
+ self .open = OpenTool ()
578
+ self .open .title ('Open investigation' )
579
+ self .open .geometry ('+%d+%d' % (root .winfo_x () +
580
+ 20 , root .winfo_y () + 20 ))
581
+ if sys .platform == "win32" :
582
+ self .open .iconbitmap (self .icon )
583
+ self .open .resizable (width = False , height = False )
584
+ self .open .protocol ('WM_DELETE_WINDOW' , self .open .quit_open )
585
+ # set focus on window
586
+ self .open .grab_set ()
587
+ self .open .focus ()
588
+
589
+ # start mainloop
590
+ self .open .mainloop ()
591
+
592
+ def delete_investigation (self ):
593
+ """Delete investigation data"""
594
+ self .delete = DeleteTool ()
595
+ self .delete .title ('Delete investigation' )
596
+ self .delete .geometry ('+%d+%d' % (root .winfo_x () +
597
+ 20 , root .winfo_y () + 20 ))
598
+ if sys .platform == "win32" :
599
+ self .delete .iconbitmap (self .icon )
600
+ self .delete .resizable (width = False , height = False )
601
+ self .delete .protocol ('WM_DELETE_WINDOW' , self .delete .quit )
602
+ # set focus on window
603
+ self .delete .grab_set ()
604
+ self .delete .focus ()
605
+
606
+ # start mainloop
607
+ self .delete .mainloop ()
608
+
609
+ def clear_investigation_data (self , event = None ):
610
+ """Clears investigation data from treeview"""
611
+ self .treeview .delete (* pockint .treeview .get_children ())
612
+ self .id_tracker = {}
613
+ self .entry .delete (0 , "end" )
614
+ self .validate_input ()
615
+
424
616
@staticmethod
425
617
def quit_program ():
426
618
"""Quits main program window"""
@@ -435,4 +627,4 @@ def quit_program():
435
627
if sys .platform == "win32" :
436
628
root .iconbitmap (pockint .icon )
437
629
root .protocol ('WM_DELETE_WINDOW' , pockint .quit_program )
438
- root .mainloop ()
630
+ root .mainloop ()
0 commit comments