Compare commits
2 Commits
938a1ea71d
...
406eb8c166
| Author | SHA1 | Date | |
|---|---|---|---|
| 406eb8c166 | |||
| 736fd3b049 |
@ -1,6 +1,8 @@
|
||||
import platform
|
||||
from tkinter import *
|
||||
from tkinter import ttk
|
||||
from customtkinter import *
|
||||
from CTkMenuBar import *
|
||||
from CTkMessagebox import *
|
||||
from typing import List
|
||||
|
||||
from app.utils_drive import *
|
||||
@ -15,45 +17,51 @@ class App:
|
||||
drive_tree = None
|
||||
|
||||
def __init__(self):
|
||||
set_default_color_theme("dark-blue")
|
||||
set_appearance_mode("dark")
|
||||
|
||||
self.OS_TYPE = platform.system()
|
||||
|
||||
self.root = Tk()
|
||||
self.root = CTk()
|
||||
self.root.title("Disk Eraser")
|
||||
self.root.geometry("700x300")
|
||||
self.root.minsize(700, 300)
|
||||
self.root.geometry("800x300")
|
||||
self.root.minsize(800, 300)
|
||||
self.__load_menus()
|
||||
self.__init_table()
|
||||
self.__update_drives()
|
||||
self.root.mainloop()
|
||||
|
||||
def __load_menus(self):
|
||||
main_menu = Menu()
|
||||
|
||||
help_menu = Menu(tearoff=0)
|
||||
help_menu.add_command(label="Содержание")
|
||||
help_menu.add_separator()
|
||||
help_menu.add_command(label="О программе")
|
||||
|
||||
main_menu.add_cascade(label="Справка", menu=help_menu)
|
||||
bg_color = self.root._apply_appearance_mode(ThemeManager.theme["CTkFrame"]["fg_color"])
|
||||
|
||||
main_menu = CTkMenuBar(self.root, bg_color=bg_color)
|
||||
|
||||
help_menu = main_menu.add_cascade("Справка")
|
||||
|
||||
dropdown1 = CustomDropdownMenu(widget=help_menu)
|
||||
dropdown1.add_option(option="Помощь")
|
||||
dropdown1.add_separator()
|
||||
dropdown1.add_option(option="О программе", command=self.__open_about_window)
|
||||
|
||||
self.root.config(menu=main_menu)
|
||||
|
||||
self.bottom_frame = ttk.Frame(borderwidth=1, relief=SOLID, padding=[3, 5])
|
||||
self.bottom_frame = CTkFrame(self.root, height=10000)
|
||||
|
||||
self.erase_button = ttk.Button(
|
||||
self.erase_button = CTkButton(
|
||||
self.bottom_frame, text="Стереть диск", command=self.__erase_drive)
|
||||
self.erase_button.pack(side=RIGHT)
|
||||
|
||||
update_button = ttk.Button(
|
||||
update_button = CTkButton(
|
||||
self.bottom_frame, text="Обновить", command=self.__update_drives)
|
||||
update_button.pack(side=RIGHT, padx=5)
|
||||
|
||||
self.method_box = ttk.Combobox(master=self.bottom_frame, values=list(erasing_methods.keys()), state="readonly")
|
||||
self.method_box = CTkComboBox(master=self.bottom_frame, values=list(erasing_methods.keys()), state="readonly")
|
||||
self.method_box.pack(side=RIGHT, padx=6)
|
||||
|
||||
method_label = ttk.Label(master=self.bottom_frame, text="Метод: ")
|
||||
method_label = CTkLabel(master=self.bottom_frame, text="Метод: ")
|
||||
method_label.pack(padx=5, side=RIGHT)
|
||||
|
||||
self.bottom_frame.pack(side=BOTTOM, fill=X)
|
||||
self.bottom_frame.pack(side=BOTTOM, fill=BOTH, padx=5, pady=5)
|
||||
|
||||
def __update_drives(self):
|
||||
self.drive_tree.delete(*self.drive_tree.get_children())
|
||||
@ -61,6 +69,7 @@ class App:
|
||||
for drive in self.drives:
|
||||
self.drive_tree.insert("", END, values=(
|
||||
drive.index, drive.name, drive.disk_type, self.__human_size(drive.capacity), drive.serial_num))
|
||||
self.selected = None
|
||||
|
||||
def __load_drives(self):
|
||||
|
||||
@ -84,6 +93,19 @@ class App:
|
||||
|
||||
def __init_table(self):
|
||||
|
||||
###Treeview Customisation (theme colors are selected)
|
||||
bg_color = self.root._apply_appearance_mode(ThemeManager.theme["CTkFrame"]["fg_color"])
|
||||
text_color = self.root._apply_appearance_mode(ThemeManager.theme["CTkLabel"]["text_color"])
|
||||
selected_color = self.root._apply_appearance_mode(ThemeManager.theme["CTkButton"]["fg_color"])
|
||||
|
||||
treestyle = ttk.Style()
|
||||
treestyle.theme_use()
|
||||
treestyle.configure("Treeview", background=bg_color, foreground=text_color, fieldbackground=bg_color, borderwidth=0)
|
||||
treestyle.map('Treeview', background=[('selected', bg_color)], foreground=[('selected', selected_color)])
|
||||
treestyle.configure("Treeview.Heading", background=bg_color, foreground=text_color, fieldbackground=bg_color, borderwidth=0)
|
||||
treestyle.map('Treeview.Heading', background=[('selected', bg_color)], foreground=[('selected', selected_color)])
|
||||
self.root.bind("<<TreeviewSelect>>", lambda event: self.root.focus_set())
|
||||
|
||||
# определяем столбцы
|
||||
columns = ("index", "name", "type", "capacity", "serial_num")
|
||||
self.drive_tree = ttk.Treeview(
|
||||
@ -118,23 +140,38 @@ class App:
|
||||
self.selected = item["values"]
|
||||
|
||||
def __erase_drive(self):
|
||||
if self.selected is not None:
|
||||
method = self.method_box.get()
|
||||
if self.selected is None:
|
||||
self.__show_warning("Выберете носитель информации для стирания!")
|
||||
elif method == "":
|
||||
self.__show_warning("Выберете метод стирания данных!")
|
||||
elif self.__ask_question():
|
||||
self.erase_button.configure(state='disabled')
|
||||
self.drive_tree.configure(selectmode="none")
|
||||
|
||||
thread = None
|
||||
self.progressbar = ttk.Progressbar(master=self.bottom_frame, orient="horizontal", length=250)
|
||||
self.progressbar = CTkProgressBar(master=self.bottom_frame, orientation="horizontal", width=200)
|
||||
self.progressbar.pack(side=LEFT, padx=6, pady=6)
|
||||
self.progress_label = CTkLabel(self.bottom_frame, text="0 %")
|
||||
self.progress_label.pack(side=LEFT, padx=5, pady=5)
|
||||
|
||||
for drive in self.drives:
|
||||
if drive.index == self.selected[0]:
|
||||
thread = drive.erase(self.method_box.get(), progress=self.progressbar)
|
||||
thread = drive.erase(self.method_box.get(), progressbar=self.progressbar, progress_label=self.progress_label)
|
||||
self.__check_thread(thread)
|
||||
|
||||
def __check_thread(self, thread):
|
||||
if thread.is_alive():
|
||||
self.root.after(1000, lambda: self.__check_thread(thread))
|
||||
else:
|
||||
self.progress_label.pack_forget()
|
||||
self.progressbar.pack_forget()
|
||||
self.drive_tree.configure(selectmode="browse")
|
||||
self.erase_button.configure(state='active')
|
||||
CTkMessagebox(title="Успешно", message=f"{self.selected[1]} стёрт!")
|
||||
|
||||
def __show_warning(self, text):
|
||||
CTkMessagebox(title="Ошибка", message=text)
|
||||
|
||||
def __sort(self, col, reverse):
|
||||
# получаем все значения столбцов в виде отдельного списка
|
||||
@ -145,4 +182,17 @@ class App:
|
||||
for index, (_, k) in enumerate(l):
|
||||
self.drive_tree.move(k, "", index)
|
||||
# в следующий раз выполняем сортировку в обратном порядке
|
||||
self.drive_tree.heading(col, command=lambda: self.__sort(col, not reverse))
|
||||
self.drive_tree.heading(col, command=lambda: self.__sort(col, not reverse))
|
||||
|
||||
def __ask_question(self):
|
||||
msg = CTkMessagebox(title="Стереть", message=f"Вы уверены, что хотите стереть {self.selected[1]}?",
|
||||
icon="question", option_1="Отмена", option_2="Нет", option_3="Да")
|
||||
response = msg.get()
|
||||
|
||||
if response == "Да":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def __open_about_window(self):
|
||||
CTkMessagebox(title="О программе", message="Программа для гарантированного стирания машинных носителей информации\n(c) Romanko M.I., Russia, 2024")
|
||||
@ -1,4 +1,8 @@
|
||||
from threading import *
|
||||
import threading
|
||||
import os
|
||||
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
erasing_methods = {
|
||||
"2 прохода": {
|
||||
@ -10,7 +14,7 @@ erasing_methods = {
|
||||
"data": ["random"]
|
||||
},
|
||||
"Гутмана": {
|
||||
"num_passes": 35,
|
||||
"num_passes": 0,
|
||||
"data": []
|
||||
},
|
||||
"3 прохода": {
|
||||
@ -23,6 +27,14 @@ erasing_methods = {
|
||||
}
|
||||
}
|
||||
|
||||
def get_random_bytes(size):
|
||||
seed=os.urandom(32)
|
||||
backend = default_backend()
|
||||
cipher = Cipher(algorithms.AES(seed), modes.CTR(b'\0'*16), backend=backend)
|
||||
encryptor = cipher.encryptor()
|
||||
|
||||
nulls=b'\0'*(size)
|
||||
return encryptor.update(nulls)
|
||||
|
||||
class Drive():
|
||||
|
||||
@ -52,27 +64,29 @@ class Drive():
|
||||
self.serial_num = dev_id
|
||||
self.index = index
|
||||
|
||||
def erase(self, method, progress=0) -> Thread:
|
||||
if method == "2 прохода":
|
||||
method_ = self.__erasing_2
|
||||
elif method == "Случайные данные":
|
||||
method = self.__erasing_random
|
||||
t = Thread(target=method_, args=(progress,))
|
||||
def erase(self, method, progressbar, progress_label) -> threading.Thread:
|
||||
t = threading.Thread(target=self.__erasing, args=(method, progressbar,progress_label))
|
||||
t.start()
|
||||
return t
|
||||
|
||||
def __erasing_2(self, progress):
|
||||
len_write = 0
|
||||
def __erasing(self, method, progressbar, progress_label):
|
||||
write_size = self.block_size*32
|
||||
with open(self.path, "wb") as drive:
|
||||
while len_write < self.capacity:
|
||||
# drive.write(b"\x00"*self.block_size)
|
||||
len_write += self.block_size*64
|
||||
progress["value"] = int(len_write/self.capacity * 100)
|
||||
|
||||
def __erasing_2(self, progress):
|
||||
len_write = 0
|
||||
with open(self.path, "wb") as drive:
|
||||
while len_write < self.capacity:
|
||||
# drive.write(b"\x00"*self.block_size)
|
||||
len_write += self.block_size*64
|
||||
progress["value"] = int(len_write/self.capacity * 100)
|
||||
for i in range(erasing_methods[method]["num_passes"]):
|
||||
drive.seek(0)
|
||||
prev_percent = 0
|
||||
len_write = 0
|
||||
progressbar.set(prev_percent)
|
||||
print(i)
|
||||
while len_write < self.capacity:
|
||||
if erasing_methods[method]["data"][i] == "random":
|
||||
data = get_random_bytes(write_size)
|
||||
else:
|
||||
data = erasing_methods[method]["data"][i] * write_size
|
||||
drive.write(data)
|
||||
len_write += write_size
|
||||
cur_percent = len_write/self.capacity
|
||||
if cur_percent - prev_percent > 0.01:
|
||||
progressbar.set(cur_percent)
|
||||
progress_label.configure(text=f"{int(cur_percent*100)} %")
|
||||
prev_percent = cur_percent
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user