Initial commit for profile PyHasher
This commit is contained in:
parent
452020c04a
commit
7ea259c512
15
.vscode/launch.json
vendored
Normal file
15
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
"name": "Python Debugger: Module",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"module": "pyhasher"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,17 +1,24 @@
|
||||
# pyhasher/__main__.py
|
||||
|
||||
# Example import assuming your main logic is in a 'main' function
|
||||
# within a 'app' module in your 'pyhasher.core' package.
|
||||
# from pyhasher.core.app import main as start_application
|
||||
#
|
||||
# Or, if you have a function in pyhasher.core.core:
|
||||
# from pyhasher.core.core import main_function
|
||||
import tkinter as tk
|
||||
from pyhasher.gui.gui import PyHasherApp
|
||||
|
||||
def main():
|
||||
print(f"Running PyHasher...")
|
||||
# Placeholder: Replace with your application's entry point
|
||||
# Example: start_application()
|
||||
print("To customize, edit 'pyhasher/__main__.py' and your core modules.")
|
||||
"""
|
||||
Main function to initialize and run the PyHasher application.
|
||||
|
||||
This function sets up the main Tkinter window and starts the GUI application.
|
||||
"""
|
||||
# Create the main window
|
||||
root = tk.Tk()
|
||||
|
||||
# Create an instance of the application
|
||||
app = PyHasherApp(root)
|
||||
|
||||
# Start the Tkinter event loop
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
# This block allows the script to be run directly,
|
||||
# though the primary entry point is via 'python -m pyhasher'
|
||||
main()
|
||||
@ -0,0 +1,67 @@
|
||||
# pyhasher/core/core.py
|
||||
|
||||
import hashlib
|
||||
import zlib
|
||||
|
||||
# Define a constant for the chunk size to read from the file.
|
||||
# This helps in processing large files without loading them entirely into memory.
|
||||
BUFFER_SIZE = 65536 # 64KB
|
||||
|
||||
def calculate_hashes_for_file(file_path: str) -> dict:
|
||||
"""
|
||||
Calculates various hashes for a given file.
|
||||
|
||||
Includes checksums (CRC32, Adler-32) and cryptographic hashes
|
||||
(MD5, SHA-1, SHA-2, SHA-3, BLAKE2).
|
||||
|
||||
Args:
|
||||
file_path: The absolute path to the file.
|
||||
|
||||
Returns:
|
||||
A dictionary containing the calculated hashes.
|
||||
Example: {'CRC32': '...', 'MD5': '...', ...}
|
||||
|
||||
Raises:
|
||||
IOError: If the file cannot be read.
|
||||
"""
|
||||
# Initialize checksums
|
||||
crc32_val = 0
|
||||
adler32_val = 1 # Adler-32 starts with a value of 1
|
||||
|
||||
# Initialize cryptographic hashers
|
||||
hashers = {
|
||||
"MD5": hashlib.md5(),
|
||||
"SHA-1": hashlib.sha1(),
|
||||
"SHA-256": hashlib.sha256(),
|
||||
"SHA-384": hashlib.sha384(),
|
||||
"SHA-512": hashlib.sha512(),
|
||||
"SHA3-256": hashlib.sha3_256(),
|
||||
"BLAKE2b": hashlib.blake2b(),
|
||||
}
|
||||
|
||||
with open(file_path, "rb") as f:
|
||||
while True:
|
||||
# Read the file in chunks
|
||||
data = f.read(BUFFER_SIZE)
|
||||
if not data:
|
||||
break
|
||||
|
||||
# Update each cryptographic hasher
|
||||
for hasher in hashers.values():
|
||||
hasher.update(data)
|
||||
|
||||
# Update checksums
|
||||
crc32_val = zlib.crc32(data, crc32_val)
|
||||
adler32_val = zlib.adler32(data, adler32_val)
|
||||
|
||||
# Prepare the results dictionary, starting with checksums
|
||||
results = {
|
||||
"CRC32": f"{crc32_val:08x}",
|
||||
"Adler-32": f"{adler32_val:08x}",
|
||||
}
|
||||
|
||||
# Add cryptographic hashes to the results
|
||||
for name, hasher in hashers.items():
|
||||
results[name] = hasher.hexdigest()
|
||||
|
||||
return results
|
||||
@ -0,0 +1,130 @@
|
||||
# pyhasher/gui/gui.py
|
||||
|
||||
import tkinter as tk
|
||||
from tkinter import filedialog, messagebox
|
||||
import os
|
||||
|
||||
# Import the core logic function
|
||||
from pyhasher.core.core import calculate_hashes_for_file
|
||||
|
||||
# Defines the order in which hashes will be displayed in the GUI.
|
||||
# This must match the keys returned by the core function.
|
||||
HASH_DISPLAY_ORDER = (
|
||||
"CRC32",
|
||||
"Adler-32",
|
||||
"MD5",
|
||||
"SHA-1",
|
||||
"SHA-256",
|
||||
"SHA-384",
|
||||
"SHA-512",
|
||||
"SHA3-256",
|
||||
"BLAKE2b",
|
||||
)
|
||||
|
||||
class PyHasherApp:
|
||||
"""
|
||||
The main GUI application class for PyHasher.
|
||||
It handles the user interface and interactions.
|
||||
"""
|
||||
def __init__(self, root_window):
|
||||
"""
|
||||
Initialize the application.
|
||||
|
||||
Args:
|
||||
root_window: The main tkinter window.
|
||||
"""
|
||||
self.root = root_window
|
||||
self.root.title("PyHasher")
|
||||
self.root.geometry("1024x400") # Increased height for more hashes
|
||||
self.file_path = tk.StringVar()
|
||||
|
||||
# --- Main frame ---
|
||||
main_frame = tk.Frame(self.root, padx=10, pady=10)
|
||||
main_frame.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
# --- File selection widgets ---
|
||||
self._create_file_selection_widgets(main_frame)
|
||||
|
||||
# --- Hash results widgets ---
|
||||
self._create_hash_display_widgets(main_frame)
|
||||
|
||||
# --- Action buttons ---
|
||||
self._create_action_buttons(main_frame)
|
||||
|
||||
def _create_file_selection_widgets(self, parent_frame):
|
||||
"""Creates widgets for file selection."""
|
||||
file_frame = tk.Frame(parent_frame)
|
||||
file_frame.pack(fill=tk.X, pady=(0, 10))
|
||||
|
||||
file_label = tk.Label(file_frame, text="File:")
|
||||
file_label.pack(side=tk.LEFT, padx=(0, 5))
|
||||
|
||||
file_entry = tk.Entry(file_frame, textvariable=self.file_path, state="readonly")
|
||||
file_entry.pack(side=tk.LEFT, fill=tk.X, expand=True)
|
||||
|
||||
browse_button = tk.Button(file_frame, text="Browse...", command=self.select_file)
|
||||
browse_button.pack(side=tk.LEFT, padx=(5, 0))
|
||||
|
||||
def _create_hash_display_widgets(self, parent_frame):
|
||||
"""Creates labels and entry boxes for displaying hash results."""
|
||||
results_frame = tk.Frame(parent_frame)
|
||||
results_frame.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
# Dictionary to hold hash names and their corresponding tk.StringVar
|
||||
self.hash_vars = {name: tk.StringVar() for name in HASH_DISPLAY_ORDER}
|
||||
|
||||
# Create labels and read-only entry widgets for each hash type
|
||||
for i, name in enumerate(HASH_DISPLAY_ORDER):
|
||||
label = tk.Label(results_frame, text=f"{name}:")
|
||||
label.grid(row=i, column=0, sticky="w", pady=2)
|
||||
|
||||
entry = tk.Entry(results_frame, textvariable=self.hash_vars[name], state="readonly")
|
||||
entry.grid(row=i, column=1, sticky="ew", pady=2, padx=(5, 0))
|
||||
|
||||
# Configure the grid to expand the entry column
|
||||
results_frame.columnconfigure(1, weight=1)
|
||||
|
||||
def _create_action_buttons(self, parent_frame):
|
||||
"""Creates the main action buttons."""
|
||||
button_frame = tk.Frame(parent_frame)
|
||||
button_frame.pack(fill=tk.X, pady=(10, 0), side=tk.BOTTOM)
|
||||
|
||||
calculate_button = tk.Button(
|
||||
button_frame,
|
||||
text="Calculate Hashes",
|
||||
command=self.calculate_hashes
|
||||
)
|
||||
calculate_button.pack(side=tk.RIGHT)
|
||||
|
||||
def select_file(self):
|
||||
"""Opens a file dialog to select a file and clears old results."""
|
||||
path = filedialog.askopenfilename()
|
||||
if path:
|
||||
self.file_path.set(path)
|
||||
# Clear previous results when a new file is selected
|
||||
for var in self.hash_vars.values():
|
||||
var.set("")
|
||||
|
||||
def calculate_hashes(self):
|
||||
"""
|
||||
Gets the file path, calls the core function to calculate hashes,
|
||||
and displays the results in the GUI.
|
||||
"""
|
||||
current_file_path = self.file_path.get()
|
||||
if not current_file_path or not os.path.exists(current_file_path):
|
||||
messagebox.showerror("Error", "Please select a valid file first.")
|
||||
return
|
||||
|
||||
try:
|
||||
# Call the decoupled core function to do the heavy lifting
|
||||
all_hashes = calculate_hashes_for_file(current_file_path)
|
||||
|
||||
# Update the GUI with the results from the core function
|
||||
for name, value in all_hashes.items():
|
||||
if name in self.hash_vars:
|
||||
self.hash_vars[name].set(value)
|
||||
|
||||
except IOError as e:
|
||||
messagebox.showerror("Error", f"Could not read file: {e}")
|
||||
except Exception as e:
|
||||
messagebox.showerror("Error", f"An unexpected error occurred: {e}")
|
||||
Loading…
Reference in New Issue
Block a user