building out databases and config files

This commit is contained in:
Phillip Tarrant 2020-08-12 21:33:36 -04:00
parent 2f12f95ab2
commit 85a69954ea
9 changed files with 188 additions and 18 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
**/logs **/logs
*.log *.log
*.sqlite
__pycache__/ __pycache__/
*.py[cod] *.py[cod]

View File

@ -17,6 +17,7 @@ logger = logging.getLogger(__name__)
try: try:
from OpenSSL import crypto from OpenSSL import crypto
from argon2 import PasswordHasher
except ModuleNotFoundError as e: except ModuleNotFoundError as e:
logger.critical("Import Error: Unable to load {} module".format(e, e.name)) logger.critical("Import Error: Unable to load {} module".format(e, e.name))
@ -29,23 +30,24 @@ class Helpers:
self.root_dir = os.path.abspath(os.path.curdir) self.root_dir = os.path.abspath(os.path.curdir)
self.config_dir = os.path.join(self.root_dir, 'app', 'config') self.config_dir = os.path.join(self.root_dir, 'app', 'config')
self.session_file = os.path.join(self.root_dir, 'session.lock') self.session_file = os.path.join(self.root_dir, 'session.lock')
self.settings_file = os.path.join(self.root_dir, 'config.ini')
self.webroot = os.path.join(self.root_dir, 'app', 'frontend') self.webroot = os.path.join(self.root_dir, 'app', 'frontend')
self.db_path = os.path.join(self.root_dir, 'app', 'config', 'commander.sqlite') self.db_path = os.path.join(self.root_dir, 'commander.sqlite')
self.passhasher = PasswordHasher()
self.exiting = False self.exiting = False
def get_setting(self, section, key): def get_setting(self, section, key):
config_file = os.path.join(self.config_dir, 'config.ini')
try: try:
our_config = configparser.ConfigParser() our_config = configparser.ConfigParser()
our_config.read(config_file) our_config.read(self.settings_file)
if our_config.has_option(section, key): if our_config.has_option(section, key):
return our_config[section][key] return our_config[section][key]
except Exception as e: except Exception as e:
logger.critical("Config File Error: Unable to read {} due to {}".format(config_file, e)) logger.critical("Config File Error: Unable to read {} due to {}".format(self.settings_file, e))
console.critical("Config File Error: Unable to read {} due to {}".format(config_file, e)) console.critical("Config File Error: Unable to read {} due to {}".format(self.settings_file, e))
return False return False
@ -82,6 +84,17 @@ class Helpers:
console.critical("Unable to create exit file!") console.critical("Unable to create exit file!")
sys.exit(1) sys.exit(1)
def encode_pass(self, password):
return self.passhasher.hash(password)
def verify_pass(self, password, currenthash):
try:
self.passhasher.verify(currenthash, password)
return True
except:
pass
return False
@staticmethod @staticmethod
def check_writeable(path: str): def check_writeable(path: str):
filename = os.path.join(path, "tempfile.txt") filename = os.path.join(path, "tempfile.txt")
@ -97,20 +110,20 @@ class Helpers:
return False return False
def ensure_logging_setup(self): def ensure_logging_setup(self):
log_file = os.path.join(os.path.curdir, 'app', 'logs', 'commander.log') log_file = os.path.join(os.path.curdir, 'logs', 'commander.log')
logger.info("Checking app directory writable") logger.info("Checking app directory writable")
writeable = self.check_writeable(os.path.join(os.path.curdir, 'app')) writeable = self.check_writeable(self.root_dir)
# if not writeable, let's bomb out # if not writeable, let's bomb out
if not writeable: if not writeable:
logger.critical("Unable to write to app directory!") logger.critical("Unable to write to {} directory!".format(self.root_dir))
sys.exit(1) sys.exit(1)
# ensure the log directory is there # ensure the log directory is there
try: try:
os.makedirs(os.path.join(os.path.curdir, 'app', 'logs')) os.makedirs(os.path.join(self.root_dir, 'logs'))
except Exception as e: except Exception as e:
pass pass
@ -121,9 +134,9 @@ class Helpers:
console.critical("Unable to open log file!") console.critical("Unable to open log file!")
sys.exit(1) sys.exit(1)
# del any old session.log file as this is a new session # del any old session.lock file as this is a new session
try: try:
os.remove(os.path.join(os.path.curdir, "app", "logs", "session.log")) os.remove(self.session_file)
except: except:
pass pass
@ -308,4 +321,5 @@ class Helpers:
""" """
return ''.join(random.choice(chars) for x in range(size)) return ''.join(random.choice(chars) for x in range(size))
helper = Helpers() helper = Helpers()

View File

@ -0,0 +1,103 @@
import sys
import logging
import datetime
from app.classes.shared.helpers import helper
from app.classes.shared.console import console
logger = logging.getLogger(__name__)
try:
from peewee import *
from playhouse.shortcuts import model_to_dict
except ModuleNotFoundError as e:
logger.critical("Import Error: Unable to load {} module".format(e, e.name))
console.critical("Import Error: Unable to load {} module".format(e, e.name))
sys.exit(1)
database = SqliteDatabase(helper.db_path, pragmas={
'journal_mode': 'wal',
'cache_size': -1024 * 10})
class BaseModel(Model):
class Meta:
database = database
class Users(BaseModel):
user_id = AutoField()
created = DateTimeField(default=datetime.datetime.now)
last_login = DateTimeField(default=datetime.datetime.now)
last_ip = CharField(default="")
username = CharField(default="")
password = CharField(default="")
enabled = BooleanField(default=True)
api_token = CharField(default="")
allowed_servers = CharField(default="[]")
class Meta:
table_name = "users"
class Host_Stats(BaseModel):
time = DateTimeField(default=datetime.datetime.now)
boot_time = CharField(default="")
cpu_usage = FloatField(default=0)
cpu_cores = IntegerField(default=0)
cpu_cur_freq = FloatField(default=0)
cpu_max_freq = FloatField(default=0)
mem_percent = FloatField(default=0)
mem_usage = CharField(default="")
mem_total = CharField(default="")
disk_percent = FloatField(default=0)
disk_usage = CharField(default="")
disk_total = CharField(default="")
class Meta:
table_name = "host_stats"
class Webhooks(BaseModel):
id = AutoField()
name = CharField(max_length=64, unique=True)
method = CharField(default="POST")
url = CharField(unique=True)
event = CharField(default="")
send_data = BooleanField(default=True)
class Meta:
table_name = "webhooks"
class Backups(BaseModel):
directories = CharField()
storage_location = CharField()
max_backups = IntegerField()
server_id = IntegerField()
class Meta:
table_name = 'backups'
class db_builder:
@staticmethod
def create_tables():
with database:
database.create_tables([
Backups,
Users,
Host_Stats,
Webhooks
])
def default_settings(self):
Users.insert({
Users.username: 'Admin',
Users.password: helper.encode_pass('asdfasdf'),
Users.api_token: helper.random_string_generator(32),
Users.enabled: True
}).execute()
installer = db_builder()

View File

@ -38,9 +38,12 @@ class PublicHandler(BaseHandler):
self.clear_cookie("user") self.clear_cookie("user")
self.clear_cookie("user_data") self.clear_cookie("user_data")
error = bleach.clean(self.get_argument('error', "")) # print(page)
template = "public/404.html"
if page is None:
self.redirect("public/login")
error = bleach.clean(self.get_argument('error', ""))
if error: if error:
error_msg = "Invalid Login!" error_msg = "Invalid Login!"
@ -57,3 +60,44 @@ class PublicHandler(BaseHandler):
self.render(template, data=context) self.render(template, data=context)
def post(self, page=None):
if page == 'login':
next_page = "/public/login"
entered_email = bleach.clean(self.get_argument('email'))
entered_password = bleach.clean(self.get_argument('password'))
user_data = Users.get_or_none(Users.email_address == entered_email)
# if we already have a user with this email...
if not user_data:
next_page = "/public/login?error=Login_Failed"
self.redirect(next_page)
return False
login_result = helper.verify_pass(entered_password, user_data.password)
# Valid Login
if login_result:
self.set_current_user(entered_email)
logger.info("User: {} Logged in from IP: {}".format(entered_email, self.get_remote_ip()))
Users.update({
Users.last_ip: self.get_remote_ip()
}).execute()
cookie_data = {
"user_email": user_data.email_address,
"user_id": user_data,
"account_type": str(user_data.account_type).upper(),
}
self.set_secure_cookie('user_data', json.dumps(cookie_data))
next_page = "/pro/dashboard"
self.redirect(next_page)
else:
self.redirect("/public/login")

View File

@ -84,7 +84,10 @@ class webserver:
debug_errors = helper.get_setting("WEB", 'show_errors') debug_errors = helper.get_setting("WEB", 'show_errors')
cookie_secret = helper.get_setting("WEB", 'cookie_secret') cookie_secret = helper.get_setting("WEB", 'cookie_secret')
if cookie_secret.lower == "random" or cookie_secret is False: if cookie_secret is False:
cookie_secret = helper.random_string_generator(32)
if cookie_secret.lower == "random":
cookie_secret = helper.random_string_generator(32) cookie_secret = helper.random_string_generator(32)
if not lang: if not lang:
@ -114,6 +117,7 @@ class webserver:
handlers = [ handlers = [
(r'/', PublicHandler), (r'/', PublicHandler),
(r'/public/(.*)', PublicHandler),
] ]
app = tornado.web.Application( app = tornado.web.Application(

View File

@ -17,7 +17,7 @@
"main_file_handler": { "main_file_handler": {
"class": "logging.handlers.RotatingFileHandler", "class": "logging.handlers.RotatingFileHandler",
"formatter": "commander", "formatter": "commander",
"filename": "app/logs/commander.log", "filename": "logs/commander.log",
"maxBytes": 5242880, "maxBytes": 5242880,
"backupCount": 20, "backupCount": 20,
"encoding": "utf8" "encoding": "utf8"
@ -25,7 +25,7 @@
"session_file_handler": { "session_file_handler": {
"class": "logging.handlers.RotatingFileHandler", "class": "logging.handlers.RotatingFileHandler",
"formatter": "commander", "formatter": "commander",
"filename": "app/logs/session.log", "filename": "logs/session.log",
"backupCount": 0, "backupCount": 0,
"encoding": "utf8" "encoding": "utf8"
} }

View File

@ -31,6 +31,7 @@
<img src="/static/assets/images/logo_long.jpg"> <img src="/static/assets/images/logo_long.jpg">
</div> </div>
<form action="/public/login" method="post"> <form action="/public/login" method="post">
{% raw xsrf_form_html() %}
<div class="form-group"> <div class="form-group">
<label class="label">Email</label> <label class="label">Email</label>
<div class="input-group"> <div class="input-group">

View File

@ -8,7 +8,7 @@ import logging.config
""" Our custom classes / pip packages """ """ Our custom classes / pip packages """
from app.classes.shared.console import console from app.classes.shared.console import console
from app.classes.shared.helpers import helper from app.classes.shared.helpers import helper
from app.classes.shared.models import installer
from app.classes.shared.tasks import tasks_manager from app.classes.shared.tasks import tasks_manager
def do_intro(): def do_intro():
@ -89,6 +89,9 @@ if __name__ == '__main__':
# this should always be last # this should always be last
tasks_manager.start_main_kill_switch_watcher() tasks_manager.start_main_kill_switch_watcher()
installer.create_tables()
installer.default_settings()
# our main loop # our main loop
while True: while True:
if tasks_manager.get_main_thread_run_status(): if tasks_manager.get_main_thread_run_status():