diff --git a/ref-test/app/__init__.py b/ref-test/app/__init__.py index 94f38df..629d0da 100644 --- a/ref-test/app/__init__.py +++ b/ref-test/app/__init__.py @@ -14,7 +14,6 @@ from .views import views from .quiz.views import quiz def create_app(): - app = Flask(__name__) app.config.from_object(Config()) app.wsgi_app = ProxyFix(app.wsgi_app, x_proto= 1, x_host= 1) diff --git a/ref-test/app/config.py b/ref-test/app/config.py index 26e214f..1218069 100644 --- a/ref-test/app/config.py +++ b/ref-test/app/config.py @@ -1,6 +1,7 @@ import os from dotenv import load_dotenv load_dotenv() +from pathlib import Path class Config(object): APP_HOST = '0.0.0.0' @@ -9,7 +10,7 @@ class Config(object): TESTING = False SECRET_KEY = os.getenv('SECRET_KEY') SESSION_COOKIE_SECURE = True - SQLALCHEMY_DATABASE_URI = 'sqlite:///data/database.db' + SQLALCHEMY_DATABASE_URI = f'sqlite:///{Path(DATA_FILE_DIRECTORY)}/database.db' SQLALCHEMY_TRACK_MODIFICATIONS = False MAIL_SERVER = os.getenv('MAIL_SERVER') diff --git a/ref-test/app/install.py b/ref-test/app/install.py index 2e0e51a..177d70a 100644 --- a/ref-test/app/install.py +++ b/ref-test/app/install.py @@ -12,12 +12,14 @@ from sqlalchemy_utils import database_exists, create_database def install_scripts(): if not path.isdir(f'./{data}'): mkdir(f'./{data}') + if not path.isfile(f'./{data}/.gitignore'): + with open(f'./{data}/.gitignore', 'a+') as file: file.write(f'*') if not path.isfile(f'./{data}/config.json'): save({}, 'config.json') if not path.isdir(f'./{data}/logs'): mkdir(f'./{data}/logs') if not path.isfile(f'./{data}/logs/users.log'): write('users.log', 'Log file created.') if not path.isfile(f'./{data}/logs/system.log'): write('system.log', 'Log file created.') - if not path.isfile(f'./{data}/logs/tests.log'): write('commands.log', 'Log file created.') - if not database_exists(Config.SQLALCHEMY_DATABASE_URI): + if not path.isfile(f'./{data}/logs/tests.log'): write('tests.log', 'Log file created.') + if not database_exists(Config.SQLALCHEMY_DATABASE_URI): create_database(Config.SQLALCHEMY_DATABASE_URI) write('system.log', 'No database found. Creating a new database.') with app.app_context(): db.create_all() diff --git a/ref-test/app/models/__init__.py b/ref-test/app/models/__init__.py index e69de29..994d8f1 100644 --- a/ref-test/app/models/__init__.py +++ b/ref-test/app/models/__init__.py @@ -0,0 +1,142 @@ +from ..modules import db +from ..tools.encryption import decrypt, encrypt +from ..tools.logs import write + +import secrets + +from flask import flash, jsonify, session +from flask.helpers import url_for +from flask_login import UserMixin, login_user, logout_user +from werkzeug.security import check_password_hash, generate_password_hash + +class User(UserMixin, db.Model): + id = db.Column(db.String(36), primary_key=True) + username = db.Column(db.String(128), nullable=False) + password = db.Column(db.String(128), nullable=False) + email = db.Column(db.String(128), nullable=False) + reset_token = db.Column(db.String(20), nullable=True) + verification_token = db.Column(db.String(20), nullable=True) + + def __repr__(self): + return f' was added with .' + + @property + def set_username(self): raise AttributeError('set_username is not a readable attribute.') + + set_username.setter + def set_username(self, username:str): self.username = encrypt(username) + + def get_username(self): return decrypt(self.username) + + @property + def set_password(self): raise AttributeError('set_password is not a readable attribute.') + + set_password.setter + def set_password(self, password:str): self.password = generate_password_hash(password, method="sha256") + + def verify_password(self, password:str): return check_password_hash(self.password, password) + + @property + def set_email(self): raise AttributeError('set_email is not a readable attribute.') + + set_email.setter + def set_email(self, email:str): self.email = encrypt(email) + + def get_email(self): return decrypt(self.email) + + def register(self): + users = User.query.all() + for user in users: + if user.get_username() == self.get_username(): + return False, f'Username {self.get_username()} already in use.' + elif user.get_email() == self.get_email(): + return False, f'Email address {self.get_email()} already in use.' + db.session.add(self) + db.session.commit() + write('users.log', f'User \'{self.get_username()}\' was created with id \'{self.id}\'.') + return True, f'User {self.get_username()} was created successfully.' + + def login(self, remember:bool=False): + self.authenticated = True + db.session.add(self) + db.session.commit() + login_user(self, remember = remember) + write('users.log', f'User \'{self.get_username()}\' has logged in.') + flash(message=f'Welcome {self.get_username()}', category='success') + + def logout(self): + self.authenticated = False + db.session.add(self) + db.session.commit() + session['remembered_username'] = self.get_username() + logout_user() + write('users.log', f'User \'{self.get_username()}\' has logged out.') + flash(message='You have successfully logged out.', category='success') + + def reset_password(self): + new_password = secrets.token_hex(12) + self.set_password(new_password) + self.reset_token = secrets.token_urlsafe(16) + self.verification_token = secrets.token_urlsafe(16) + db.session.commit() + print('Password', new_password) + print('Reset Token', self.reset_token) + print('Verification Token', self.verification_token) + print('Reset Link', f'{url_for("auth._reset", token=self.reset_token, verification=self.verification_token, _external=True)}') + return jsonify({'success': 'Your password reset link has been generated.'}), 200 + + def clear_reset_tokens(self): + self.reset_token = self.verification_token = None + db.session.commit() + + def delete(self): + username = self.get_username() + db.session.delete(self) + db.session.commit() + write('users.log', f'User \'{username}\' was deleted.') # TODO add current user + +class Device(db.Model): + id = db.Column(db.String(36), primary_key=True) + name = db.Column(db.String(128), nullable=False) + mac_address = db.Column(db.String(128), nullable=False) + ip_address = db.Column(db.String(128), nullable=False) + description = db.Column(db.String(250), nullable=True) + + @property + def set_name(self): raise AttributeError('set_name is not a readable attribute.') + + set_name.setter + def set_name(self, name:str): self.name = encrypt(name) + + def get_name(self): return decrypt(self.name) + + @property + def set_mac_address(self): raise AttributeError('set_mac_address is not a readable attribute.') + + set_mac_address.setter + def set_mac_address(self, mac_address:str): self.mac_address = encrypt(mac_address) + + def get_mac_address(self): return decrypt(self.mac_address) + + @property + def set_ip_address(self): raise AttributeError('set_ip_address is not a readable attribute.') + + set_ip_address.setter + def set_ip_address(self, ip_address:str): self.ip_address = encrypt(ip_address) + + def get_ip_address(self): return decrypt(self.ip_address) + + def add(self): + db.session.add(self) + db.session.commit() + write('commands.log', f'Device \'{self.get_name()}\' was added at the IP address \'{self.get_ip_address()}\' and the MAC address \'{self.get_mac_address()}\'.') + return True, f'Device {self.get_name()} was added.' + + def delete(self): + name = self.get_name() + ip_address = self.get_ip_address() + mac_address = self.get_mac_address() + db.session.delete(self) + db.session.commit() + write('commands.log', f'Device \'{name}\' with the IP address {ip_address} and MAC address {mac_address} was deleted.') + return True, f'Device {name} was deleted.' \ No newline at end of file diff --git a/ref-test/app/tools/encryption.py b/ref-test/app/tools/encryption.py new file mode 100644 index 0000000..1bc3362 --- /dev/null +++ b/ref-test/app/tools/encryption.py @@ -0,0 +1,19 @@ +from ..data import data +from cryptography.fernet import Fernet + +def load_key(): + with open(f'./{data}/.encryption.key', 'rb') as keyfile: return keyfile.read() + +def decrypt(input:str): + encryption_key = load_key() + fernet = Fernet(encryption_key) + input = input.encode() + output = fernet.decrypt(input) + return output.decode() + +def encrypt(input:str): + encryption_key = load_key() + fernet = Fernet(encryption_key) + input = input.encode() + output = fernet.encrypt(input) + return output.decode()