This commit is contained in:
Kyattsukuro 2025-10-02 10:48:30 +02:00
parent 2025d26a5c
commit 842ad3ff44
12 changed files with 126 additions and 5 deletions

View File

@ -11,7 +11,8 @@
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"nixEnvSelector.nixFile": "${workspaceFolder}/shell.nix",
"python.testing.unittestArgs": ["-s", "simple_chat_api/tests", "-p", "*.py"],
"python.testing.unittestArgs": ["-s", ".", "-p", "*.py"],
"python.testing.pytestEnabled": false,
"python.testing.cwd": "${workspaceFolder}",
"python.testing.unittestEnabled": true
}

View File

@ -4,7 +4,7 @@ This is a simple one-room chat application with user management, developed as a
**Not recommended for production use.**
A test protocol can be found here: [simple_chat_testprotokoll.pdf](simple_chat_testprotokoll.pdf)
A test protocol can be found here: [docs/simple_chat_testprotokoll.pdf](simple_chat_testprotokoll.pdf)
## Running with Docker

BIN
docs/unittest_sample.sqlite Normal file

Binary file not shown.

View File

@ -1 +1,2 @@
from simple_chat_api.main import main
from simple_chat_api.main import main
from simple_chat_api.db_handler.db_handler import DbConnector

View File

View File

@ -34,6 +34,8 @@ class DbConnector:
self.session = sessionmaker(bind=self.engine)()
self._create_defaults()
def close(self):
self.session.close()
def _create_optional_default_user(self):
for user in optional_default_user:

View File

@ -0,0 +1,71 @@
from simple_chat_api.db_handler.db_handler import DbConnector
from simple_chat_api.config import JWT_SECRET, hash_context
class UserManager:
"""
Class that handles authentication with database backend
"""
def __init__(self, db_con: DbConnector):
self.db_con = db_con
def create_user(self, username: str, password: str) -> bool:
"""
Create a new user in the database
:param username: logon name
:param password: password to save
:return: True if user was created
"""
try:
self.db_con.add_user(username, password)
except:
return False
return True
def authenticate(self, username: str, password: str) -> bool:
"""
Authenticate against the database
:param username: username to check
:param password: password to check
:return: True if authenticated
"""
user = self.db_con.get_user(username)
if not user or not hash_context.verify(password, user.hash):
return False
return True
def delete_user(self, username: str) -> bool:
"""
Delete a user from the database
:param username: username to delete
:return: True on success
"""
try:
self.db_con.delete_user(username)
except:
return False
return True
def change_user_password(self, username: str, password: str) -> bool:
"""
Change the password for a user
:param username: username to change
:param password: new password
:return: True on success
"""
try:
self.db_con.change_password(username, hash_context.hash(password))
except:
return False
return True
def check_user_exists(self, username: str) -> bool:
"""
Check if a user exists in the database
:param username: logon name to look for
:return: True if user exists
"""
if self.db_con.get_user(username):
return True
return False

View File

@ -2,7 +2,7 @@
from bottle import Bottle, request, response
from json import dumps, loads
from simple_chat_api.db_handler import User, Message
from simple_chat_api.db_handler.db_handler import User, Message
from simple_chat_api.endpoints.auth import user_guard
from simple_chat_api.utils import read_keys_from_request
app = Bottle()

View File

@ -1,6 +1,6 @@
from bottle import request, Bottle
from simple_chat_api.db_handler import DbConnector
from simple_chat_api.db_handler.db_handler import DbConnector
import simple_chat_api.endpoints.auth as auth
import simple_chat_api.endpoints.messages as messages

View File

View File

@ -0,0 +1,46 @@
import unittest
import os
import shutil
from simple_chat_api.db_handler.db_handler import DbConnector
from simple_chat_api.db_handler.user_manager import UserManager
DB_PATH = "./data/TEST.sqlite"
EXISTING_USER = ("admin", "admin")
class TestUserManagmentWrapper(unittest.TestCase):
def setUp(self):
shutil.copyfile("docs/unittest_sample.sqlite", DB_PATH)
db = DbConnector(f"sqlite:///{DB_PATH}")
self.user_mgr = UserManager(db)
def tearDown(self):
self.user_mgr.db_con.close()
os.remove(DB_PATH)
def test_create_user(self):
user = ("someone", "some_pass")
ret = self.user_mgr.create_user(*user)
self.assertTrue(ret, f"user {user} faild to be created")
def test_authenticate(self):
self.assertTrue(self.user_mgr.authenticate(*EXISTING_USER),
f"Existing user {EXISTING_USER} could not be authenticated")
self.assertFalse(self.user_mgr.authenticate(EXISTING_USER[0], "unknown_pass"),
f"Existing user {EXISTING_USER[0]} could be authenticated with wrong password")
self.assertFalse(self.user_mgr.authenticate("unknown_user", "unknown_pass"),
f"An unknown User was authenticated")
def test_delete_user(self):
self.assertTrue(self.user_mgr.delete_user(EXISTING_USER[0]), f"The existing user {EXISTING_USER[0]} could not be removed")
self.assertFalse(self.user_mgr.delete_user("unknown_user"), "an unknown user could be deleted")
def test_change_password(self):
self.assertTrue(self.user_mgr.change_user_password(EXISTING_USER[0], "new_pass"), f"Could not change password for existing user")
self.assertFalse(self.user_mgr.change_user_password("unknown_user", "new_pass"), "The password for an unknown user was changed")
def test_check_user_exists(self):
self.assertTrue(self.user_mgr.check_user_exists(EXISTING_USER[0]), f"The {EXISTING_USER[0]} could not be found")
self.assertFalse(self.user_mgr.check_user_exists("unknown_user"), "An unknown user was found")