Skip to content

Commit

Permalink
Py2FA Google Authenticator in Python
Browse files Browse the repository at this point in the history
Google Authenticator desktop GUI and script application in Python with JSON secrets.
  • Loading branch information
atomjoy committed Feb 24, 2024
1 parent 5ad51f5 commit a9d68b3
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 23 deletions.
29 changes: 23 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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/

- <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/>
21 changes: 17 additions & 4 deletions json_file.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/python3

import pyotp, time, json, os, shutil, base64
import pyotp, time, json, os, shutil, base64, sys


class JsonFile:
Expand All @@ -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
Expand All @@ -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 = []
Expand All @@ -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")

Expand All @@ -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
31 changes: 18 additions & 13 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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():
Expand All @@ -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)
Expand All @@ -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("<<TreeviewSelect>>", selectItem)
# treeview.bind('<ButtonRelease-1>', selectItem)

for col_name in cols:
treeview.heading(col_name, text=col_name)
treeview.heading(
col_name,
text=col_name,
)

i = 0

Expand All @@ -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()

Expand All @@ -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)
Expand Down
21 changes: 21 additions & 0 deletions py2fa.desktop
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit a9d68b3

Please sign in to comment.