From a9d68b3fd3edcfc4fa8fcc91b376f409c28a7894 Mon Sep 17 00:00:00 2001 From: Atomjoy Date: Sat, 24 Feb 2024 10:13:12 +0100 Subject: [PATCH] Py2FA Google Authenticator in Python Google Authenticator desktop GUI and script application in Python with JSON secrets. --- README.md | 29 +++++++++++++++++++++++------ json_file.py | 21 +++++++++++++++++---- main.py | 31 ++++++++++++++++++------------- py2fa.desktop | 21 +++++++++++++++++++++ 4 files changed, 79 insertions(+), 23 deletions(-) create mode 100644 py2fa.desktop diff --git a/README.md b/README.md index 74dbc9e..0b53c09 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ # Google Authenticator in Python + Google Authenticator desktop GUI and script application in Python with JSON secrets. ## How to -Install python3 and module + +Install python3 and modules ```sh # Check @@ -13,16 +15,18 @@ sudo apt install python3 python3-pyotp python3-tk -y ``` ### Add secrets + First add your 2FA secrets to the **secrets.json** file (when enabling github two factor auth get secret key). ```json { "atomjoy_github": "JBSWY3DPEHPK3PXP", - "moovspace_github": "JBSWY3DPEHPK3PXD" + "moovspace_github": "JBSWY3DPEHPK3PXD" } ``` ### Run script + The script generates 2fa codes for secrets. ```sh @@ -69,8 +73,21 @@ print(x.verify(code)) # True # print(x.verify(code)) ``` +## Edit and copy PyF2A activator + +For Linux Debian 12 Gnome 43+ + +```sh +# Edit this line change main.py file location +Exec=/bin/python3 /home/username/Dokumenty/github/py2fa-gui/main.py %u + +# And copy app activator file to +cp py2fa.desktop /home/username/.local/share/applications +``` + ## Links -- https://pyauth.github.io/pyotp/ -- https://medium.com/@olutomilayodolapo/how-to-retrieve-otp-from-authy-google-authenticator-with-python-53544575bcef -- https://github.com/grahammitchell/google-authenticator/blob/master/google-authenticator.py -- https://www.geeksforgeeks.org/two-factor-authentication-using-google-authenticator-in-python/ + +- +- +- +- diff --git a/json_file.py b/json_file.py index 3d12ecc..448022d 100644 --- a/json_file.py +++ b/json_file.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -import pyotp, time, json, os, shutil, base64 +import pyotp, time, json, os, shutil, base64, sys class JsonFile: @@ -14,6 +14,10 @@ def __init__(self, filename="secrets.json"): self.filename = filename self.__loadJson() self.__updateCode() + self.scriptPath() + + def scriptPath(self): + print(os.path.dirname(os.path.realpath(sys.argv[0]))) def getAll(self): return self.data_code @@ -39,7 +43,7 @@ def addItem(self, name, secret): self.data.append(item) self.__updateCode() self.saveJson() - print("Appended", self.data) + # print("Appended", self.data) def updateCode(self): self.data_code = [] @@ -64,7 +68,7 @@ def saveJson(self): rel = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__))) with open(os.path.join(rel, self.filename), "w") as outfile: json.dump(json_obj, outfile) - print("Saved json", json_obj) + # print("Saved json", json_obj) except (ImportError, Exception): print("Save error") @@ -85,7 +89,16 @@ def removeItem(self, name): res = [i for i in self.data if i[0] != name] self.data = res self.saveJson() - print(res) + # print(res) + + def showPaths(self): + print(sys.path[0]) + print(os.path.realpath(__file__)) + print(os.path.dirname(__file__)) + print(os.getcwd()) + print(os.path.join(os.getcwd(), os.path.dirname(__file__))) + print(os.path.dirname(os.path.realpath(__file__))) + print(os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))) __loadJson = loadJson # private copy of original update() method __updateCode = updateCode # private copy of original update() method diff --git a/main.py b/main.py index 87cdd52..037431d 100644 --- a/main.py +++ b/main.py @@ -7,7 +7,7 @@ from json_file import JsonFile window = tkinter.Tk() -window.title("2FA Google Authenticator") +window.title("Py2FA Google Authenticator") # window.geometry('300x200') # window.resizable(False, False) @@ -25,18 +25,19 @@ def selectItem(event): tree = event.widget current_item = tree.focus() item = tree.item(current_item) - print("Selected Item", item) + # print("Selected Item", item) try: if hasattr(item, "values"): - code = format(item["values"][2], "006d") + code = format(item["values"][2], "06d") messagebox.showinfo("Code", code) - print("Id:", current_item, "Item:", item, "Code:", code) - except IndexError: - print("Empty item values", item) + # print("Id:", current_item, "Item:", item, "Code:", code) + except (IndexError, Exception): + # print("Item not selected") + pass def update(): - t = time.strftime("%I:%M:%S", time.localtime()) + t = time.strftime("%H:%M:%S", time.localtime()) treeview.delete(*treeview.get_children()) i = 0 for item_tuple in load_data(): @@ -47,7 +48,7 @@ def update(): # Show user codes -fr_codes = tkinter.LabelFrame(fr, text="2FA Codes", font="times 21") +fr_codes = tkinter.LabelFrame(fr, text="2FA Codes", font="roboto 16") fr_codes.grid(row=0, column=0) treeFrame = ttk.Frame(fr_codes) @@ -59,17 +60,20 @@ def update(): treeview = ttk.Treeview( treeFrame, show="headings", - yscrollcommand=treeScroll.set, columns=cols, - height=13, + height=20, selectmode="browse", + yscrollcommand=treeScroll.set, ) treeview.column("Name", width=250) treeview.bind("<>", selectItem) # treeview.bind('', selectItem) for col_name in cols: - treeview.heading(col_name, text=col_name) + treeview.heading( + col_name, + text=col_name, + ) i = 0 @@ -90,7 +94,7 @@ def callback_add(): js = JsonFile("secrets.json") if len(name) >= 3: if len(secret) >= 16: - print("Name", name, "Secret", secret) + # print("Name", name, "Secret", secret) js.addItem(name, secret) update() @@ -104,8 +108,9 @@ def callback_del(): # Saving user secret -fr_add_secret = tkinter.LabelFrame(fr, text="Add secret", font="times 21") +fr_add_secret = tkinter.LabelFrame(fr, text="Add secret", font="roboto 16") fr_add_secret.grid(row=1, column=0) +# fr_add_secret.pack(fill="x") label_name = tkinter.Label(fr_add_secret, text="App name") label_name.grid(row=0, column=0) diff --git a/py2fa.desktop b/py2fa.desktop new file mode 100644 index 0000000..9d2b7b2 --- /dev/null +++ b/py2fa.desktop @@ -0,0 +1,21 @@ +# App activator +# /home/user/.local/share/applications + +[Desktop Entry] +Exec=/bin/python3 /home/user/Dokumenty/github/py2fa-gui/main.py %u +Name=Py2FA +Name[pl]=Py2FA +Comment=Py2fa Authenticator +Comment[pl]=Py2fa Authenticator +GenericName=Py2fa Authenticator +GenericName[pl]=Py2fa Authenticator +X-GNOME-FullName=Py2fa Google Authenticator +X-GNOME-FullName[pl]=Py2fa Google Authenticator +Terminal=false +X-MultipleArgs=false +Type=Application +Icon=qrcode +Categories=Network;Authenticator; +MimeType=text/html;text/xml;application/xhtml+xml;application/xml;application/vnd.mozilla.xul+xml;application/rss+xml;application/rdf+xml;image/gif;image/jpeg;image/png;x-scheme-handler/htt> +StartupWMClass=Py2FA-bin +StartupNotify=true \ No newline at end of file