Compare commits

..

21 Commits

Author SHA1 Message Date
e06ba5cecd currently fixed 2022-11-15 19:21:18 -06:00
23a3f27b57 mac compatibility 2022-11-02 13:05:39 -05:00
12f93c04d2 Clean up extra code 2022-10-25 11:05:35 -05:00
37231e8b57 Remove login test 2022-10-25 01:41:15 -05:00
7e67920719 Merge branch 'testing' of https://git.deck.sh/Interfaz/ff into testing 2022-10-25 01:38:09 -05:00
b3d26107f9 git fix 2022-10-25 01:33:35 -05:00
a31cd877f2 Disable debug mode for demo, add status text 2022-10-25 01:21:20 -05:00
ba0e84ee95 Add icon to installer 2022-10-25 01:04:10 -05:00
8a803b9d02 Add icons, firewall blocking (windows) 2022-10-25 01:03:04 -05:00
def22643f6 fix UI data for blocked connections 2022-10-24 22:35:35 -05:00
f64ff86d83 More UI functionality 2022-10-24 22:13:29 -05:00
ae230af4fc continue work on blocking 2022-10-18 21:01:34 -05:00
6f2f8fc535 add numpy dep 2022-10-18 19:32:56 -05:00
258918eecc yaml2 2022-10-18 19:24:00 -05:00
f781056b69 Merge branch 'testing' of https://git.deck.sh/Interfaz/ff into testing 2022-10-18 19:22:41 -05:00
2ee04b59d1 yaml 2022-10-18 19:22:32 -05:00
88b38d1492 start block code 2022-10-18 19:13:48 -05:00
bbb92d1fdb Add red highlighting, better align buttons 2022-10-18 16:08:45 -05:00
0b97b2287a Add new UI files 2022-10-18 12:41:10 -05:00
578eea1c1f Add UI import, add login to UI, etc 2022-10-17 13:50:39 -05:00
5c7cd9b0a5 Finish auth 2022-10-11 20:47:12 -05:00
22 changed files with 824 additions and 86137 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

1
.gitignore vendored
View File

@ -6,3 +6,4 @@ admin-key.ppk
token.txt token.txt
*.zip *.zip
output.log output.log
output.log

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"python.pythonPath": "/usr/bin/python3"
}

BIN
WXPython.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
WXPython_30x30.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

35
auth.py
View File

@ -3,26 +3,41 @@ import csv
from util import fprint from util import fprint
from util import find_data_file from util import find_data_file
from time import sleep from time import sleep
import bcrypt
def login(config, user, password, sysid): def login(config, user, password, sysid):
fprint("Attempting to login as " + user) fprint("Attempting to login as " + user)
filename = sysid + "login.csv" filename = sysid + "login.csv"
#hashpasswd = bcrypt.hashpw(password.encode('utf-8'), user).decode()
with open(find_data_file(filename), "w", newline="") as f: with open(find_data_file(filename), "w", newline="") as f:
writer = csv.writer(f) writer = csv.writer(f)
writer.writerows([[user,password,sysid],]) writer.writerows([[user,password,sysid],])
fprint("done creating csv") fprint("done creating csv")
#return True
ssh.sftp_send_data(config, filename, 'sendlogin') ssh.sftp_send_data(config, filename, 'sendlogin')
command = "python3 login_service.py " + sysid command = "python3 login_service.py " + sysid
ssh.run_ssh(config, command, 'scripts') ssh.run_ssh(config, command, 'scripts')
sleep(1)
filename = sysid + "success.txt" filename = sysid + "success.txt"
output = ssh.check_for_file(config, filename, 'receivelogin') count = 0
if output == False: while count < 20:
filename = sysid + "fail.txt" output = ssh.check_for_file(config, filename, 'receivelogin')
if ssh.check_for_file(config, filename, 'receivelogin') == False: if output == False:
raise ValueError("Unable to determine login status") filename = sysid + "fail.txt"
if ssh.check_for_file(config, filename, 'receivelogin') == False:
# try again
count += 1
sleep(0.1)
filename = sysid + "success.txt"
#raise ValueError("Unable to determine login status")
else:
return False
else: else:
return False fprint(type(output))
else: if str(output).find("admin") >= 0 or str(output).find("Admin") >= 0:
return True fprint("Authorized as admin!")
fprint(output) return True
else:
fprint("Not admin")
return False
return False

84
block.py Normal file
View File

@ -0,0 +1,84 @@
from util import find_data_file
from util import setup_child
from util import fprint
from util import run_cmd
from util import win32
from util import linux
from util import kill
import util
import time
import csv
import ssh
def get_blocklist(config):
setup_child()
fprint("Downloading deny list from server")
data = ssh.check_for_file(config, "BadIPs.csv", "receive")
#fprint(data.stdout)
csvreader = csv.reader(data.stdout.split("\n"), delimiter=',', quotechar='|')
data2 = list()
for row in csvreader:
data2.append(row)
data2 = [i for i in data2 if i]
#fprint(data2)
data2.append(["N/A", "TCP", "N/A", "N/A", "20.112.52.29", "5000", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A"])
data2.append(["N/A", "TCP", "N/A", "N/A", "20.81.111.85", "80", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A"])
data2.append(["N/A", "TCP", "N/A", "N/A", "100.115.71.78", "5000", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A"])
data2.append(["N/A", "TCP", "N/A", "N/A", "100.115.71.78", "5000", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A"])
data2.append(["N/A", "TCP", "N/A", "N/A", "174.143.130.167", "443", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A"])
data2.append(["N/A", "TCP", "N/A", "N/A", "216.47.134.203", "443", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A"])
data2.append(["N/A", "TCP", "N/A", "N/A", "34.111.83.189", "443", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A"])
fprint(data2)
with open(find_data_file("blocklist.csv"), "w", newline="") as f:
writer = csv.writer(f)
writer.writerows(data2)
fprint("done creating csv")
return data2
def block_conn(config, datafile, res):
setup_child()
fprint("Searching block data")
mydata = list()
badapps = list()
badips = list()
badlines = list()
with open(find_data_file(datafile), newline='') as csvfile:
csvreader = csv.reader(csvfile, delimiter=',', quotechar='|')
for row in csvreader:
mydata.append(row)
baddata = res
fprint("Local loaded successfully")
#fprint(mydata)
for line in mydata:
#fprint(line)
#fprint(line)
if line[0].find("0x") >= 0:
continue
srcip = line[2].split(":")[0]
destip = line[3].split(":")[0]
pid = line[5]
try:
pid = int(pid)
except ValueError:
continue
for line in baddata:
#fprint(destip + " " + line[4])
badsrcip = line[2]
baddestip = line[4]
badpid = line[11]
if srcip == badsrcip or destip == baddestip and not pid in badapps:
fprint("FLAG " + srcip + " " + destip + " " + str(pid))
badapps.append(pid)
badips.append(baddestip)
badlines.append(line)
#fprint(badapps)
#fprint("FLAG " + srcip + " " + destip + " " + str(pid))
#kill(pid)
return badapps, badips, badlines

View File

@ -1,19 +1,19 @@
core:
autostart: true
clockspeed: 20
interval: 10
level: 0
localadmin: true
sftp: sftp:
host: ec2-34-232-29-46.compute-1.amazonaws.com filepath:
user: ec2-user
port: 22
keyfile: keyfile-admin.pem
filepath:
send: /home/ec2-user/Incoming/Incoming_Data
sendlogin: /home/ec2-user/Incoming/Login
receive: /home/ec2-user/Outgoing/Outgoing_Data receive: /home/ec2-user/Outgoing/Outgoing_Data
receivelogin: /home/ec2-user/Outgoing/Login receivelogin: /home/ec2-user/Outgoing/Login
scripts: /home/ec2-user/scripts scripts: /home/ec2-user/scripts
send: /home/ec2-user/Incoming/Incoming_Data
sendlogin: /home/ec2-user/Incoming/Login
host: ec2-34-232-29-46.compute-1.amazonaws.com
keyfile: keyfile-admin.pem
port: 22
user: ec2-user
ui: ui:
darkmode: true darkmode: true
core:
autokill: false
localadmin: true
interval: 10

View File

@ -1,138 +0,0 @@
import glob
import wx
import wx.adv
import os
from time import sleep
from multiprocessing import Process, Pipe
from sys import platform
TRAY_TOOLTIP = 'IP Pigeon'
TRAY_ICON = 'icon.png'
"""if platform == "linux" or platform == "linux2":
# linux
elif platform == "darwin":
# OS X
elif platform == "win32":
# Windows...
"""
displaydata = None
settings = None
class ServerPanel(wx.Panel):
def __init__(self, parent):
super().__init__(parent)
main_sizer = wx.BoxSizer(wx.VERTICAL)
self.row_obj_dict = {}
self.list_ctrl = wx.ListCtrl(
self, size=(-1, 100),
style=wx.LC_REPORT | wx.BORDER_SUNKEN
)
self.list_ctrl.InsertColumn(0, 'Server name', width=140)
self.list_ctrl.InsertColumn(1, 'Port number', width=140)
self.list_ctrl.InsertColumn(2, 'Status', width=200)
main_sizer.Add(self.list_ctrl, 0, wx.ALL | wx.EXPAND, 5)
start_button = wx.Button(self, label='Start')
start_button.Bind(wx.EVT_BUTTON, self.on_edit)
stop_button = wx.Button(self, label='Stop')
stop_button.Bind(wx.EVT_BUTTON, self.on_edit)
main_sizer.Add(start_button, 0, wx.ALL | 100, 5)
main_sizer.Add(stop_button, 0, wx.ALL | 100, 5)
self.SetSizer(main_sizer)
def on_edit(self, event):
print('in on_edit')
def update_mp3_listing(self, folder_path):
print(folder_path)
class ServerFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None,
title='Server Dashboard')
self.panel = ServerPanel(self)
self.Show()
### Taskbar Icon
def create_menu_item(menu, label, func):
item = wx.MenuItem(menu, -1, label)
menu.Bind(wx.EVT_MENU, func, id=item.GetId())
menu.Append(item)
return item
class TaskBarIcon(wx.adv.TaskBarIcon):
def __init__(self, frame):
self.frame = frame
super(TaskBarIcon, self).__init__()
self.set_icon(TRAY_ICON)
self.Bind(wx.adv.EVT_TASKBAR_LEFT_DOWN, self.on_left_down)
def CreatePopupMenu(self):
menu = wx.Menu()
create_menu_item(menu, 'Control Panel', self.on_open)
menu.AppendSeparator()
create_menu_item(menu, 'Exit', self.on_exit)
return menu
def set_icon(self, path):
icon = wx.Icon(path)
self.SetIcon(icon, TRAY_TOOLTIP)
def on_left_down(self, event):
print ('Tray icon was left-clicked.')
def on_open(self, event):
foreground()
#self.close_popup()
def on_exit(self, event):
wx.CallAfter(self.Destroy)
self.close_popup()
def close_popup(self):
self.frame.Close()
class TaskbarApp(wx.App):
def OnInit(self):
frame=wx.Frame(None)
self.SetTopWindow(frame)
TaskBarIcon(frame)
return True
class FullApp(wx.App):
def OnInit(self):
fullframe=ServerFrame()
return True
def background():
app = TaskbarApp(False)
#with Manager() as manager:
app.MainLoop()
#displaydata = manager.list()
#settings = manager.list()
#rawdata = manager.list()
#logdata = manager.list()
#uploaddata = manager.list()
#downloaddata = manager.list()
def open_fg(outputdata, uisettings):
app = FullApp(False)
app.MainLoop()
def foreground():
# Open the foreground in a separate process so that UI acts independently of the taskbar icon
p = Process(target=open_fg, args=(displaydata, settings))
p.start()
#p.join()
print("Launched foreground")
if __name__ == '__main__':
background()

View File

@ -8,17 +8,24 @@ import uuid
import yaml import yaml
from util import find_data_file from util import find_data_file
from util import fprint from util import fprint
from util import kill
from util import run_cmd
import taskbartool import taskbartool
import util import util
import netstat import netstat
import ssh import ssh
import auth import auth
import panel
import block
badapps = [756, 278670]
badips = ["208.59.79.12",]
displaydata = None displaydata = None
settings = None settings = None
netdata_res = None netdata_res = None
procdata_res = None procdata_res = None
killme = None killme = None
ppanel = None
datafile = "" datafile = ""
#print(datafile) #print(datafile)
config = None config = None
@ -41,7 +48,7 @@ if win32:
_, username = res.strip().rsplit("\n", 1) _, username = res.strip().rsplit("\n", 1)
userid, sysdom = username.rsplit("\\", 1) userid, sysdom = username.rsplit("\\", 1)
if linux: if linux or macos:
sysid = hex(uuid.getnode()) sysid = hex(uuid.getnode())
#fprint(sysid) #fprint(sysid)
datafile += sysid datafile += sysid
@ -57,18 +64,60 @@ def netstat_done(res):
#netstat.process(res) #netstat.process(res)
def process_done(res): def process_done(res):
fprint("uploading to sftp...") if settings["running"] == True:
#ssh.sftp_send_data(res, config, datafile) #settings["newdata"] = True
procdata_res = pool.apply_async(ssh.sftp_send_data, (config, datafile, 'send')) fprint("uploading to sftp...")
#ssh.sftp_send_data(res, config, datafile)
procdata_res = pool.apply_async(ssh.sftp_send_data, (config, datafile, 'send'), callback=upload_done)
def upload_done(res):
settings["block"] = True
def login_done(res): def login_done(res):
if not res: if not res:
fprint("Login failure") fprint("Login failure")
settings["message"] = "Login failure" settings["message"] = "Login failure"
else: else:
fprint("Login result in main: " + str(res)) fprint("Login result in main: " + str(res))
settings["loggedin"] = res
settings["continueui"] = True
def blockdata_done(res):
global settings
fprint("FINISHED downloading block data")
tmpkill = settings["kill"]
settings["kill"] = False
#block_res = pool.apply_async(block.block_conn, (config, datafile, res, settings))
block_pids, block_ips, block_data = block.block_conn(config, datafile, res)
tmplist = settings["badapps"]
for x in block_pids:
fprint(x)
if not x in tmplist:
tmplist.append(x)
settings["badapps"] = tmplist
fprint(settings["badapps"])
tmplist = settings["badips"]
for x in block_ips:
fprint(x)
if not x in tmplist:
tmplist.append(x)
settings["badips"] = tmplist
fprint(settings["badips"])
settings["kill"] = tmpkill
tmplist = settings["badlines"]
for x in block_data:
fprint(x)
if not x in tmplist:
tmplist.append(x)
settings["badlines"] = tmplist
fprint(settings["badlines"])
settings["newdata"] = True
def killall(): def killall():
kids = active_children() kids = active_children()
for kid in kids: for kid in kids:
@ -76,21 +125,24 @@ def killall():
fprint("Every child has been killed") fprint("Every child has been killed")
os.kill(os.getpid(), 9) # dirty kill of self os.kill(os.getpid(), 9) # dirty kill of self
def mainloop(pool): def mainloop(pool):
# worker pool: netstat, netstat cleanup, upload, download, ui tasks # worker pool: netstat, netstat cleanup, upload, download, ui tasks
global config
global counter global counter
global netdata_res global netdata_res
global procdata_res global procdata_res
global rawdata global rawdata
global killme global killme
global ppanel
#print(killme) #print(killme)
if killme.value > 0: if killme.value > 0:
#print("killing") #print("killing")
killall() killall()
#print(res.get(timeout=1)) #print(res.get(timeout=1))
if counter == 0: # runs every INTERVAL if counter == 0: # runs every INTERVAL
fprint("start loop") #fprint("start loop")
if netdata_res is None or netdata_res.ready(): if netdata_res is None or netdata_res.ready():
#rawdata = netdata_res.get() #rawdata = netdata_res.get()
#procdata_res = pool.apply_async(process_netstat, (rawdata)) #procdata_res = pool.apply_async(process_netstat, (rawdata))
@ -99,16 +151,80 @@ def mainloop(pool):
#fprint(netdata_res.successful()) #fprint(netdata_res.successful())
# runs every 50ms # runs every 50ms
if settings["continueui"] == True:
settings["continueui"] = False
if ppanel is not None:
# login panel is already open
ppanel.terminate()
ppanel = Process(target=panel.openwindow, args=(displaydata,settings,killme))
ppanel.start()
if settings["showui"] == True:
settings["showui"] = False
ppanel = Process(target=panel.openwindow, args=(displaydata,settings,killme))
ppanel.start()
if settings["login"] == True: if settings["login"] == True:
login_res = pool.apply_async(auth.login, (config, settings["username"], settings["password"], sysid), callback=login_done) login_res = pool.apply_async(auth.login, (config, settings["username"], settings["password"], sysid), callback=login_done)
#fprint(auth.login(config, settings["username"], settings["password"], sysid)) #fprint(auth.login(config, settings["username"], settings["password"], sysid))
settings["login"] = False settings["login"] = False
if settings["block"] == True and settings["running"] == True:
blockdata_res = pool.apply_async(block.get_blocklist, (config,), callback=blockdata_done)
#block.get_blocklist(config)
settings["block"] = False
sleep(interval / (interval * 20.0)) if config["core"]["level"] == 0:
settings["kill"] = False
settings["fwll"] = False
if config["core"]["level"] == 1:
settings["kill"] = True
settings["fwll"] = False
if config["core"]["level"] == 2:
settings["kill"] = False
settings["fwll"] = True
if config["core"]["level"] == 3:
settings["kill"] = True
settings["fwll"] = True
if settings["kill"] == True:
tmplist = settings["badapps"]
settings["badapps"] = list()
for x in tmplist:
kill(x)
if settings["fwll"] == True:
tmplist = settings["badlines"]
settings["badlines"] = list()
for line in tmplist:
badproto = line[1]
badip = line[4]
badport = line[5]
fprint("Firewalling " + badip + ":" + str(badport))
cmd = 'New-NetFirewallRule -DisplayName "IPPigeon Security Rule ' + badip + ':' + str(badport) + '" -Group "IPPigeon" -Direction Outbound -LocalPort Any -Protocol ' + badproto + ' -Action Block -RemoteAddress ' + badip + ' -RemotePort ' + str(badport)
run_cmd(cmd)
if settings["applyconfig"] == True:
settings["applyconfig"] = False
config = settings["config"]
#fprint(settings["config"])
with open(find_data_file('config.yml'), 'w') as filewrite:
#global config
yaml.dump(config, filewrite)
fprint("Config saved!")
sleep(interval / (interval * config["core"]["clockspeed"]))
counter += 1 counter += 1
if counter == interval * 20: if counter == interval * config["core"]["clockspeed"]:
counter = 0 counter = 0
class Logger(object): class Logger(object):
def __init__(self, filename="output.log"): def __init__(self, filename="output.log"):
self.log = open(filename, "a") self.log = open(filename, "a")
@ -133,21 +249,35 @@ if __name__ == '__main__':
sys.stdout = Logger(filename=find_data_file("output.log")) sys.stdout = Logger(filename=find_data_file("output.log"))
sys.stderr = Logger(filename=find_data_file("output.log")) sys.stderr = Logger(filename=find_data_file("output.log"))
with Manager() as manager:
with Pool(processes=5) as pool: with Pool(processes=5) as pool:
with Manager() as manager:
with open(find_data_file('config.yml'), 'r') as file: with open(find_data_file('config.yml'), 'r') as fileread:
#global config #global config
config = yaml.safe_load(file) config = yaml.safe_load(fileread)
#print(config['sftp']['host']) #print(config['sftp']['host'])
interval = config['core']['interval'] interval = config['core']['interval']
displaydata = manager.list(range(2)) # data to be printed displaydata = manager.list(range(2)) # data to be printed
settings = manager.dict() # configuration settings = manager.dict() # configuration
settings["login"] = False settings["login"] = False
settings["loggedin"] = False settings["loggedin"] = False
settings["showui"] = False
settings["continueui"] = False
settings["killbox"] = list()
settings["badapps"] = list()
settings["badips"] = list()
settings["badlines"] = list()
settings["block"] = False
settings["kill"] = False
settings["config"] = config
settings["applyconfig"] = False
settings["fwll"] = 0
settings["running"] = config["core"]["autostart"]
settings["newdata"] = False
killme = manager.Value('d', 0) killme = manager.Value('d', 0)
#killme = False #killme = False
# launch background UI app as process # launch background UI app as process
util.clear_fwll()
p = Process(target=taskbartool.background, args=(displaydata,settings,killme)) p = Process(target=taskbartool.background, args=(displaydata,settings,killme))
p.start() p.start()
#p.join() # not a foreground job, so let's not join it #p.join() # not a foreground job, so let's not join it
@ -160,11 +290,4 @@ if __name__ == '__main__':
# launch loop - non-blocking! # launch loop - non-blocking!
counter = 0 counter = 0
while(keeprunning): while(keeprunning):
mainloop(pool) mainloop(pool)

View File

@ -4,6 +4,7 @@ from util import fprint
from util import run_cmd from util import run_cmd
from util import win32 from util import win32
from util import linux from util import linux
from util import macos
import util import util
import time import time
import csv import csv
@ -70,8 +71,10 @@ def process(data):
writer.writerows(output2) writer.writerows(output2)
fprint("done creating csv") fprint("done creating csv")
if linux: if linux or macos:
output = data.stdout.decode().split('\n') # split stdout into lines output = data.stdout.decode().split('\n') # split stdout into lines
#output = data.stdout.decode().split(',')
#fprint("output data: " + str(output))
output = [i for i in output if i] output = [i for i in output if i]
if output[0].find("Not all processes could be identified") >= 0: if output[0].find("Not all processes could be identified") >= 0:
fprint("Not enough permissions") fprint("Not enough permissions")
@ -83,25 +86,22 @@ def process(data):
string_split = [i for i in string_split if i] string_split = [i for i in string_split if i]
#fprint("Input: " + str(string_split)) #fprint("Input: " + str(string_split))
if string_split[1].find("Multipath") >= 0:
break
if string_split[0].find("Active") >= 0 or string_split[0].find("Proto") >= 0: if string_split[0].find("Active") >= 0 or string_split[0].find("Proto") >= 0:
continue continue
if len(string_split) == 6: # no connection status if len(string_split) == 10: # no connection status
#fprint(string_split) #fprint(string_split)
string_split.append(string_split[-1]) string_split.append(string_split[-1])
string_split[-2] = "UNKNOWN" string_split[-7] = "UNKNOWN"
string_split[-4] = string_split[-5]
#fprint(string_split) #fprint(string_split)
procname = string_split[6]
if procname != "-":
string_split2 = procname.split("/")
procname = string_split2[1]
pid = string_split2[0]
else:
pid = "Unknown"
output2.append([procname, string_split[0], string_split[3], string_split[4], string_split[5], pid]) output2.append(["Unknown", string_split[0], string_split[3], string_split[4], string_split[5], string_split[8]])
#fprint(output2) #fprint("FINAL CSV: " + str(output2))
with open(find_data_file(util.datafile), "w", newline="") as f: with open(find_data_file(util.datafile), "w", newline="") as f:
writer = csv.writer(f) writer = csv.writer(f)
@ -123,3 +123,7 @@ def start():
fprint("data acquired") fprint("data acquired")
return data return data
if macos:
data = run_cmd("netstat -anv")
fprint("data acquired")
return data

85933
output.log

File diff suppressed because one or more lines are too long

365
panel.py Normal file
View File

@ -0,0 +1,365 @@
import glob
import wx
import wx.lib.buttons as buttons
import numpy as np
import pandas as pd
from util import sysid
from util import setup_child
from util import fprint
from util import find_data_file
import util
BG_IMG = 'icon.png'
filename = sysid + "gendata.csv"
COLUMN_NAMES = np.flip(['Executable', 'Proto', 'Source IP', 'Destination IP', 'Status', 'PID'])
COLUMN_SIZES = np.flip([200, 50, 200, 200, 140, 100])
TEST_FILE = None
SEC_LEVELS = ["0: Backend analysis only.", "1: Kill offending processes.", "2: Block offending connections using firewall.", "3: Kill and block connections and processes."]
displaydata = None
settings = None
killme = False
def loaddata():
global TEST_FILE
try:
TEST_FILE = pd.read_csv(find_data_file(filename), skiprows=1)
TEST_FILE = TEST_FILE.iloc[1:, :]
TEST_FILE.columns = ['Executable', 'Protocol', 'Source IP', 'Destination IP', 'Status', 'PID']
#fprint(TEST_FILE)
#fprint(len(TEST_FILE))
#fprint(TEST_FILE.iloc[1, 1])
except FileNotFoundError:
pass
class OtherFrame(wx.Frame):
"""
Class used for creating frames other than the main one
"""
def __init__(self):
wx.Frame.__init__(self, None, -1, 'Server Panel', size=(1000, 620))
panel = ServerPanel(self)
self.SetIcon(wx.Icon(find_data_file("icon.ico"), wx.BITMAP_TYPE_ICO))
self.Show()
def on_edit(self, event):
fprint('in on_edit')
def on_window(self, event):
return
class HelpFrame(wx.Frame):
"""
Class used for creating frames other than the main one
"""
def __init__(self):
wx.Frame.__init__(self, None, -1, 'Help', size=(600, 250))
panel = HelpPanel(self)
self.SetIcon(wx.Icon(find_data_file("icon.ico"), wx.BITMAP_TYPE_ICO))
self.Show()
# Panel with all the login widgets
class LoginPanel(wx.Panel):
def __init__(self, parent):
super(LoginPanel, self).__init__(parent)
self.SetBackgroundColour((44, 51, 51))
basicLabel = wx.StaticText(self, -1, "Username")
basicLabel.SetForegroundColour((255,255,255))
global basicText
global pwdText
basicText = wx.TextCtrl(self, -1, "", size=(175, -1))
# basicText.SetInsertionPoint(0)
pwdLabel = wx.StaticText(self, -1, "Password")
pwdText = wx.TextCtrl(self, -1, "", size=(175, -1), style=wx.TE_PASSWORD)
#pwdText.Bind(wx.EVT_TEXT_ENTER, self.on_login) # press enter in password field to login
pwdLabel.SetForegroundColour((255, 255, 255))
vbox = wx.BoxSizer(wx.VERTICAL)
hbox = wx.BoxSizer(wx.HORIZONTAL)
vbox.Add(basicLabel, 0, wx.ALIGN_CENTER | 100, 5)
vbox.Add(basicText, 0, wx.ALIGN_CENTER | 100, 5)
vbox.Add(pwdLabel, 0, wx.ALIGN_CENTER | 100, 5)
vbox.Add(pwdText, 0, wx.ALIGN_CENTER | 100, 5)
login_button = wx.Button(self, label='Login')
login_button.Bind(wx.EVT_BUTTON, self.on_login)
help_button = wx.Button(self, label='Help')
help_button.Bind(wx.EVT_BUTTON, self.on_help)
# signup_button = wx.Button(self, label='Sign Up')
hbox.Add(login_button, 0, wx.ALL | 200, 20)
# hbox.Add(signup_button, 0, wx.ALL | 200, 20)
hbox.Add(help_button, 0, wx.ALL | 200, 20)
vbox.Add(hbox, 0, wx.ALIGN_CENTER | 100, 5)
self.SetSizer(vbox)
def on_login(self, event):
# check for login verification
settings["username"] = basicText.GetValue()
settings["password"] = pwdText.GetValue()
settings["login"] = True
#OtherFrame()
def on_help(self, event):
HelpFrame()
# Panel with all the login widgets
class HelpPanel(wx.Panel):
def __init__(self, parent):
super(HelpPanel, self).__init__(parent)
self.SetBackgroundColour((44, 51, 51))
# basicLabel = wx.StaticText(self, -1, "Username")
# basicLabel.SetForegroundColour((255,255,255))
# basicText = wx.TextCtrl(self, -1, "", size=(175, -1))
#
# # basicText.SetInsertionPoint(0)
# pwdLabel = wx.StaticText(self, -1, "Password")
# pwdText = wx.TextCtrl(self, -1, "", size=(175, -1), style=wx.TE_PASSWORD)
# pwdLabel.SetForegroundColour((255, 255, 255))
# vbox = wx.BoxSizer(wx.VERTICAL)
# hbox = wx.BoxSizer(wx.HORIZONTAL)
# vbox.Add(basicLabel, 0, wx.ALIGN_CENTER | 100, 5)
# vbox.Add(basicText, 0, wx.ALIGN_CENTER | 100, 5)
# vbox.Add(pwdLabel, 0, wx.ALIGN_CENTER | 100, 5)
# vbox.Add(pwdText, 0, wx.ALIGN_CENTER | 100, 5)
# login_button = wx.Button(self, label='Login')
# login_button.Bind(wx.EVT_BUTTON, self.on_login)
# help_button = wx.Button(self, label='Help')
# # signup_button = wx.Button(self, label='Sign Up')
# hbox.Add(login_button, 0, wx.ALL | 200, 20)
# # hbox.Add(signup_button, 0, wx.ALL | 200, 20)
# hbox.Add(help_button, 0, wx.ALL | 200, 20)
# vbox.Add(hbox, 0, wx.ALIGN_CENTER | 100, 5)
# self.SetSizer(vbox)
class ServerPanel(wx.Panel):
def __init__(self, parent):
super().__init__(parent, size=(500, 500))
#self.SetBackgroundColour((44, 51, 51))
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
secondary_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.row_obj_dict = {}
self.list_ctrl = wx.ListCtrl(
self, size=(-1, 400),
style=wx.LC_REPORT | wx.BORDER_SUNKEN
)
#tb = wx.ToolBar( self, -1)
#self.ToolBar = tb
#tb.SetToolBitmapSize(wx.Size(30, 3))
#tb.AddTool(wx.ID_ANY, '',wx.Bitmap(find_data_file("WXPython_30x30.png")),)
#tb.AddTool(wx.ID_ANY, '',wx.Bitmap(find_data_file("settings_30x30.png")))
#tb.Realize()
if settings["running"] == True:
txt = "Status: Running (" + str(settings["config"]["core"]["level"]) + ")"
else:
txt = "Status: Not running"
self.statustext = wx.StaticText(self, label=txt) # pos=(20,20))
#self.main_sizer.Add(tb)
#main_sizer.SetBackgroundColour((44, 51, 51))
# self.pnl1.SetBackgroundColour(wx.BLACK)
self.handle_columns()
# self.updatedata()
wx.CallAfter(self.updatedata)
wx.GetApp().ProcessPendingEvents()
self.main_sizer.Add(self.list_ctrl, 0, wx.ALL | wx.EXPAND, 20)
start_button = wx.Button(self, label='Start IPPigeon')
start_button.SetBackgroundColour((205, 215, 206))
start_button.Bind(wx.EVT_BUTTON, self.on_start)
#start_button.Bind(wx.EVT_ENTER_WINDOW, self.on_start)
stop_button = wx.Button(self, label='Stop IPPigeon')
stop_button.SetBackgroundColour('#F08080')
secondary_frame_button = wx.Button(self, label='Settings')
secondary_frame_button.Bind(wx.EVT_BUTTON, self.on_window)
# wx.BORDER(stop_button, wx.BORDER_NONE)
stop_button.Bind(wx.EVT_BUTTON, self.on_stop)
self.main_sizer.Add(self.statustext, 0, wx.CENTER | wx.ALL | 100, 5)
self.main_sizer.Add(start_button, 0, wx.CENTER | wx.ALL | 100, 5)
self.main_sizer.Add(stop_button, 0, wx.CENTER | wx.ALL | 100, 5)
self.main_sizer.Add(secondary_frame_button, 0, wx.CENTER | wx.ALL | 100, 5)
self.SetSizer(self.main_sizer)
def handle_columns(self):
for col in range(len(COLUMN_NAMES)):
self.list_ctrl.InsertColumn(0, COLUMN_NAMES[col], width=COLUMN_SIZES[col])
def updatedata(self):
global settings
if settings["running"] == True:
txt = "Status: Running (" + str(settings["config"]["core"]["level"]) + ")"
else:
txt = "Status: Not running"
if settings["newdata"] == True:
settings["newdata"] = False
else:
wx.CallLater(1000, self.updatedata)
return
fprint("updatedata called")
loaddata()
if self.list_ctrl.DeleteAllItems():
fprint("Items deleted")
else:
fprint("Unable to delete")
for i in range(len(TEST_FILE)):
if str(TEST_FILE.iloc[i, 4]).find("TIME_WAIT") >= 0 or str(TEST_FILE.iloc[i, 4]).find("FIN_WAIT_2") >= 0:
continue
idx = 0
for ip in settings["badips"]:
#fprint(pid)
idx = i
if str(TEST_FILE.iloc[i, 3]).find(ip) >= 0 and str(TEST_FILE.iloc[i, 4]).find("TIME_WAIT") < 0: # "bad" pid, highlight in red at the top
idx = self.list_ctrl.InsertItem(0, TEST_FILE.iloc[i, 0])
self.list_ctrl.SetItemBackgroundColour(idx, wx.Colour(200, 51, 51))
break
else:
idx = self.list_ctrl.InsertItem(i, TEST_FILE.iloc[i, 0])
#fprint(TEST_FILE.iloc[i, 5] + " in " + str(settings["badapps"]))
#if TEST_FILE.iloc[i, 5] in settings["badapps"]:
#fprint("Got " + TEST_FILE.iloc[i, 5])
for j in range(1, 6):
#fprint(str(idx) + " " + str(TEST_FILE.iloc[i, 0]))
self.list_ctrl.SetItem(idx, j, str(TEST_FILE.iloc[i, j]))
#fprint(i, j, TEST_FILE.iloc[i, j])
#self.SetSizer(self.main_sizer)
self.statustext.SetLabel(txt)
wx.CallLater(1000, self.updatedata)
def on_start(self, event):
fprint('in on_start')
settings["running"] = True
# fprint("check if settings[running] is set to true" + str(settings["running"]))
def on_stop(self, event):
fprint('in on_stop')
settings["running"] = False
util.clear_fwll()
def on_window(self, event):
fprint("open settings")
dg = GetData(parent = None)
dg.ShowModal()
def ShowImage(self, imageFile):
if imageFile == "":
self.bitmap = wx.StaticBitmap(self, -1, size=(0, 0))
else:
bmp = wx.Image(imageFile, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
self.bitmap = wx.StaticBitmap(self, -1, bmp, (0, 0))
class ServerFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None,
title='Server Dashboard')
self.panel = LoginPanel(self)
# image = wx.StaticBitmap(self, wx.ID_ANY)
# image.SetBitmap(wx.Bitmap('WXPython.png'))
self.Show()
def openwindow(data, sets, kill):
setup_child()
global killme
global settings
global displaydata
killme = kill
displaydata = data
settings = sets
if settings["loggedin"] == False:
fprint("Creating server panel")
loaddata()
app = wx.App(False)
frame = OtherFrame()
frame.SetIcon(wx.Icon(find_data_file("icon.ico"), wx.BITMAP_TYPE_ICO))
app.MainLoop()
else:
fprint("Creating login panel")
app = wx.App(False)
frame = ServerFrame()
frame.SetIcon(wx.Icon(find_data_file("icon.ico"), wx.BITMAP_TYPE_ICO))
app.MainLoop()
class GetData(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent, wx.ID_ANY, "User Settings: ", size = (800,500))
self.p = wx.Panel(self, wx.ID_ANY)
self.hostname = wx.StaticText(self.p, label="Host:", pos=(20,20))
self.hostnametext = wx.TextCtrl(self.p, value=settings["config"]["sftp"]["host"], pos=(180,20), size=(500,-1))
self.user = wx.StaticText(self.p, label="User: ", pos=(20,60))
self.usertext = wx.TextCtrl(self.p, value=settings["config"]["sftp"]["user"], pos=(180,60), size=(500,-1))
self.port = wx.StaticText(self.p, label="Port: ", pos=(20,100))
self.porttext = wx.TextCtrl(self.p, value=str(settings["config"]["sftp"]["port"]), pos=(180,100), size=(500,-1))
self.keyfile = wx.StaticText(self.p, label="Keyfile: ", pos=(20,140))
self.keyfiletext = wx.TextCtrl(self.p, value=settings["config"]["sftp"]["keyfile"], pos=(180,140), size=(500,-1))
self.filepathsend = wx.StaticText(self.p, label="Sending File Path: ", pos=(20,180))
self.filepathsendtext = wx.TextCtrl(self.p, value=settings["config"]["sftp"]["filepath"]["send"], pos=(180,180), size=(500,-1))
self.filepathsendlogin = wx.StaticText(self.p, label="Sending Login Path: ", pos=(20,220))
self.filepathsendlogintext = wx.TextCtrl(self.p, value=settings["config"]["sftp"]["filepath"]["sendlogin"], pos=(180,220), size=(500,-1))
self.filepathreceive = wx.StaticText(self.p, label="Receiving File Path: ", pos=(20,260))
self.filepathreceivetext = wx.TextCtrl(self.p, value=settings["config"]["sftp"]["filepath"]["receive"], pos=(180,260), size=(500,-1))
self.filepathreceivelogin = wx.StaticText(self.p, label="Receiving Login Path: ", pos=(20,300))
self.filepathreceivelogintext = wx.TextCtrl(self.p, value=settings["config"]["sftp"]["filepath"]["receivelogin"], pos=(180,300), size=(500,-1))
self.darkmode = wx.StaticText(self.p, label="Dark mode (On/Off): ", pos=(20,340))
self.darkmodetext = wx.TextCtrl(self.p, value=str(settings["config"]["ui"]["darkmode"]), pos=(180,340), size=(500,-1))
self.interval = wx.StaticText(self.p, label="Interval (sec): ", pos=(20,380))
self.intervaltext = wx.TextCtrl(self.p, value=str(settings["config"]["core"]["interval"]), pos=(180,380), size=(500,-1))
self.seclevel = wx.StaticText(self.p, label="Security Strength Level: ", pos=(20,420))
self.seclevelslider = wx.Slider(self.p, pos=(180,410), minValue=0, maxValue=3, style=wx.SL_HORIZONTAL | wx.SL_AUTOTICKS, value=settings["config"]["core"]["level"])
self.seclevel2 = wx.StaticText(self.p, label=SEC_LEVELS[settings["config"]["core"]["level"]], pos=(300,420))
self.seclevelslider.Bind(wx.EVT_SCROLL, self.level_upd)
self.Bind(wx.EVT_CLOSE, self.OnQuit)
def level_upd(self, event):
self.seclevel2.SetLabel(SEC_LEVELS[self.seclevelslider.GetValue()])
def OnQuit(self, event):
# save changes
fprint("saving changes...")
config = settings["config"]
config["sftp"]["host"] = self.hostnametext.GetValue()
config["sftp"]["user"] = self.usertext.GetValue()
config["sftp"]["port"] = int(self.porttext.GetValue())
config["sftp"]["keyfile"] = self.keyfiletext.GetValue()
config["sftp"]["filepath"]["send"] = self.filepathsendtext.GetValue()
config["sftp"]["filepath"]["sendlogin"] = self.filepathsendlogintext.GetValue()
config["sftp"]["filepath"]["receive"] = self.filepathreceivetext.GetValue()
config["sftp"]["filepath"]["receivelogin"] = self.filepathreceivelogintext.GetValue()
config["ui"]["darkmode"] = bool(self.darkmodetext.GetValue())
config["core"]["interval"] = int(self.intervaltext.GetValue())
config["core"]["level"] = int(self.seclevelslider.GetValue())
settings["config"] = config
settings["applyconfig"] = True
self.result_name = None
self.Destroy()
def on_edit(self, event):
print('in on_edit')
if __name__ == '__main__':
openwindow(list(), dict(), int())

View File

@ -2,3 +2,7 @@ fabric
paramiko paramiko
wxpython wxpython
cx_Freeze cx_Freeze
pandas
pyyaml
numpy
bcrypt

BIN
settings.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
settings_30x30.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -2,10 +2,10 @@ import sys
from cx_Freeze import setup, Executable from cx_Freeze import setup, Executable
debug = True debug = True
#debug = not debug debug = not debug
# Dependencies are automatically detected, but it might need fine tuning. # Dependencies are automatically detected, but it might need fine tuning.
# "packages": ["os"] is used as example only # "packages": ["os"] is used as example only
build_exe_options = {"packages": ["os"], "excludes": ["tkinter"], "include_msvcr": True, "include_files": ["icon.png", "config.yml", "keyfile-admin.pem"], "optimize": 2} build_exe_options = {"packages": ["os"], "excludes": ["tkinter"], "include_msvcr": True, "include_files": ["icon.png", "config.yml", "keyfile-admin.pem", "WXPython.png", "WXPython_30x30.png", "settings.png", "settings_30x30.png", "icon.ico"], "optimize": 1}
# base="Win32GUI" should be used only for Windows GUI app # base="Win32GUI" should be used only for Windows GUI app
base = None base = None
@ -23,4 +23,4 @@ setup(
description="IP Pigeon client application", description="IP Pigeon client application",
options={"build_exe": build_exe_options}, options={"build_exe": build_exe_options},
executables=[Executable("ippigeon.py", base=base, icon="icon.ico", uac_admin=True, target_name=name)], executables=[Executable("ippigeon.py", base=base, icon="icon.ico", uac_admin=True, target_name=name)],
) )

1
ssh.py
View File

@ -37,3 +37,4 @@ def run_ssh(config, command, location):
fprint("Running ssh command: " + command) fprint("Running ssh command: " + command)
res = c.run(command, hide=True, asynchronous=True) res = c.run(command, hide=True, asynchronous=True)
return res return res

View File

@ -45,8 +45,8 @@ class TaskBarIcon(wx.adv.TaskBarIcon):
fprint ('Tray icon was left-clicked.') fprint ('Tray icon was left-clicked.')
def on_open(self, event): def on_open(self, event):
foreground() settings["showui"] = True
#self.close_popup() self.close_popup()
def on_login(self, event): def on_login(self, event):
settings["username"] = "frontend" settings["username"] = "frontend"
@ -55,10 +55,11 @@ class TaskBarIcon(wx.adv.TaskBarIcon):
def on_exit(self, event): def on_exit(self, event):
wx.CallAfter(self.Destroy) wx.CallAfter(self.Destroy)
self.close_popup()
#print("kill cmd")
global killme global killme
killme.value += 1 killme.value += 1
self.close_popup()
#print("kill cmd")
def close_popup(self): def close_popup(self):
self.frame.Close() self.frame.Close()

18
util.py
View File

@ -4,6 +4,7 @@ import subprocess
import os import os
from sys import platform from sys import platform
import time as t import time as t
from time import sleep
import uuid import uuid
win32 = platform == "win32" win32 = platform == "win32"
@ -25,7 +26,7 @@ if win32:
_, username = res.strip().rsplit("\n", 1) _, username = res.strip().rsplit("\n", 1)
userid, sysdom = username.rsplit("\\", 1) userid, sysdom = username.rsplit("\\", 1)
if linux: if linux or macos:
sysid = hex(uuid.getnode()) sysid = hex(uuid.getnode())
#fprint(sysid) #fprint(sysid)
datafile += sysid datafile += sysid
@ -39,6 +40,13 @@ if linux:
def time(): def time():
return int(t.time()) return int(t.time())
def kill(pid):
setup_child()
if pid > 0:
fprint("Killing PID " + str(pid))
os.kill(int(pid), 9)
fprint("Signal 9 sent to PID " + str(pid))
def fprint(msg): def fprint(msg):
#if not getattr(sys, "frozen", False): #if not getattr(sys, "frozen", False):
setup_child() setup_child()
@ -83,7 +91,7 @@ def run_cmd(cmd):
fprint("ran PS command successfully") fprint("ran PS command successfully")
#completed = subprocess.run(["powershell", "-WindowStyle", "hidden", "-Command", cmd], capture_output=True, startupinfo=startupinfo) #completed = subprocess.run(["powershell", "-WindowStyle", "hidden", "-Command", cmd], capture_output=True, startupinfo=startupinfo)
return completed return completed
if linux: if linux or macos:
fprint("running sh command: " + cmd) fprint("running sh command: " + cmd)
completed = subprocess.run(["sh", "-c", cmd], capture_output=True) completed = subprocess.run(["sh", "-c", cmd], capture_output=True)
fprint("ran sh command successfully") fprint("ran sh command successfully")
@ -109,4 +117,8 @@ class Logger(object):
sleep(0) sleep(0)
def flush(self): def flush(self):
print("", end="") print("", end="")
def clear_fwll():
if win32:
run_cmd('Remove-NetFirewallRule -Group "IPPigeon"')

34
wizard.py Normal file
View File

@ -0,0 +1,34 @@
import wx
from wx.adv import Wizard, WizardPageSimple
class TitlePage(WizardPageSimple):
def __init__(self, parent, title):
WizardPageSimple.__init__(self, parent)
sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(sizer)
title = wx.StaticText(self, wx.ID_ANY, title)
title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
sizer.Add(title, 0, wx.ALIGN_CENTER|wx.ALL, 5)
sizer.Add(wx.StaticLine(self, wx.ID_ANY), 0, wx.EXPAND|wx.ALL, 5)
def main():
wizard = Wizard(None, wx.ID_ANY, "Simple Wizard")
page1 = TitlePage(wizard, "Page 1")
page2 = TitlePage(wizard, "Page 2")
page3 = TitlePage(wizard, "Page 3")
WizardPageSimple.Chain(page1, page2)
WizardPageSimple.Chain(page2, page3)
wizard.FitToPage(page1)
wizard.RunWizard(page1)
wizard.Destroy()
if __name__ == "__main__":
app = wx.App()
main()
app.MainLoop()

111
wizardTutorial.py Normal file
View File

@ -0,0 +1,111 @@
import wx
########################################################################
class WizardPage(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent, title=None):
"""Constructor"""
wx.Panel.__init__(self, parent)
sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(sizer)
if title:
title = wx.StaticText(self, -1, title)
title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
sizer.Add(title, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 5)
########################################################################
class WizardPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent=parent)
self.pages = []
self.page_num = 0
self.mainSizer = wx.BoxSizer(wx.VERTICAL)
self.panelSizer = wx.BoxSizer(wx.VERTICAL)
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
# add prev/next buttons
self.prevBtn = wx.Button(self, label="Previous")
self.prevBtn.Bind(wx.EVT_BUTTON, self.onPrev)
btnSizer.Add(self.prevBtn, 0, wx.ALL|wx.ALIGN_RIGHT, 5)
self.nextBtn = wx.Button(self, label="Next")
self.nextBtn.Bind(wx.EVT_BUTTON, self.onNext)
btnSizer.Add(self.nextBtn, 0, wx.ALL|wx.ALIGN_RIGHT, 5)
# finish layout
self.mainSizer.Add(self.panelSizer, 1, wx.EXPAND)
self.mainSizer.Add(btnSizer, 0, wx.ALIGN_RIGHT)
self.SetSizer(self.mainSizer)
#----------------------------------------------------------------------
def addPage(self, title=None):
""""""
panel = WizardPage(self, title)
self.panelSizer.Add(panel, 2, wx.EXPAND)
self.pages.append(panel)
if len(self.pages) > 1:
# hide all panels after the first one
panel.Hide()
self.Layout()
#----------------------------------------------------------------------
def onNext(self, event):
""""""
pageCount = len(self.pages)
if pageCount-1 != self.page_num:
self.pages[self.page_num].Hide()
self.page_num += 1
self.pages[self.page_num].Show()
self.panelSizer.Layout()
else:
print("End of pages!")
if self.nextBtn.GetLabel() == "Finish":
# close the app
self.GetParent().Close()
if pageCount == self.page_num+1:
# change label
self.nextBtn.SetLabel("Finish")
#----------------------------------------------------------------------
def onPrev(self, event):
""""""
pageCount = len(self.pages)
if self.page_num-1 != -1:
self.pages[self.page_num].Hide()
self.page_num -= 1
self.pages[self.page_num].Show()
self.panelSizer.Layout()
else:
print("You're already on the first page!")
########################################################################
class MainFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="Generic Wizard", size=(800,600))
self.panel = WizardPanel(self)
self.panel.addPage("Page 1")
self.panel.addPage("Page 2")
self.panel.addPage("Page 3")
self.Show()
if __name__ == "__main__":
app = wx.App()
frame = MainFrame()
app.MainLoop()