macBank/app.py

455 lines
16 KiB
Python

# Copyright 2018 Wproject - Aitzol Berasategi - https://aitzol.eus
#
# This file is part of macBank Ver.1.0.0.
#
# This project is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 3.
#
# PyCalculator is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or ANY OTHER COMMERCIAL PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from io import open
from time import sleep
import os.path
import urllib.request
import sqlite3
from development import parser
import re
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GLib
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.mac48 = self.search[:8] # mac address first 3 octets
self.dbCursor.execute("SELECT * FROM data WHERE mac=?", (self.mac48.upper(),))
self.rows = self.dbCursor.fetchall()
if self.rows:
for row in self.rows:
if row[1] == "IEEE Registration Authority":
self.iab_base = self.mac48+":00:00:00"
self.dbCursor.execute("SELECT * FROM data WHERE mac<=? AND mac>=? ORDER BY mac DESC LIMIT 1", (self.search.upper(), self.iab_base.upper()))
self.rows = self.dbCursor.fetchall()
if self.rows:
for row in self.rows:
print(row)
self.result = (self.search.upper(), row[1])
else:
self.result = (self.search.upper(), 'Sorry, No results found!')
print(self.result)
else:
self.result = (self.search.upper(), row[1])
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()