macBank/app.py

424 lines
15 KiB
Python

from io import open
from time import sleep
import os.path
import urllib.request
import sqlite3
import parser
import re
import gi
from gi.repository import Gtk, Gdk, GLib
gi.require_version('Gtk', '3.0')
class AppWindow(Gtk.ApplicationWindow):
mode = "OUI"
repeatFactor = "1"
isValid = False
result = ""
UI_INFO = """
<ui>
<menubar name='MenuBar'>
<menu action='FileMenu'>
<menu action='Database'>
<menuitem action='Update' />
</menu>
<separator />
<menuitem action='FileQuit' />
</menu>
<menu action='HelpMenu'>
<menuitem action='? help' />
<menuitem action='About' />
</menu>
</menubar>
</ui>
"""
def __init__(self):
Gtk.Window.__init__(self, title=parser.manifest("name"))
self.set_default_size(300, 200)
# --- menu --- #
self.action_group = Gtk.ActionGroup("my_actions")
self.add_file_menu_actions(self.action_group)
self.add_help_menu_actions(self.action_group)
self.uimanager = self.create_ui_manager()
self.uimanager.insert_action_group(self.action_group)
self.menubar = self.uimanager.get_widget("/MenuBar")
self.menuBox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=50)
self.menuBox.pack_start(self.menubar, False, False, 0)
# --- Label --- #
self.label = Gtk.Label()
self.label.set_text("Enter any MAC address, OUI, or IAB:")
self.label.set_justify(Gtk.Justification.LEFT)
self.label.set_hexpand(True)
# --- Result Treeview --- #
self.history = Gtk.ListStore(str, str)
self.treeview = Gtk.TreeView(model=self.history)
self.renderer_mac = Gtk.CellRendererText()
self.mac_column = Gtk.TreeViewColumn("MAC/OUI", self.renderer_mac, text=0)
self.treeview.append_column(self.mac_column)
self.renderer_vendor = Gtk.CellRendererText()
self.renderer_vendor.set_property("editable", False)
self.vendor_column = Gtk.TreeViewColumn("Vendor", self.renderer_vendor, text=1)
self.treeview.append_column(self.vendor_column)
self.treeview.set_margin_start(10)
self.treeview.set_margin_end(10)
self.treeview.set_margin_bottom(10)
# --- Entry --- #
self.entry = Gtk.Entry()
self.entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, "edit-clear")
self.entry.set_max_length(8)
self.entry.set_placeholder_text("00:00:00")
self.entry.connect("key-release-event", self.on_key_release)
self.entry.connect("icon-press", self.entry_icon_event)
self.entry.set_margin_start(10)
self.entry.set_margin_end(10)
# --- Radio buttons --- #
self.box = Gtk.Box(spacing=10)
self.radioButton1 = Gtk.RadioButton.new_with_label_from_widget(None, "OUI")
self.radioButton1.connect("toggled", self.on_button_toggled, "OUI")
self.box.pack_start(self.radioButton1, False, False, 0)
self.box.set_margin_start(10)
self.box.set_margin_end(10)
self.radioButton2 = Gtk.RadioButton.new_from_widget(self.radioButton1)
self.radioButton2.set_label("MAC")
self.radioButton2.connect("toggled", self.on_button_toggled, "MAC")
self.box.pack_start(self.radioButton2, False, False, 0)
# --- Buttons --- #
self.search_button = Gtk.Button(label="Search")
self.search_button.connect("clicked", self.on_search_clicked)
self.search_button.set_margin_start(10)
self.search_button.set_margin_end(10)
# --- ProgressBar --- #
self.progressbar = Gtk.ProgressBar()
# --- Grid --- #
self.grid = Gtk.Grid()
self.grid.set_row_spacing(5)
self.grid.add(self.menuBox)
self.grid.attach(self.label, 0, 2, 1, 1)
self.grid.attach_next_to(self.entry, self.label, Gtk.PositionType.BOTTOM, 1, 1)
self.grid.attach_next_to(self.box, self.entry, Gtk.PositionType.BOTTOM, 1, 1)
self.grid.attach_next_to(self.search_button, self.box, Gtk.PositionType.BOTTOM, 1, 1)
self.grid.attach_next_to(self.treeview, self.search_button, Gtk.PositionType.BOTTOM, 1, 1)
self.grid.attach_next_to(self.progressbar, self.treeview, Gtk.PositionType.BOTTOM, 1, 1)
self.add(self.grid)
def on_key_release(self, widget, event):
self.colon = False
print(event.keyval)
keyname = Gdk.keyval_name(event.keyval)
print(keyname)
if len(self.entry.get_text()) == 2:
self.entry.set_text(self.entry.get_text() + ":")
self.colon = True
self.entry.set_position(-1)
elif len(self.entry.get_text()) == 5:
self.entry.set_text(self.entry.get_text() + ":")
self.colon = True
self.entry.set_position(-1)
elif len(self.entry.get_text()) == 8 and (self.mode == "MAC"):
self.entry.set_text(self.entry.get_text() + ":")
self.colon = True
self.entry.set_position(-1)
elif len(self.entry.get_text()) == 11 and (self.mode == "MAC"):
self.entry.set_text(self.entry.get_text() + ":")
self.colon = True
self.entry.set_position(-1)
elif len(self.entry.get_text()) == 14 and (self.mode == "MAC"):
self.entry.set_text(self.entry.get_text() + ":")
self.colon = True
self.entry.set_position(-1)
if ((keyname == 'BackSpace') or (event.keyval == 65288)) and self.colon:
self.entry.set_text(self.entry.get_text()[:-2])
self.entry.set_position(-1)
for i in range(len(self.entry.get_text())):
self.check_mac(self.entry.get_text())
def check_mac(self, mac):
if re.match("[0-9a-f]{2}([-:]?)[0-9a-f]{2}(\\1[0-9a-f]{2}){" + self.repeatFactor + "}$", mac.lower()):
self.entry.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("green"))
self.isValid = True
else:
self.entry.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse(""))
self.isValid = False
def entry_icon_event(self, widget, icon, event):
self.entry.set_text("")
def on_search_clicked(self, widget):
if self.isValid:
if self.entry.get_text().find('-') != -1:
self.search = self.entry.get_text().replace('-', ':')
else:
self.search = self.entry.get_text()
self.dbCursor.execute("SELECT * FROM data WHERE mac=?", (self.search.upper(),))
self.rows = self.dbCursor.fetchall()
if self.rows:
for row in self.rows:
print(row)
self.result = row
else:
if self.mode == "MAC":
self.search = self.search[:8]
self.dbCursor.execute("SELECT * FROM data WHERE mac=?", (self.search.upper(),))
self.rows = self.dbCursor.fetchall()
if self.rows:
for row in self.rows:
print(row)
self.result = row
else:
self.result = (self.search.upper(), 'Sorry, No results found!')
print(self.result)
else:
self.result = (self.search.upper(), 'Sorry, No results found!')
print(self.result)
self.history.append(self.result)
print(self.history)
def on_button_toggled(self, button, name):
if button.get_active():
self.mode = name
if self.mode == "OUI":
self.entry.set_max_length(8)
self.entry.set_placeholder_text("00:00:00")
self.repeatFactor = "1"
self.check_mac(self.entry.get_text())
else:
self.entry.set_max_length(17)
self.entry.set_placeholder_text("00:00:00:00:00:00")
self.repeatFactor = "4"
self.check_mac(self.entry.get_text())
if (len(self.entry.get_text()) == 8) and (self.mode == "MAC"):
if self.entry.get_text().find('-') != -1:
self.search = self.entry.get_text().replace('-', ':')
else:
self.search = self.entry.get_text()
self.entry.set_text(self.search + ":")
self.colon = True
self.entry.set_position(-1)
print("Search mode: ", self.mode)
print("Repeat: ", self.repeatFactor)
def file_check(self):
if not os.path.exists('source.txt'):
print("file does not exist")
download = self.on_update_clicked(self)
if download:
self.save_data()
else:
print(download)
else:
return True
def db_connect(self):
# database connection
self.dbConnection = sqlite3.connect("macDB")
self.dbCursor = self.dbConnection.cursor()
self.dbCursor.execute("CREATE TABLE IF NOT EXISTS data(mac VARCHAR(20), vendor VARCHAR(50), UNIQUE('mac'))")
def save_data(self):
# read source file using "r"(read) parameter
source_file = open("source.txt", "r")
line = source_file.readlines()
source_file.close()
data = []
for i in range(len(line)):
try:
if(line[i][0] != "#") and (line[i][0] != "\n"):
mac = line[i].split('\t', -1)[0][:17]
if mac == "00:00:00":
vendor = "Xerox Corporation"
else:
vendor = (line[i].split('\t', -1)[-1])[:-1]
data.append((mac, vendor))
except Exception as e:
print(e)
print(data)
self.dbCursor.executemany("INSERT OR REPLACE INTO data VALUES(?,?)", data)
self.dbConnection.commit()
# --- menu actions --- #
def add_file_menu_actions(self, action_group):
self.action_filemenu = Gtk.Action("FileMenu", "File", None, None)
action_group.add_action(self.action_filemenu)
self.action_database = Gtk.Action("Database", "Database", None, None)
action_group.add_action(self.action_database)
action_group.add_actions([
("Update", None, "Update", "<control><alt>U", "Update data base",
self.on_update_clicked)
])
self.action_filequit = Gtk.Action("FileQuit", None, None, Gtk.STOCK_QUIT)
self.action_filequit.connect("activate", self.on_menu_file_quit)
action_group.add_action(self.action_filequit)
def add_help_menu_actions(self, action_group):
action_group.add_actions([
("HelpMenu", None, "Help"),
("? help", None, "? help", "<control><alt>H", None,
lambda x: self.launch_generic_dialog(self, "Help")),
("About", None, "About", "<control><alt>A", None,
lambda x:self.launch_generic_dialog(self, "About"))
])
def create_ui_manager(self):
self.uimanager = Gtk.UIManager()
# Throws exception if something went wrong
self.uimanager.add_ui_from_string(self.UI_INFO)
# Add the accelerator group to the toplevel window
self.accelgroup = self.uimanager.get_accel_group()
self.add_accel_group(self.accelgroup)
return self.uimanager
def on_menu_file_quit(self, widget):
Gtk.main_quit()
# --- Database source update --- #
def on_update_clicked(self, widget):
print("Updating...")
self.progressbar.set_visible(True)
self.progressbar.set_fraction(0.10)
url = "https://gitlab.com/aitzol76/mac-vendors/raw/master/manuf"
# url = "https://github.com/wireshark/wireshark/raw/master/manuf"
try:
r = urllib.request.urlretrieve(url, "source.txt")
remote_file_size = r[1]["Content-Length"]
size = round(int(remote_file_size))
fraction = round(size/10)
print(size)
print(fraction)
def progress_bar():
i = 0
while i < size:
value = round(self.progressbar.get_fraction() + 0.1, 1)
self.progressbar.set_fraction(value)
print(self.progressbar.get_fraction())
sleep(0.3)
i = i + fraction
print(i)
yield True
# while Gtk.events_pending():
# Gtk.main_iteration()
if self.progressbar.get_fraction() == 1.0:
print("...updated!")
self.launch_dialog(self, "Database succesfully updated!", "Success")
break
def run_progressbar_generator(function):
gen = function()
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
run_progressbar_generator(progress_bar)
return True
except Exception as e:
self.launch_dialog(self, str(e), "Error")
return e
def launch_dialog(self, widget, text, title):
dialog = UpdaterDialog(self, title)
dialog.label.set_text(text)
response = dialog.run()
if response == Gtk.ResponseType.OK:
print("The OK button was clicked")
self.progressbar.set_visible(False)
dialog.destroy()
def launch_generic_dialog(self, widget, title):
dialog = GenericDialog(self, title)
# dialog.label.set_text(text)
response = dialog.run()
if response == Gtk.ResponseType.OK:
print("The OK button was clicked")
dialog.destroy()
# --- Dialogs --- #
class UpdaterDialog(Gtk.Dialog):
def __init__(self, parent, title):
Gtk.Dialog.__init__(self, title, parent, 0,
(Gtk.STOCK_OK, Gtk.ResponseType.OK))
self.set_default_size(150, 100)
self.label = Gtk.Label()
box = self.get_content_area()
box.set_border_width(10)
box.add(self.label)
self.show_all()
class GenericDialog(Gtk.Dialog):
def __init__(self, parent, title):
Gtk.Dialog.__init__(self, title, parent, 0,
(Gtk.STOCK_OK, Gtk.ResponseType.OK))
self.set_default_size(150, 100)
self.label = Gtk.Label()
self.label.set_justify(Gtk.Justification.LEFT)
self.label.set_margin_bottom(20)
box = self.get_content_area()
box.set_border_width(10)
box.add(self.label)
if title == "Help":
self.label.set_markup(parser.file_parser("md", "README.md"))
elif title == "About":
self.label.set_markup(parser.file_parser("json", "manifest.json"))
self.show_all()
win = AppWindow()
win.connect("destroy", Gtk.main_quit)
win.db_connect()
win.show_all()
if win.file_check():
win.save_data()
win.progressbar.hide()
Gtk.main()