diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5d72669 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +__pycache__/ +build/ +config.yaml +*.csv +admin-key.ppk +token.txt +*.zip +output.log +output.log diff --git a/WXPython_30x30.png b/WXPython_30x30.png new file mode 100644 index 0000000..8aa648d Binary files /dev/null and b/WXPython_30x30.png differ diff --git a/__pycache__/core.cpython-310.pyc b/__pycache__/core.cpython-310.pyc new file mode 100644 index 0000000..6cf9b68 Binary files /dev/null and b/__pycache__/core.cpython-310.pyc differ diff --git a/auth.py b/auth.py new file mode 100644 index 0000000..ccd4354 --- /dev/null +++ b/auth.py @@ -0,0 +1,43 @@ +import ssh +import csv +from util import fprint +from util import find_data_file +from time import sleep +import bcrypt + +def login(config, user, password, sysid): + fprint("Attempting to login as " + user) + filename = sysid + "login.csv" + + #hashpasswd = bcrypt.hashpw(password.encode('utf-8'), user).decode() + with open(find_data_file(filename), "w", newline="") as f: + writer = csv.writer(f) + writer.writerows([[user,password,sysid],]) + fprint("done creating csv") + #return True + ssh.sftp_send_data(config, filename, 'sendlogin') + command = "python3 login_service.py " + sysid + ssh.run_ssh(config, command, 'scripts') + filename = sysid + "success.txt" + count = 0 + while count < 20: + output = ssh.check_for_file(config, filename, 'receivelogin') + if output == False: + 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: + fprint(type(output)) + if str(output).find("admin") >= 0 or str(output).find("Admin") >= 0: + fprint("Authorized as admin!") + return True + else: + fprint("Not admin") + return False + return False \ No newline at end of file diff --git a/block.py b/block.py new file mode 100644 index 0000000..ac6aebb --- /dev/null +++ b/block.py @@ -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 diff --git a/config.yml b/config.yml new file mode 100644 index 0000000..62fb355 --- /dev/null +++ b/config.yml @@ -0,0 +1,19 @@ +core: + autostart: false + clockspeed: 20 + interval: 10 + level: 3 + localadmin: true +sftp: + filepath: + receive: /home/ec2-user/Outgoing/Outgoing_Data + receivelogin: /home/ec2-user/Outgoing/Login + 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: + darkmode: true diff --git a/icon.ico b/icon.ico new file mode 100644 index 0000000..6d691a5 Binary files /dev/null and b/icon.ico differ diff --git a/icon.png b/icon.png new file mode 100644 index 0000000..edb3388 Binary files /dev/null and b/icon.png differ diff --git a/ippigeon.py b/ippigeon.py new file mode 100644 index 0000000..1314a56 --- /dev/null +++ b/ippigeon.py @@ -0,0 +1,292 @@ +import os +import sys +import subprocess +from multiprocessing import Process, Manager, Pool, TimeoutError, freeze_support, active_children +from sys import platform +from time import sleep +import uuid +import yaml +from util import find_data_file +from util import fprint +from util import kill +from util import run_cmd +import taskbartool +import util +import netstat +import ssh +import auth +import panel +import block + +badapps = [756, 278670] +badips = ["208.59.79.12",] +displaydata = None +settings = None +netdata_res = None +procdata_res = None +killme = None +ppanel = None +datafile = "" +#print(datafile) +config = None +interval = 10 +win32 = platform == "win32" +linux = platform == "linux" or platform == "linux2" +macos = platform == "darwin" +# Get unique system values +if win32: + sysid = hex(uuid.getnode()) + datafile += sysid + datafile += "gendata.csv" + # Python is running as Administrator (so netstat can get filename, to block, etc), + # so we use this to see who is actually logged in + # it's very hacky + startupinfo = subprocess.STARTUPINFO() + #if not getattr(sys, "frozen", False): + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW # hide powershell window + res = subprocess.check_output(["WMIC", "ComputerSystem", "GET", "UserName"], universal_newlines=True, startupinfo=startupinfo) + _, username = res.strip().rsplit("\n", 1) + userid, sysdom = username.rsplit("\\", 1) + +if linux: + sysid = hex(uuid.getnode()) + #fprint(sysid) + datafile += sysid + datafile += "gendata.csv" + res = subprocess.check_output(["who",], universal_newlines=True) + userid = res.strip().split(" ")[0] + sysdom = subprocess.check_output(["hostname",], universal_newlines=True).strip() + #fprint(hostname) + +def netstat_done(res): + fprint("netstat done, processing") + procdata_res = pool.apply_async(netstat.process, (res,), callback=process_done) + #netstat.process(res) + +def process_done(res): + if settings["running"] == True: + 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): + if not res: + fprint("Login failure") + settings["message"] = "Login failure" + else: + 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(): + kids = active_children() + for kid in kids: + kid.kill() + fprint("Every child has been killed") + os.kill(os.getpid(), 9) # dirty kill of self + + + +def mainloop(pool): + # worker pool: netstat, netstat cleanup, upload, download, ui tasks + global config + global counter + global netdata_res + global procdata_res + global rawdata + global killme + global ppanel + #print(killme) + if killme.value > 0: + #print("killing") + killall() + #print(res.get(timeout=1)) + if counter == 0: # runs every INTERVAL + #fprint("start loop") + if netdata_res is None or netdata_res.ready(): + #rawdata = netdata_res.get() + #procdata_res = pool.apply_async(process_netstat, (rawdata)) + fprint("netstat starting") + netdata_res = pool.apply_async(netstat.start, callback=netstat_done) + #fprint(netdata_res.successful()) + + # 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: + 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)) + 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 + + 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 + if counter == interval * config["core"]["clockspeed"]: + counter = 0 + + +class Logger(object): + def __init__(self, filename="output.log"): + self.log = open(filename, "a") + self.terminal = sys.stdout + + def write(self, message): + self.log.write(message) + #close(filename) + #self.log = open(filename, "a") + try: + self.terminal.write(message) + except: + sleep(0) + + def flush(self): + print("",end="") + +if __name__ == '__main__': + freeze_support() # required if packaged into single EXE + # create manager to share data to me, background, foreground + # create worker pool + + sys.stdout = 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 open(find_data_file('config.yml'), 'r') as fileread: + #global config + config = yaml.safe_load(fileread) + #print(config['sftp']['host']) + interval = config['core']['interval'] + displaydata = manager.list(range(2)) # data to be printed + settings = manager.dict() # configuration + settings["login"] = 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 = False + # launch background UI app as process + util.clear_fwll() + p = Process(target=taskbartool.background, args=(displaydata,settings,killme)) + p.start() + #p.join() # not a foreground job, so let's not join it + keeprunning = True + + # initial setup + #netdata_res = pool.apply_async(netstat, callback=netstat_done) + + + # launch loop - non-blocking! + counter = 0 + while(keeprunning): + mainloop(pool) \ No newline at end of file diff --git a/keyfile-admin.pem b/keyfile-admin.pem new file mode 100755 index 0000000..6fb5cb6 --- /dev/null +++ b/keyfile-admin.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAkKf5kPTTHIvL44Tfe7QO13K/JVfD+DbIwWQBURqa60ohVldN +mWg7dngpMeHcr27JXLHfAT1c2ztbZR13ZZzKTpu1IbUtecVhCsduNtMzLehB8seQ +0lPLAUeE76IK7KfYBUXNXnA5n9oFTS2DJwnYgSqAODbILOxbUpdRajTbacE3Mo0p +nMLwvqcCwXXfKEhlcccclckDKkZYpwLfmuw7veD007NlBfq/lOezdFBERezEUIgr ++A22JP5KCsVeuQBJuuRrXdz8p334n2xaR4RDjN3p0cmMi2Oohm7M7MbhAImC/J+P +HXOJMQpdEgD6Ea17Jr9ORPf08HrrjaZzA/SW7QIDAQABAoIBAEe07LKdmjTxW42a +JUpl9GF6gSRawEs/pP6wuzJgFOGD6sipGE9uauOMJyeSBdp0+Z5YkepEZ85JO0IB +fFlDgsm6x+xAqp1NaZB1Ub4draYZFu/pW3HXla85q706P14Wya+7bVVeHkKOSch7 +QiNM7yUAU3UKOuqB87caSYJzVzyxhUd5S6/ro2VNbXT/7vHSsKCja2scy+JaRhKn +m4cc3P+ggI06JLfZsMZY1zJKDhbWiHGmB5ZdzqAJsu/bAtXWY25QsHowYAqPG7Uq +7rcJlbbdkCASE4MXqi427uJfeqBB0vfykttSriBpQVBKus5wpcCEOMkpEho0zU0Z +yx9bdeECgYEA9d0PDjAqIwrVSxjeOd6eXcSwmMzaK5fc5beptKRQA0U/O4swhn2+ +NOio6v6fTWuDwNHAsMZiDvW3boO357GCm2N7YkqvdarydfOt7IccsUnEROaAxOqx +1wlnl0NkVIwaTo3XoRSWIcIqE3mCAaz8peqtRmIcXcQ/S9RGm3QeiAUCgYEAlp67 +vmn6Z1U0XLILnf4i9D3ECJlwJXEP64pB4XnXiHU/StaXY7CSRaCX+SxfgUR8pATQ +ySYDRY1Ag6cHxSVIo1vkotT3P11x7/8yWnomvnEwRJqTMdN+/VuTi4tPzU1ScNXX +F7aRqkNoGEkmsmi2wdszbJcruI74k4TGLcbNj8kCgYEAgG37AVRTjn6IMHRLETui +yiSGgyrvBDqN30lzUrNKQIsZnsb0kCx7ATRPmIFtQYnaBw0KdM0MR/g+23HezR7C +tNzghNWyleq4QLkLrzRc3pdD+SHXPgXC5Cs7e55ueGO/Ei2x56jTS8sbI5UjPjDY +wOq3nL5/RtPOpJO8VlPv5ukCgYEAjytM/D9SdNyJzD61SjWiVhVL/HyVHBHvdw3R +d5jQZfZE9kcqWekh8KspKgGiuoY2D9Y/+6N1YqxUkY+4lA3PkPAtURYr+wBA6Ebk +PxpzL3z5y4w+tBL8V6mvguomLdj8ryKktPamWXh/Pu5xqQ5eAcDxjZvYRDMqV1bS +5fpdtPkCgYEAoRVdlDSaj9u3NPoFkschl1bOZlJpm9tJVU+LoWxRe8tuLIwVDvXP +JsZMcpfinEPWSrJN+hlGDuaq7k5LtSNeQoruaafhlE+CV54G7J2Khn8pRKWT+n/p +36PfgGbhuLsZl8KDy+PXjS+L5A1kuTxB4rOBdHXIHm60aNCqB0BRcTM= +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/known_hosts b/known_hosts new file mode 100644 index 0000000..a379106 --- /dev/null +++ b/known_hosts @@ -0,0 +1 @@ +ec2-34-232-29-46.compute-1.amazonaws.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBM8sLlu0mu1PqYXk+a9XYHXXFiOaxk/2tIS5O3q+3ah13bd5Iz+NSxS0bXT7TdMTA/lD1kWMUXROEauADgIfT98= diff --git a/netstat.py b/netstat.py new file mode 100644 index 0000000..b13220e --- /dev/null +++ b/netstat.py @@ -0,0 +1,125 @@ +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 +import util +import time +import csv + + + +def process(data): + setup_child() + fprint("netstat processing") + if win32: + #output = data.stdout + #print(output) + output = data.stdout.decode().split('\r\n') # split stdout into lines + #print(output) + if output[0].find("The requested operation requires elevation.") >= 0: + #print("test3") + raise PermissionError("Unable to acquire netstat data without admin!") + #print("test2") + output2 = list() + output2.append([util.sysid, util.userid, util.sysdom, util.time()]) # add metadata + #print(output2) + procname = "" + """for x in range(4, len(output)): + tmp = output[x].split(" ") + print(tmp) + tmp = [i for i in output[x] if i] + print(tmp) + print(len(tmp)) + if len(len(tmp) == 1): + procname = tmp[0] + print(x) + else: + print(x) + output2[x] = list() + output2[x].append(procname) + output2[x].append(output[x].split(" ")) + output2[x] = [i for i in output2[x] if i] + output2 = [i for i in output2 if i] + print(output2)""" + x = len(output) - 1 # start at the end because filename comes after connection + procname = "Unknown" # if the very last connection happens to have no file (yes, it's possible), we can say unknown + while x > 3: + string = output[x] + #print("LINE: ", string) + string_split = string.split(" ") + string_split = [i for i in string_split if i] + if string.find("Can not obtain ownership information") >= 0: # Higher privilige than us, must be system + procname = "Windows System" + elif string.find("]") >= 0 and string.find("[") == 1: # generic [file.exe] + procname = string[2:-1] + elif len(string_split) == 5: # actual netstat line + tmp = [procname,] # add executable name first + tmp.extend(string.split(" ")) + tmp = [i for i in tmp if i] + #print(tmp) + output2.append(tmp) + #else: # In case of an extra line above file, or an empty line, ignore it + #print("Garbage data", string) + x = x - 1 + #output2 = output2[2:] + #print(output2) + with open(find_data_file(util.datafile), "w", newline="") as f: + writer = csv.writer(f) + writer.writerows(output2) + fprint("done creating csv") + + if linux: + output = data.stdout.decode().split('\n') # split stdout into lines + output = [i for i in output if i] + if output[0].find("Not all processes could be identified") >= 0: + fprint("Not enough permissions") + raise PermissionError("Unable to acquire netstat data without admin!") + output2 = list() + output2.append([util.sysid, util.userid, util.sysdom, util.time()]) # add metadata + for line in output: + string_split = line.split(" ") + string_split = [i for i in string_split if i] + #fprint("Input: " + str(string_split)) + + if string_split[0].find("Active") >= 0 or string_split[0].find("Proto") >= 0: + continue + + if len(string_split) == 6: # no connection status + #fprint(string_split) + string_split.append(string_split[-1]) + string_split[-2] = "UNKNOWN" + #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]) + #fprint(output2) + + with open(find_data_file(util.datafile), "w", newline="") as f: + writer = csv.writer(f) + writer.writerows(output2) + fprint("done creating csv") + + +def start(): + setup_child() + fprint("netstat started") + + if win32: + data = run_cmd("netstat -n -o -b") + fprint("data acquired") + return data + + if linux: + data = run_cmd("netstat -atunpw") + fprint("data acquired") + return data + diff --git a/panel.py b/panel.py new file mode 100644 index 0000000..cb5dfbc --- /dev/null +++ b/panel.py @@ -0,0 +1,364 @@ +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 + + 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"]: + 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()) \ No newline at end of file diff --git a/release.sh b/release.sh new file mode 100644 index 0000000..adc249c --- /dev/null +++ b/release.sh @@ -0,0 +1,57 @@ +#!/bin/bash +#set -x + +TOKEN=$(< token.txt) +EDITOR=nano git commit -a +git push + +COMMIT=$(git log | head -n 1 | cut -d' ' -f2) +echo $COMMIT +export PATH=$PATH:"C:\Program Files\7-Zip" +TAG=$(date +%s) +"C:/Program Files/Python310/python.exe" setup.py build +sleep 2 +mv ./build/exe.win-amd64-3.10/ ./build/ippigeon-win +7z a -r release-$COMMIT.zip ./build/ippigeon-win +7z a -sfx7z.sfx IPPigeon-install.exe ./build/ippigeon-win +mv ./build/ippigeon-win/ ./build/exe.win-amd64-3.10 +#sleep 30 +DATA='{ + "body": "Autogenerated release", + "draft": false, + "name": "Development release", + "prerelease": true, + "tag_name": "'$TAG'", + "target_commitish": "'$COMMIT'" +}' +OUT=$(curl -X 'POST' \ + 'https://git.deck.sh/api/v1/repos/Interfaz/ff/releases?token='$TOKEN'' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d "$DATA") + +ID=$(echo $OUT | cut -d',' -f 1 | cut -d':' -f 2) + +OUT=$(curl -X 'POST' \ + 'https://git.deck.sh/api/v1/repos/Interfaz/ff/releases/'$ID'/assets?token='$TOKEN'' \ + -H 'accept: application/json' \ + -H 'Content-Type: multipart/form-data' \ + -F 'attachment=@IPPigeon-install.exe;type=application/octet-stream') + +URL=$(echo $OUT | cut -d',' -f 7 | cut -d\" -f4) + + + +OUT=$(curl -X 'POST' \ + 'https://git.deck.sh/api/v1/repos/Interfaz/ff/releases/'$ID'/assets?token='$TOKEN'' \ + -H 'accept: application/json' \ + -H 'Content-Type: multipart/form-data' \ + -F 'attachment=@'release-$COMMIT.zip';type=application/x-zip-compressed') + +URLZIP=$(echo $OUT | cut -d',' -f 7 | cut -d\" -f4) +curl -d "Self extracting installer: $URL + +Portable Zip: $URLZIP" https://notify.deck.sh/ipro-release + +rm release-$COMMIT.zip +rm IPPigeon-install.exe \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..8f85568 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,8 @@ +fabric +paramiko +wxpython +cx_Freeze +pandas +pyyaml +numpy +bcrypt \ No newline at end of file diff --git a/run.sh b/run.sh new file mode 100644 index 0000000..2f005db --- /dev/null +++ b/run.sh @@ -0,0 +1,2 @@ +"C:/Program Files/Python310/python.exe" setup.py build + diff --git a/settings_30x30.png b/settings_30x30.png new file mode 100644 index 0000000..75f60dd Binary files /dev/null and b/settings_30x30.png differ diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..d33e010 --- /dev/null +++ b/setup.py @@ -0,0 +1,26 @@ +import sys +from cx_Freeze import setup, Executable + +debug = True +debug = not debug +# Dependencies are automatically detected, but it might need fine tuning. +# "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", "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 = None +if sys.platform == "win32" and not debug: + base = "Win32GUI" + +if sys.platform == "linux" or sys.platform == "linux2" or sys.platform == "darwin": + name = "IPPigeon" +else: + name = "IPPigeon.exe" + +setup( + name="IP Pigeon", + version="0.2.4", + description="IP Pigeon client application", + options={"build_exe": build_exe_options}, + executables=[Executable("ippigeon.py", base=base, icon="icon.ico", uac_admin=True, target_name=name)], +) diff --git a/ssh.py b/ssh.py new file mode 100644 index 0000000..09a78e3 --- /dev/null +++ b/ssh.py @@ -0,0 +1,40 @@ +#from __future__ import with_statement +from fabric import Connection +from util import find_data_file +from util import setup_child +from util import fprint +from invoke import exceptions +import sys + +def sftp_send_data(config, filename, filetype): + setup_child() + fprint("Connecting over SSH to " + config['sftp']['host']) + c = Connection(host=config['sftp']['host'], user=config['sftp']['user'], port=config['sftp']['port'], connect_kwargs={"key_filename": find_data_file(config['sftp']['keyfile']),}) + fprint("Sending data over SFTP: " + filename) + fprint(c.put(find_data_file(filename), remote=config['sftp']['filepath'][filetype])) + fprint("Data sent over SFTP successfully") + #command = 'ls ' + config['sftp']['filepath'][filetype] + #fprint(c.run(command)) + +def check_for_file(config, filename, location): + setup_child() + fprint("Connecting over SSH to " + config['sftp']['host']) + c = Connection(host=config['sftp']['host'], user=config['sftp']['user'], port=config['sftp']['port'], connect_kwargs={"key_filename": find_data_file(config['sftp']['keyfile']),}) + fprint("Checking for existence of file " + config['sftp']['filepath'][location] + "/" + filename) + try: + res = c.run("ls -l " + config['sftp']['filepath'][location] + "/" + filename, hide=True) + fprint("File " + filename + " exists!") + return c.run("cat " + config['sftp']['filepath'][location] + "/" + filename, hide=True) + except exceptions.UnexpectedExit: + return False + +def run_ssh(config, command, location): + setup_child() + fprint("Connecting over SSH to " + config['sftp']['host']) + c = Connection(host=config['sftp']['host'], user=config['sftp']['user'], port=config['sftp']['port'], connect_kwargs={"key_filename": find_data_file(config['sftp']['keyfile']),}) + fprint("cd to " + config['sftp']['filepath'][location]) + with c.cd(config['sftp']['filepath'][location]): + fprint("Running ssh command: " + command) + res = c.run(command, hide=True, asynchronous=True) + return res + diff --git a/taskbartool.py b/taskbartool.py new file mode 100644 index 0000000..54b7278 --- /dev/null +++ b/taskbartool.py @@ -0,0 +1,90 @@ +import glob +import wx +import wx.adv +import os +from time import sleep +from sys import platform +import sys +from util import find_data_file +from util import fprint +from util import setup_child + +TRAY_TOOLTIP = 'IP Pigeon' + +displaydata = None +settings = None + +killme = False + +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) + #create_menu_item(menu, 'Login test', self.on_login) + 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): + fprint ('Tray icon was left-clicked.') + + def on_open(self, event): + settings["showui"] = True + self.close_popup() + + def on_login(self, event): + settings["username"] = "frontend" + settings["password"] = "qwertyuiop" + settings["login"] = True + + def on_exit(self, event): + wx.CallAfter(self.Destroy) + global killme + killme.value += 1 + self.close_popup() + #print("kill cmd") + + + 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 + +def background(data, sets, kill): + setup_child() + global killme + global settings + global displaydata + killme = kill + app = TaskbarApp(False) + displaydata = data + settings = sets + fprint("Creating taskbar icon") + app.MainLoop() + +TRAY_ICON = find_data_file('icon.png') + +if __name__ == "__main__": + background(list(), dict(), int()) \ No newline at end of file diff --git a/taskbartool2.py b/taskbartool2.py new file mode 100644 index 0000000..3baf66d --- /dev/null +++ b/taskbartool2.py @@ -0,0 +1,94 @@ +#!/usr/bin/env pythonw + +import wx +import wx.adv +import wx.lib.embeddedimage + +WXPdemo = wx.lib.embeddedimage.PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAWlJ" + "REFUWIW1V1sSwjAIBMebeBU9db2KZ8EPmxbCI4TUnXGskWaXDQktwhjErjERP4XRhER08iPi" + "5SKiyQR5JyI7xxB3j7wn5GI6V2hFxM0gJtjYANFBiIjQu7L/1lYlwR0QxLDZhE0II1+CtwRC" + "RI8riBva7DL7CC9VAwDbbxwKtdDXwBi7K+1zCP99T1vDFedd8FBwYd6BCAUXuACEF7QsbET/" + "FaHs+gDQw4vOLNHkMojAnTw8nlNipIiwmR0DCXJbjCXkFCAL23BnpQgRWt1EMbyujCK9AZzZ" + "f+b3sX0oSqJQ6EorFeT4NiL6Wtj0+LXnQAzThYoAAsN6ehqR3sHExmcEqGeFApQLcTvm5Kt9" + "wkHGgb+RZwSkyc1dwOcpCtCoNKSz6FRCUQ3o7Nn+5Y+Lg+y5CIXlcyAk99ziiQS32+svz/UY" + "vClJoLpIC8gi+VwwfDecEiEtT/WZTJDf94uk1Ru8vbz0cvoF7S2DnpeVL9UAAAAASUVORK5C" + "YII=") + +class DemoTaskBarIcon(wx.adv.TaskBarIcon): + TBMENU_RESTORE = wx.NewId() + TBMENU_CLOSE = wx.NewId() + TBMENU_CHANGE = wx.NewId() + TBMENU_REMOVE = wx.NewId() + + def __init__(self, frame): + wx.adv.TaskBarIcon.__init__(self) + self.frame = frame + + # Set the image + icon = self.MakeIcon(WXPdemo.GetImage()) + self.SetIcon(icon, "wxPython Demo") + self.imgidx = 1 + + # bind some events + self.Bind(wx.adv.EVT_TASKBAR_LEFT_DCLICK, self.OnTaskBarActivate) + self.Bind(wx.EVT_MENU, self.OnTaskBarActivate, id=self.TBMENU_RESTORE) + self.Bind(wx.EVT_MENU, self.OnTaskBarClose, id=self.TBMENU_CLOSE) + + + def CreatePopupMenu(self): + """ + This method is called by the base class when it needs to popup + the menu for the default EVT_RIGHT_DOWN event. Just create + the menu how you want it and return it from this function, + the base class takes care of the rest. + """ + menu = wx.Menu() + menu.Append(self.TBMENU_RESTORE, "Restore wxPython Demo") + menu.Append(self.TBMENU_CLOSE, "Close wxPython Demo") + return menu + + + def MakeIcon(self, img): + """ + The various platforms have different requirements for the + icon size... + """ + if "wxMSW" in wx.PlatformInfo: + img = img.Scale(16, 16) + elif "wxGTK" in wx.PlatformInfo: + img = img.Scale(22, 22) + # wxMac can be any size upto 128x128, so leave the source img alone.... + icon = wx.Icon("icon.png") + #self.SetIcon(icon, TRAY_TOOLTIP) + return icon + + + def OnTaskBarActivate(self, evt): + if self.frame.IsIconized(): + self.frame.Iconize(False) + if not self.frame.IsShown(): + self.frame.Show(True) + self.frame.Raise() + + + def OnTaskBarClose(self, evt): + wx.CallAfter(self.frame.Close) + + + +class MainFrame(wx.Frame): + def __init__(self, parent): + wx.Frame.__init__(self, parent, title="Hello World") + self.tbicon = DemoTaskBarIcon(self) + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + + def OnCloseWindow(self, evt): + self.tbicon.Destroy() + evt.Skip() + + +app = wx.App(redirect=False) +frame = MainFrame(None) +frame.Show(True) +app.MainLoop() \ No newline at end of file diff --git a/util.py b/util.py new file mode 100644 index 0000000..d5a992b --- /dev/null +++ b/util.py @@ -0,0 +1,124 @@ +import inspect +import sys +import subprocess +import os +from sys import platform +import time as t +from time import sleep +import uuid + +win32 = platform == "win32" +linux = platform == "linux" or platform == "linux2" +macos = platform == "darwin" +datafile = "" + +if win32: + sysid = hex(uuid.getnode()) + datafile += sysid + datafile += "gendata.csv" + # Python is running as Administrator (so netstat can get filename, to block, etc), + # so we use this to see who is actually logged in + # it's very hacky + startupinfo = subprocess.STARTUPINFO() + #if not getattr(sys, "frozen", False): + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW # hide powershell window + res = subprocess.check_output(["WMIC", "ComputerSystem", "GET", "UserName"], universal_newlines=True, startupinfo=startupinfo) + _, username = res.strip().rsplit("\n", 1) + userid, sysdom = username.rsplit("\\", 1) + +if linux: + sysid = hex(uuid.getnode()) + #fprint(sysid) + datafile += sysid + datafile += "gendata.csv" + res = subprocess.check_output(["who",], universal_newlines=True) + userid = res.strip().split(" ")[0] + sysdom = subprocess.check_output(["hostname",], universal_newlines=True).strip() + #fprint(sysdom) + #fprint("d") + +def 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): + #if not getattr(sys, "frozen", False): + setup_child() + try: + frm = inspect.stack()[1] + + mod = inspect.getmodule(frm[0]) + print('[' + mod.__name__ + ":" + frm.function + ']:', str(msg)) + except Exception as e: + try: + print('[????:' + frm.function + ']:', str(msg)) + except: + print('[????]:', str(msg)) + + + # else: + #print(msg) + +def find_data_file(filename): + if getattr(sys, "frozen", False): + # The application is frozen + datadir = os.path.dirname(sys.executable) + else: + # The application is not frozen + # Change this bit to match where you store your data files: + datadir = os.path.dirname(__file__) + return os.path.join(datadir, filename) + +def run_cmd(cmd): + if win32: + startupinfo = subprocess.STARTUPINFO() + #print("DICKS") + #if not getattr(sys, "frozen", False): + # print("test") + # + #completed = subprocess.run(["powershell", "-Command", cmd], capture_output=True, startupinfo=startupinfo) + #else: + # print("alt") + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW # , "-WindowStyle", "hidden" + fprint("running PS command: " + cmd) + completed = subprocess.run(["powershell", "-Command", cmd], capture_output=True, startupinfo=startupinfo) + fprint("ran PS command successfully") + #completed = subprocess.run(["powershell", "-WindowStyle", "hidden", "-Command", cmd], capture_output=True, startupinfo=startupinfo) + return completed + if linux: + fprint("running sh command: " + cmd) + completed = subprocess.run(["sh", "-c", cmd], capture_output=True) + fprint("ran sh command successfully") + return completed + +def setup_child(): + if not getattr(sys, "frozen", False): + sys.stdout = Logger(filename=find_data_file("output.log")) + sys.stderr = Logger(filename=find_data_file("output.log")) + +class Logger(object): + def __init__(self, filename="output.log"): + self.log = open(filename, "a") + self.terminal = sys.stdout + + def write(self, message): + self.log.write(message) + #close(filename) + #self.log = open(filename, "a") + try: + self.terminal.write(message) + except: + sleep(0) + + def flush(self): + print("", end="") + +def clear_fwll(): + if win32: + run_cmd('Remove-NetFirewallRule -Group "IPPigeon"')