7 Commits

Author SHA1 Message Date
Szymon
deb7433d3e Merge branch 'main' into feature/password-storing 2026-02-15 13:20:06 +01:00
3506d1f5ea add pywin32 lib 2026-02-15 13:18:52 +01:00
876463d7c5 Added xdg-compliant path for Linux and macOS 2026-02-15 13:06:41 +01:00
ec01f9a7da Update readme with new config info 2026-02-11 22:32:34 +01:00
196482f9e2 fixed not showing login screen if no password is saved 2026-02-11 22:10:57 +01:00
30b2ef6afd Added secure password storing with keyring 2026-02-11 21:56:47 +01:00
19d6c78fb0 Added xdg-compliant path for Linux and macOS
Created config.py

Moved system path logic to config.py
2026-02-09 23:49:31 +01:00
5 changed files with 51 additions and 25 deletions

View File

@@ -30,17 +30,12 @@ zutui
`ctrl`+`q` - Quit `ctrl`+`q` - Quit
# Sidenotes # Sidenotes
- config is stored @ `~/zutui/config.json` ## Config
- On Unix like is stored @ `~/.config/zutui/config.json`
- On Windows is stored @ `~/zutui/config.json`
- so are `grades_cache.json` - so are `grades_cache.json`
- in plaintext.....
##### As of right now I don't see any MUCH better way. ##### Feel free to pull request if you're smarter :)
##### I mean we could simply encrypt and decrypt it during runtime, but... does it really make it any more secure?
##### And we can't really store it in any form of a _hash_ as we have to log in everytime with plain text anyways...
##### However feel free to pull request if you're smarter :)
# TODO: # TODO:
- [x] **Nothing** - [x] **Nothing**

View File

@@ -8,6 +8,8 @@ setup(
"requests", "requests",
"beautifulsoup4", "beautifulsoup4",
"textual", "textual",
"keyring",
"pywin32"
], ],
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [

19
zut_app/config.py Normal file
View File

@@ -0,0 +1,19 @@
import os
import platform
USER_HOME = os.path.expanduser("~")
WINDOWS_PATH = "zutui" # probably should be in %AppData% or something, but I'm not sure, so I won't change it
LINUX_PATH = ".config/zutui"
def get_config_path():
system = platform.system()
if system == "Windows":
APP_DIR = os.path.join(USER_HOME, WINDOWS_PATH)
elif system in ["Linux", "Darwin"]:
APP_DIR = os.path.join(USER_HOME, LINUX_PATH)
else:
print(f"System {system} not supported, aborting...")
exit(1)
if not os.path.exists(APP_DIR):
os.makedirs(APP_DIR)
return APP_DIR

View File

@@ -1,13 +1,11 @@
import requests import requests
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
import json import json
import os import os
USER_HOME = os.path.expanduser("~") from .config import get_config_path
APP_DIR = os.path.join(USER_HOME, "zutui")
if not os.path.exists(APP_DIR): APP_DIR = get_config_path()
os.makedirs(APP_DIR)
CACHE_FILE = os.path.join(APP_DIR, "grades_cache.json") CACHE_FILE = os.path.join(APP_DIR, "grades_cache.json")
TIMEOUT = 10 TIMEOUT = 10

View File

@@ -1,7 +1,7 @@
import json import json
import os import os
import time import keyring
from keyring.errors import KeyringError
from datetime import datetime from datetime import datetime
from textual.app import App, ComposeResult from textual.app import App, ComposeResult
from textual.containers import Container from textual.containers import Container
@@ -10,11 +10,9 @@ from textual.screen import Screen
from textual.binding import Binding from textual.binding import Binding
from .zut_client import ZUT from .zut_client import ZUT
from .config import get_config_path
USER_HOME = os.path.expanduser("~") APP_DIR = get_config_path()
APP_DIR = os.path.join(USER_HOME, "zutui")
if not os.path.exists(APP_DIR):
os.makedirs(APP_DIR)
CONFIG_FILE = os.path.join(APP_DIR, "config.json") CONFIG_FILE = os.path.join(APP_DIR, "config.json")
REFRESH_INTERVAL = 1800 REFRESH_INTERVAL = 1800
@@ -58,9 +56,20 @@ class LoginScreen(Screen):
if success: if success:
try: try:
with open(CONFIG_FILE, "w") as f: with open(CONFIG_FILE, "w") as f:
json.dump({"username": user, "password": password}, f) json.dump({"username": user}, f)
keyring.set_password("zutui", user, password)
except KeyringError as e:
error = e
self.app.call_from_thread(
lambda:
self.app.notify(
f"Błąd: {str(error)}",
title="Błąd zapisu hasła do systemowego menedżera haseł",
severity="warning",
timeout=5
)
)
except: pass except: pass
def do_switch(): def do_switch():
self.app.switch_screen(DashboardScreen()) self.app.switch_screen(DashboardScreen())
self.app.call_from_thread(do_switch) self.app.call_from_thread(do_switch)
@@ -410,7 +419,10 @@ class ZutApp(App):
try: try:
with open(CONFIG_FILE, "r") as f: with open(CONFIG_FILE, "r") as f:
creds = json.load(f) creds = json.load(f)
self.zut_client = ZUT(creds["username"], creds["password"]) password = keyring.get_password("zutui", creds["username"])
if password is None:
raise ValueError("Hasło nie zostało znalezione")
self.zut_client = ZUT(creds["username"], password)
self.push_screen(DashboardScreen()) self.push_screen(DashboardScreen())
except: except:
self.push_screen(LoginScreen()) self.push_screen(LoginScreen())