From 88110c68f0b4c575f936f7dbbe0da10f6a807fb0 Mon Sep 17 00:00:00 2001 From: Vincent Hanewinkel Date: Wed, 12 Nov 2025 15:08:20 +0100 Subject: [PATCH] first commit + add OtpViewer.py + add requirements.txt + updated Readme --- OtpViewer.py | 105 ++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 1 + requirments.txt | 2 + 3 files changed, 108 insertions(+) create mode 100644 OtpViewer.py create mode 100644 requirments.txt diff --git a/OtpViewer.py b/OtpViewer.py new file mode 100644 index 0000000..0f330c8 --- /dev/null +++ b/OtpViewer.py @@ -0,0 +1,105 @@ +import pyotp, time +import tkinter as tk +from tkinter import simpledialog, messagebox +from dotenv import load_dotenv +import os +load_dotenv() + +email = os.getenv("ACCOUND") +seed = os.getenv("OTP_SEED") + +def set_env_value(key, value, path=".env"): + lines = [] + found = False + + try: + with open(path, "r") as f: + for line in f: + if line.startswith(f"{key}="): + lines.append(f"{key}={value}\n") + found = True + else: + lines.append(line) + except FileNotFoundError: + pass # Falls Datei noch nicht existiert + + if not found: + lines.append(f"{key}={value}\n") + + with open(path, "w") as f: + f.writelines(lines) + +otp = pyotp.TOTP(seed) +INTERVAL = otp.interval # Standard = 30s + +def seconds_left(): + # Differenz bis zum nächsten 30-Sekunden-Zyklus + return INTERVAL - int(time.time()) % INTERVAL + +root = tk.Tk() +root.title("OTP-Code") + + +label_email = tk.Label( + root, + text=f"Account: {email}", + font=("Arial", 20, "bold"), + fg='Black', # Textfarbe + ) +label_email.pack(padx=20, pady=20) +label = tk.Label( + root, + text=f"Lade ...", + font=("Arial", 20, "bold"), + fg='Black', # Textfarbe + ) +label.pack(padx=20, pady=20) + +def update(): + remaining = seconds_left() + global seed + if seed == 'Standard': + label.config(text=f"Gibt deinen Otp Seed ein",fg='black',) + root.after(250, update) + + else: + if remaining > 10: + color = 'green' + elif remaining > 5: + color = "#e9ab00" + else: + color = 'red' + + label.config(text=f"Code: {otp.now()} - Läuft ab in: {remaining:02d}s",fg=color,) + + root.after(250, update) + +def set_seed(): + global email, seed, otp + new_account = simpledialog.askstring("Accountname eingeben", "Gib deinen Accountnamen ein:") + new_seed = simpledialog.askstring("Seed eingeben", "Gib den neuen OTP-Seed ein:") + if new_seed and new_account: + try: + otp = pyotp.TOTP(new_seed) + seed = new_seed + set_env_value("OTP_SEED", new_seed) + set_env_value("ACCOUND", new_account) + email = new_account + label_email.config(text=f"Account: {email}") + messagebox.showinfo("Erfolg", "Seed wurde erfolgreich geändert!") + except Exception as e: + messagebox.showerror("Fehler", f"Ungültiger Seed:\n{e}") + +menubar = tk.Menu(root) +root.config(menu=menubar) + +otp_menu = tk.Menu(menubar, tearoff=0) +otp_menu.add_command(label="Seed ändern", command=set_seed) +otp_menu.add_separator() +otp_menu.add_command(label="Beenden", command=root.destroy) +menubar.add_cascade(label="Optionen", menu=otp_menu) + + + +update() +root.mainloop() diff --git a/README.md b/README.md index 5adbdb8..f3a0332 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # OTP-Viewer +Software die für ein OPT-Token die Code Generiert \ No newline at end of file diff --git a/requirments.txt b/requirments.txt new file mode 100644 index 0000000..23f0852 --- /dev/null +++ b/requirments.txt @@ -0,0 +1,2 @@ +pyotp +python-dotenv \ No newline at end of file