mirror of
https://github.com/simon987/Simple-Incremental-Search-Tool.git
synced 2025-04-16 08:46:49 +00:00
Added local storage for users
This commit is contained in:
parent
fec23d40d9
commit
de0a835ecd
@ -10,7 +10,7 @@ class FileParser:
|
||||
pass
|
||||
|
||||
|
||||
class CheckSumCalculator:
|
||||
class FileCheckSumCalculator:
|
||||
|
||||
def checksum(self, path: str) -> str:
|
||||
"""
|
||||
@ -21,7 +21,7 @@ class CheckSumCalculator:
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class Md5CheckSumCalculator(CheckSumCalculator):
|
||||
class Md5CheckSumCalculator(FileCheckSumCalculator):
|
||||
|
||||
def __init__(self):
|
||||
self.name = "md5"
|
||||
@ -41,7 +41,7 @@ class Md5CheckSumCalculator(CheckSumCalculator):
|
||||
return result.hexdigest().upper()
|
||||
|
||||
|
||||
class Sha1CheckSumCalculator(CheckSumCalculator):
|
||||
class Sha1CheckSumCalculator(FileCheckSumCalculator):
|
||||
|
||||
def __init__(self):
|
||||
self.name = "sha1"
|
||||
@ -61,7 +61,7 @@ class Sha1CheckSumCalculator(CheckSumCalculator):
|
||||
return result.hexdigest().upper()
|
||||
|
||||
|
||||
class Sha256CheckSumCalculator(CheckSumCalculator):
|
||||
class Sha256CheckSumCalculator(FileCheckSumCalculator):
|
||||
|
||||
def __init__(self):
|
||||
self.name = "sha256"
|
||||
|
@ -35,6 +35,8 @@ CREATE TABLE User (
|
||||
CREATE TABLE User_canRead_Directory (
|
||||
username TEXT,
|
||||
directory_id INTEGER,
|
||||
PRIMARY KEY (username, directory_id)
|
||||
PRIMARY KEY (username, directory_id),
|
||||
FOREIGN KEY (username) REFERENCES User(username),
|
||||
FOREIGN KEY (directory_id) REFERENCES Directory(id)
|
||||
|
||||
)
|
||||
|
@ -1,2 +1,4 @@
|
||||
PIL
|
||||
simplejson
|
||||
flask
|
||||
flask_bcrypt
|
@ -1,4 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
rm test.db
|
||||
sqlite3 local_storage.db -init "database.sql"
|
@ -1,18 +1,17 @@
|
||||
from unittest import TestCase
|
||||
|
||||
from storage import LocalStorage, Directory, DuplicateDirectoryException
|
||||
from storage import LocalStorage, Directory, DuplicateDirectoryException, User
|
||||
|
||||
|
||||
class LocalStorageTest(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
||||
s = LocalStorage()
|
||||
s = LocalStorage("test_database.db")
|
||||
s.init_db("../database.sql")
|
||||
|
||||
def test_save_and_retrieve_dir(self):
|
||||
|
||||
storage = LocalStorage()
|
||||
storage = LocalStorage("test_database.db")
|
||||
|
||||
d = Directory("/some/directory", True, ["opt1", "opt2", "opt3"])
|
||||
|
||||
@ -23,19 +22,19 @@ class LocalStorageTest(TestCase):
|
||||
|
||||
def test_save_and_retrieve_dir_persistent(self):
|
||||
|
||||
s1 = LocalStorage()
|
||||
s1 = LocalStorage("test_database.db")
|
||||
|
||||
d = Directory("/some/directory", True, ["opt1", "opt2", "opt3"])
|
||||
|
||||
s1.save_directory(d)
|
||||
|
||||
s2 = LocalStorage()
|
||||
s2 = LocalStorage("test_database.db")
|
||||
self.assertEqual(s2.dirs()["/some/directory"].enabled, True)
|
||||
self.assertEqual(s2.dirs()["/some/directory"].options[0], "opt1")
|
||||
|
||||
def test_reject_duplicate_path(self):
|
||||
|
||||
s = LocalStorage()
|
||||
s = LocalStorage("test_database.db")
|
||||
|
||||
d1 = Directory("/some/directory", True, ["opt1", "opt2"])
|
||||
d2 = Directory("/some/directory", True, ["opt1", "opt2"])
|
||||
@ -45,3 +44,34 @@ class LocalStorageTest(TestCase):
|
||||
with self.assertRaises(DuplicateDirectoryException) as e:
|
||||
s.save_directory(d2)
|
||||
|
||||
def test_save_and_retrieve_user(self):
|
||||
|
||||
s = LocalStorage("test_database.db")
|
||||
|
||||
u = User("bob", "anHashedPassword", True)
|
||||
|
||||
s.save_user(u)
|
||||
|
||||
self.assertEqual(s.users()["bob"].username, "bob")
|
||||
self.assertEqual(s.users()["bob"].admin, True)
|
||||
|
||||
def test_return_none_with_unknown_user(self):
|
||||
|
||||
s = LocalStorage("test_database.db")
|
||||
|
||||
with self.assertRaises(KeyError) as e:
|
||||
_ = s.users()["unknown_user"]
|
||||
|
||||
def test_auth_user(self):
|
||||
|
||||
s = LocalStorage("test_database.db")
|
||||
|
||||
u = User("bob", b'$2b$14$VZEMbwAdy/HvLL/zh0.Iv.8XYnoZMz/LU9V4VKXLiuS.pthcUly2O', True)
|
||||
|
||||
s.save_user(u)
|
||||
|
||||
self.assertTrue(s.auth_user("bob", "test"))
|
||||
self.assertFalse(s.auth_user("bob", "wrong"))
|
||||
self.assertFalse(s.auth_user("wrong", "test"))
|
||||
|
||||
pass
|
||||
|
108
storage.py
108
storage.py
@ -1,11 +1,34 @@
|
||||
import sqlite3
|
||||
import os
|
||||
import flask_bcrypt
|
||||
|
||||
|
||||
class CheckSumCalculator:
|
||||
|
||||
def checksum(self, string: str):
|
||||
|
||||
return flask_bcrypt.generate_password_hash(string, 14) # todo load from config
|
||||
|
||||
|
||||
class DuplicateDirectoryException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class DuplicateUsernameException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class User:
|
||||
"""
|
||||
Data structure to hold user information
|
||||
"""
|
||||
|
||||
def __init__(self, username: str, hashed_password: bytes, admin: bool):
|
||||
self.username = username
|
||||
self.hashed_password = hashed_password
|
||||
self.admin = admin
|
||||
|
||||
|
||||
class Directory:
|
||||
"""
|
||||
Data structure to hold directory information
|
||||
@ -25,22 +48,20 @@ class LocalStorage:
|
||||
Could be refactored into a abstract class to switch from SQLite3 to something else
|
||||
"""
|
||||
|
||||
cache_outdated = True
|
||||
"""Static variable that indicates that the database was changed since the last time it was cached in memory"""
|
||||
|
||||
db_path = "../local_storage.db"
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, db_path):
|
||||
self.cached_dirs = {}
|
||||
self.cached_users = {}
|
||||
self.db_path = db_path
|
||||
self.dir_cache_outdated = True # Indicates that the database was changed since it was cached in memory
|
||||
self.user_cache_outdated = True
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def init_db(script_path):
|
||||
def init_db(self, script_path):
|
||||
"""Creates a blank database. Overwrites the old one"""
|
||||
if os.path.isfile(LocalStorage.db_path):
|
||||
os.remove(LocalStorage.db_path)
|
||||
if os.path.isfile(self.db_path):
|
||||
os.remove(self.db_path)
|
||||
|
||||
conn = sqlite3.connect(LocalStorage.db_path)
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
c = conn.cursor()
|
||||
with open(script_path, "r") as f:
|
||||
c.executescript(f.read())
|
||||
@ -56,9 +77,9 @@ class LocalStorage:
|
||||
:return: None
|
||||
"""
|
||||
|
||||
LocalStorage.cache_outdated = True
|
||||
self.dir_cache_outdated = True
|
||||
|
||||
conn = sqlite3.connect(LocalStorage.db_path)
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
c = conn.cursor()
|
||||
c.execute("PRAGMA FOREIGN_KEYS = ON;")
|
||||
try:
|
||||
@ -79,11 +100,11 @@ class LocalStorage:
|
||||
|
||||
def dirs(self):
|
||||
|
||||
if LocalStorage.cache_outdated:
|
||||
if self.dir_cache_outdated:
|
||||
|
||||
self.cached_dirs = {}
|
||||
|
||||
conn = sqlite3.connect(LocalStorage.db_path)
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
c = conn.cursor()
|
||||
c.execute("SELECT id, path, enabled FROM Directory")
|
||||
db_directories = c.fetchall()
|
||||
@ -100,8 +121,63 @@ class LocalStorage:
|
||||
options.append(db_opt[0])
|
||||
|
||||
self.cached_dirs[directory.path] = directory
|
||||
LocalStorage.cache_outdated = False
|
||||
self.dir_cache_outdated = False
|
||||
return self.cached_dirs
|
||||
|
||||
else:
|
||||
return self.cached_dirs
|
||||
|
||||
def save_user(self, user: User):
|
||||
"""Save user to storage"""
|
||||
|
||||
self.user_cache_outdated = True
|
||||
|
||||
try:
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
c = conn.cursor()
|
||||
c.execute("PRAGMA FOREIGN_KEYS = ON;")
|
||||
c.execute("INSERT INTO User (username, password, is_admin) VALUES (?,?,?)",
|
||||
(user.username, user.hashed_password, user.admin))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
except sqlite3.IntegrityError:
|
||||
raise DuplicateDirectoryException("Duplicate username: " + user.username)
|
||||
|
||||
def users(self):
|
||||
"""Get user list"""
|
||||
|
||||
if self.user_cache_outdated:
|
||||
|
||||
self.cached_users = {}
|
||||
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
c = conn.cursor()
|
||||
c.execute("SELECT username, is_admin FROM User")
|
||||
|
||||
db_users = c.fetchall()
|
||||
|
||||
for db_user in db_users:
|
||||
self.cached_users[db_user[0]] = User(db_user[0], "", db_user[1])
|
||||
|
||||
conn.close()
|
||||
|
||||
return self.cached_users
|
||||
|
||||
else:
|
||||
return self.cached_users
|
||||
|
||||
def auth_user(self, username: str, password: str) -> bool:
|
||||
"""Authenticates an user"""
|
||||
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
c = conn.cursor()
|
||||
c.execute("SELECT username, password FROM User WHERE username=?", (username,))
|
||||
|
||||
db_user = c.fetchone()
|
||||
|
||||
if db_user is not None:
|
||||
return flask_bcrypt.check_password_hash(db_user[1], password)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
|
@ -6,5 +6,8 @@
|
||||
</head>
|
||||
<body>
|
||||
|
||||
{% block body %}
|
||||
{% endblock body %}
|
||||
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user