From ef75228361a4717745e186315d8f73b799cdf546 Mon Sep 17 00:00:00 2001 From: Astatin3 <77305074+Astatin3@users.noreply.github.com> Date: Fri, 9 Feb 2024 18:52:05 -0700 Subject: [PATCH] Update - still working --- html/src/main.js | 4 +- html/src/packets.js | 3 ++ html/src/style.css | 22 ++++++-- html/src/utils.js | 48 ++++++++++++----- main.py | 6 +-- modules/chat/chat.html | 33 ++++++++++++ modules/chat/main.py | 12 +++++ modules/chat/module.json | 20 +++++++ modules/example/example.html | 11 ++++ modules/example/main.py | 12 +++++ modules/example/module.json | 20 +++++++ modules/main/Dashboard-copy.html | 1 - modules/main/adminSettings.html | 11 ++++ modules/main/main.py | 39 ++++++++++++-- modules/main/module.json | 27 +++++----- modules/main/programSettings.html | 11 ++++ modules/main/test.py | 2 - modules/main/userSettings.html | 86 +++++++++++++++++++++++++++++++ src/auth.py | 54 ++++++++++++++++--- src/modules.py | 45 ++++++++++++++-- src/utils.py | 12 ++--- src/web.py | 67 +++++++++++++----------- 22 files changed, 461 insertions(+), 85 deletions(-) create mode 100644 modules/chat/chat.html create mode 100644 modules/chat/main.py create mode 100644 modules/chat/module.json create mode 100644 modules/example/example.html create mode 100644 modules/example/main.py create mode 100644 modules/example/module.json delete mode 100644 modules/main/Dashboard-copy.html create mode 100644 modules/main/adminSettings.html create mode 100644 modules/main/programSettings.html delete mode 100644 modules/main/test.py create mode 100644 modules/main/userSettings.html diff --git a/html/src/main.js b/html/src/main.js index a9b7baa..12cb5f6 100755 --- a/html/src/main.js +++ b/html/src/main.js @@ -41,4 +41,6 @@ window.addListener('popupError', (data)=>{ window.addListener('popupColor', (data)=>{ window.utils.addPopup(data.data.color, data.data.isDark, data.data.title, data.data.msg) -}) \ No newline at end of file +}) + +window.main() \ No newline at end of file diff --git a/html/src/packets.js b/html/src/packets.js index de4782a..d9335e9 100755 --- a/html/src/packets.js +++ b/html/src/packets.js @@ -14,6 +14,7 @@ function getErrorDesc(error){ utils.setCookie('session', '') return 'Some part of the login request is invalid, please try again' case 'prelogin': + window.location.pathname = '/' return 'You are already logged in' } return error @@ -32,6 +33,8 @@ function processData(data){ utils.iconauth() } break + case 'redir': + window.location.pathname = data.location case 'data': console.log(data.data) break diff --git a/html/src/style.css b/html/src/style.css index a96af1b..f57e778 100755 --- a/html/src/style.css +++ b/html/src/style.css @@ -56,6 +56,21 @@ body { font-family: var(--font); } +.half-left { + position: relative; + display: inline-block; + width: 45%; + margin-right: calc(4%); +} + +.half-right { + position: relative; + display: inline-block; + width: 44%; + margin-left: 4%; +} + + .navbar { position: fixed; top:0; @@ -202,7 +217,7 @@ li::marker { width: var(--popupBoxWidth); height: calc(100% - var(--topnavheight) - 10px); - pointer-events:none; + pointer-events: none; bottom: 0; right: 20px; overflow: auto; @@ -225,7 +240,7 @@ li::marker { padding: 0; background-color: inherit; - pointer-events:all; + pointer-events: all; left: 0; margin: 0; @@ -254,10 +269,11 @@ li::marker { opacity: 1; } -.popupBox article a { +dialog article a { cursor: pointer; } + .popupBox article p { font-size: 15px; } diff --git a/html/src/utils.js b/html/src/utils.js index 07e15ba..6dc1bb0 100755 --- a/html/src/utils.js +++ b/html/src/utils.js @@ -1,3 +1,5 @@ +export const getEl = (id)=>{return document.getElementById(id)} + export const setCookie = (name, value, hours = 1, path = '/') => { const expires = new Date(Date.now() + hours * 6e4).toUTCString() document.cookie = `${name}=${encodeURIComponent(value)}; path=${path}; SameSite=None; secure=True; session=True` @@ -64,6 +66,21 @@ export function iconauth() { // } +export function modal(elem, identifier, bgcolor, header, textColor, title, innerHTML) { + elem.innerHTML += ` + +
+
+

${formatTime(getUnixTime())}

+ + ${title} +
+ ${innerHTML} +
+
+ ` +} + export function addPopup(bgcolor, isDark, title, content) { const elem = document.getElementById('popupBox') let header @@ -75,18 +92,8 @@ export function addPopup(bgcolor, isDark, title, content) { header = 'rgba(0,0,0,0.2)' textColor = 'text-black' } - elem.innerHTML += ` - -
-
-

${formatTime(getUnixTime())}

- - ${title} -
-

${content}

-
-
- ` + modal(elem, "document.getElementById('popupBox')", bgcolor, header, textColor, title, `

${content}

`) + } export function popupInfo(title, text){ @@ -105,12 +112,27 @@ export function popupError(title, text){ addPopup('#500000', true, title, text) } +export function confirmBox(bgcolor, isDark, title, yesFunc, noFunc) { + const elem = document.body + let header + let textColor + if(isDark){ + header = 'rgba(255,255,255,0.05)' + textColor = 'text-white' + }else{ + header = 'rgba(0,0,0,0.2)' + textColor = 'text-black' + } + modal(elem, 'document.body', bgcolor, header, textColor, title, ` + + `) +} export function getUnixTime() { return (+ new Date()) } -function formatTime(Millis){ +export function formatTime(Millis){ const date = new Date(Millis) if(date.getDate() != (new Date()).getDate()){ diff --git a/main.py b/main.py index 6a682db..eb8ddaa 100755 --- a/main.py +++ b/main.py @@ -16,13 +16,13 @@ def main(): if input("No credentials file was found, \nwould you like to create one? (Y/n): ").lower() in ["yes", "y", ""]: utils.writeFile('data/creds.json', utils.genDefaultAccounts()) - if webserv.secure and ( not utils.pathExists('data/selfsign.crt') or not utils.pathExists('data/selfsign.key') ): + if webserv.secure and ( not utils.pathExists('data/ssl.crt') or not utils.pathExists('data/ssl.key') ): if input("No ssl key/cert was found, \nwould you like to create them? (Y/n): ").lower() in ["yes", "y", ""]: - if not utils.pathExists('data/selfsign.key'): + if not utils.pathExists('data/ssl.key'): utils.genKey(utils.getRoot('data/')) - if not utils.pathExists('data/selfsign.crt'): + if not utils.pathExists('data/ssl.crt'): utils.genCert(utils.getRoot('data/')) moduleMaster.addModules(webserv) diff --git a/modules/chat/chat.html b/modules/chat/chat.html new file mode 100644 index 0000000..411c45c --- /dev/null +++ b/modules/chat/chat.html @@ -0,0 +1,33 @@ + + + + + + +

This is an example chat module

+
+ \ No newline at end of file diff --git a/modules/chat/main.py b/modules/chat/main.py new file mode 100644 index 0000000..b27a687 --- /dev/null +++ b/modules/chat/main.py @@ -0,0 +1,12 @@ +mm = None + +def test(ac, data): + mm.sendPopupColor(ac.rawClient, 'test!', 'test!', '#600060', True) + +def init(moduleMaster): + global mm + mm = moduleMaster + mm.addAuthEventListener('exampleTest', test) + +def main(): + pass \ No newline at end of file diff --git a/modules/chat/module.json b/modules/chat/module.json new file mode 100644 index 0000000..881a6d3 --- /dev/null +++ b/modules/chat/module.json @@ -0,0 +1,20 @@ +{ + "name": "chat", + "creators": ["ASTATIN3"], + "version": "1.0", + "entrypoint": "modules/chat/main.py", + "tabs": [ + { + "name": "chat", + "defaultPage": "chat", + "pages": [ + { + "type": "page", + "name": "chat", + "requiredPermGroup": "", + "location": "modules/chat/chat.html" + } + ] + } + ] +} \ No newline at end of file diff --git a/modules/example/example.html b/modules/example/example.html new file mode 100644 index 0000000..f23c222 --- /dev/null +++ b/modules/example/example.html @@ -0,0 +1,11 @@ +

This is a very simple example module!

+ + \ No newline at end of file diff --git a/modules/example/main.py b/modules/example/main.py new file mode 100644 index 0000000..b27a687 --- /dev/null +++ b/modules/example/main.py @@ -0,0 +1,12 @@ +mm = None + +def test(ac, data): + mm.sendPopupColor(ac.rawClient, 'test!', 'test!', '#600060', True) + +def init(moduleMaster): + global mm + mm = moduleMaster + mm.addAuthEventListener('exampleTest', test) + +def main(): + pass \ No newline at end of file diff --git a/modules/example/module.json b/modules/example/module.json new file mode 100644 index 0000000..3d21a3e --- /dev/null +++ b/modules/example/module.json @@ -0,0 +1,20 @@ +{ + "name": "example", + "creators": ["ASTATIN3"], + "version": "1.0", + "entrypoint": "modules/example/main.py", + "tabs": [ + { + "name": "example", + "defaultPage": "example", + "pages": [ + { + "type": "page", + "name": "example", + "requiredPermGroup": "", + "location": "modules/example/example.html" + } + ] + } + ] +} \ No newline at end of file diff --git a/modules/main/Dashboard-copy.html b/modules/main/Dashboard-copy.html deleted file mode 100644 index caa5726..0000000 --- a/modules/main/Dashboard-copy.html +++ /dev/null @@ -1 +0,0 @@ -

Test123123!

\ No newline at end of file diff --git a/modules/main/adminSettings.html b/modules/main/adminSettings.html new file mode 100644 index 0000000..1f00026 --- /dev/null +++ b/modules/main/adminSettings.html @@ -0,0 +1,11 @@ +

Test!

+ + \ No newline at end of file diff --git a/modules/main/main.py b/modules/main/main.py index fa1eb15..b1cc43a 100644 --- a/modules/main/main.py +++ b/modules/main/main.py @@ -1,14 +1,43 @@ -from modules.main import test as test - mm = None -def test1(ac, data): - mm.sendPopupColor(ac.rawClient, 'test!', 'test!', '#600060', True) +def logout(ac, data): + ac.send('redir', { + "location": "/" + }) + mm.authServer.unauth(ac) + +def loadSessions(ac): + obj = [] + for client in mm.authServer.clients: + if client.user != ac.user: + continue + obj.append({ + 'username': client.username, + 'address': client.rawClient.address, + 'currentPage': client.currentPage, + 'clientid': client.rawClient.clientid, + 'timeout': client.timeout + }) + # obj.append(client.session) + ac.send('sessions', obj) + +def unauth(ac, data): + removeClient = mm.getAuthClientByID(data['data']) + if removeClient == None: + return + if removeClient.user == ac.user: + removeClient.send('redir', { + "location": "/" + }) + mm.unauth(removeClient) + loadSessions(ac) def init(moduleMaster): global mm mm = moduleMaster - mm.addAuthEventListener('test1', test1) + mm.addAuthEventListener('logout', logout) + mm.addAuthEventListener('unauth', unauth) + mm.addPageEventListener('/main/User', loadSessions) def main(): pass \ No newline at end of file diff --git a/modules/main/module.json b/modules/main/module.json index b6f540c..18ac352 100644 --- a/modules/main/module.json +++ b/modules/main/module.json @@ -11,27 +11,30 @@ { "type": "page", "name": "dashboard", + "requiredPermGroup": "", "location": "modules/main/Dashboard.html" }, { "type": "folder", - "name": "folder 1", + "name": "Settings", "pages": [ { "type": "page", - "name": "dashboardcopy", - "location": "modules/main/Dashboard-copy.html" + "name": "User", + "requiredPermGroup": "", + "location": "modules/main/userSettings.html" }, { - "type": "folder", - "name": "folder 2", - "pages": [ - { - "type": "page", - "name": "dashboardcopy", - "location": "modules/main/Dashboard-copy.html" - } - ] + "type": "page", + "name": "Program", + "requiredPermGroup": "Admin", + "location": "modules/main/programSettings.html" + }, + { + "type": "page", + "name": "Admin", + "requiredPermGroup": "Admin", + "location": "modules/main/adminSettings.html" } ] } diff --git a/modules/main/programSettings.html b/modules/main/programSettings.html new file mode 100644 index 0000000..1f00026 --- /dev/null +++ b/modules/main/programSettings.html @@ -0,0 +1,11 @@ +

Test!

+ + \ No newline at end of file diff --git a/modules/main/test.py b/modules/main/test.py deleted file mode 100644 index bdcaa13..0000000 --- a/modules/main/test.py +++ /dev/null @@ -1,2 +0,0 @@ -def test(): - return "testsjdhgkjrhsgkhjertestsjdhgkjrhsgkhjertestsjdhgkjrhsgkhjer" \ No newline at end of file diff --git a/modules/main/userSettings.html b/modules/main/userSettings.html new file mode 100644 index 0000000..3985015 --- /dev/null +++ b/modules/main/userSettings.html @@ -0,0 +1,86 @@ +
+

User Settings

+

Sessions

+ + + + + + + + + + + +
UsernameAddressPathExpiresRemove
+ + +
+ + \ No newline at end of file diff --git a/src/auth.py b/src/auth.py index c508127..6c705ad 100755 --- a/src/auth.py +++ b/src/auth.py @@ -18,14 +18,16 @@ class authClient: def __init__(self): self.username = None self.session = utils.randID(32) - self.userData = None + self.currentPage = "/login" + self.user = None self.timeout = utils.getUnixTime() + (60 * 60 * 1000) self.loginTime = utils.getUnixTime() self.lastReauth = utils.getUnixTime() self.rawClient = None - def send(type, data): + + def send(self, type, data): self.rawClient.send(type, data) class authServer: @@ -37,6 +39,8 @@ class authServer: self.webserv = webserv + self.pageListeners = [] + self.reloadUsers() self.rawServer = webserv.rawServer self.initRawServer() @@ -67,13 +71,14 @@ class authServer: ac = authClient() ac.username = validAcc.username - ac.userData = validAcc + ac.user = validAcc ac.rawClient = c self.clients.append(ac) c.send('loginSuccess', { 'username': ac.username, + 'permGroups': ac.user.permGroups, 'session': ac.session, 'redir': f'/{self.webserv.defaultTab}/{self.webserv.defaultPage}', 'timeout': ac.timeout @@ -87,6 +92,8 @@ class authServer: def validAc(self, ac): if ac == None: return False + if not (ac in self.clients): + return False if ac.rawClient.address != request.remote_addr: return False if utils.getUnixTime() > ac.timeout: @@ -106,10 +113,16 @@ class authServer: ac.rawClient = c ac.lastReauth = utils.getUnixTime() - c.send('reauth', { - 'username': ac.username + ac.send('reauth', { + 'username': ac.username, + 'permGroups': ac.user.permGroups, + 'timeout': ac.timeout }) + for pageListener in self.pageListeners: + if pageListener['page'] == ac.currentPage: + pageListener['func'](ac) + def cookieLogin(self, request): session = request.cookies.get('session') if session == None: @@ -117,8 +130,37 @@ class authServer: ac = utils.getatribinarr(self.clients, 'session', session) - return self.validAc(ac) + if not self.validAc(ac): + return False + ac.currentPage = request.path + + return True + + def validPermGroup(self, group, request): + session = request.cookies.get('session') + if session == None: + return False, None + + ac = utils.getatribinarr(self.clients, 'session', session) + + if not self.validAc(ac): + return False, None + if (group != "") and not (group in ac.user.permGroups): + return False, None + return True, ac.user.permGroups + + # def validPermGroupfromSession(self, group, request): + + + # def logout(self, ac): + # if not self.validAc(ac): + # return False + # self.clients.remove(ac) + # return True + + def unauth(self, ac): + self.clients.remove(ac) def initRawServer(self): self.rawServer.addEventListener('login', self.login) diff --git a/src/modules.py b/src/modules.py index ece8362..4cc97cb 100644 --- a/src/modules.py +++ b/src/modules.py @@ -1,6 +1,7 @@ import json import importlib import sys +import multiprocessing as mupr import src.web as web import src.utils as utils @@ -9,6 +10,7 @@ class module(): def __init__(self): self.name = None self.module = None + self.proc = None self.rootdir = None self.tabs = [] @@ -19,10 +21,15 @@ class module(): self.module = module def init(self, moduleMaster): - self.module.init(moduleMaster) + self.module.init(moduleMaster) + self.proc = mupr.Process(target=self.module.main) def run(self): - self.module.main() + self.proc.start() + + def stop(self): + self.proc.stop() + class moduleMaster(): @@ -33,6 +40,9 @@ class moduleMaster(): self.app = None self.rawServer = None self.authServer = None + self.defaultPage = "" + self.vars = {} + # self.addRawEventListener('test1', test1) def addModules(self, webserv): @@ -67,6 +77,7 @@ class moduleMaster(): else: mpage = web.webpage() mpage.name = obj['name'] + mpage.requiredPermGroup = obj['requiredPermGroup'] mpage.location = obj['location'] tmpPages.append(mpage) return tmpPages @@ -83,8 +94,8 @@ class moduleMaster(): m.add() self.modules.append(m) - for tab in webserv.webtabs: - tab.addHtml() + # for tab in webserv.webtabs: + # tab.compileHtml('User') @@ -94,6 +105,8 @@ class moduleMaster(): self.rawServer = webserv.rawServer self.authServer = webserv.authServer + self.defaultPage = f'/{webserv.defaultTab}/{webserv.defaultPage}' + for module in self.modules: module.init(self) @@ -101,6 +114,11 @@ class moduleMaster(): for module in self.modules: module.run() + def runModules(self): + for module in self.modules: + module.run() + + @@ -139,6 +157,25 @@ class moduleMaster(): return None return utils.getatribinarr(self.authServer.clients, 'rawClient', c) + def addPageEventListener(self, page, func): + self.authServer.pageListeners.append({ + 'page': page, + 'func': func + }) + + + + def getVar(self, varName): + return self.vars[varname] + + def setVar(self, varName, val): + self.vars[varName] = val + + + def unauth(self, ac): + self.authServer.unauth(ac) + + def sendPopupInfo(self, c, title, msg): c.send('popupInfo', { 'title': title, diff --git a/src/utils.py b/src/utils.py index 5350188..c459e21 100755 --- a/src/utils.py +++ b/src/utils.py @@ -99,10 +99,10 @@ def genDefaultAccounts(): ], sort_keys=True, indent=2) def genKey(path): - subprocess.run(['openssl', 'genrsa', '-out', f'{path}selfsign.key', '2048']) + subprocess.run(['openssl', 'genrsa', '-out', f'{path}ssl.key', '2048']) def genCert(path): - writeFile(f'{path}/selfsign.cnf', + writeFile(f'{path}/ssl.cnf', """[req] default_bits = 2048 prompt = no @@ -117,8 +117,8 @@ OU = www.ca.local CN = Self-Signed Root CA """) - subprocess.run(['openssl', 'req', '-new', '-key', f'{path}selfsign.key', '-out', f'{path}selfsign.csr', '-config', f'{path}selfsign.cnf']) - subprocess.run(['openssl', 'x509', '-req', '-days', '36500', '-in', f'{path}selfsign.csr', '-signkey', f'{path}selfsign.key', '-out', f'{path}selfsign.crt']) + subprocess.run(['openssl', 'req', '-new', '-key', f'{path}ssl.key', '-out', f'{path}ssl.csr', '-config', f'{path}ssl.cnf']) + subprocess.run(['openssl', 'x509', '-req', '-days', '36500', '-in', f'{path}ssl.csr', '-signkey', f'{path}ssl.key', '-out', f'{path}ssl.crt']) - delFile(f'{path}selfsign.cnf') - delFile(f'{path}selfsign.csr') \ No newline at end of file + delFile(f'{path}ssl.cnf') + delFile(f'{path}ssl.csr') \ No newline at end of file diff --git a/src/web.py b/src/web.py index 7542ac6..74e7c59 100755 --- a/src/web.py +++ b/src/web.py @@ -23,24 +23,12 @@ class webtab(): self.defaultPage = '' self.html = '' - def recursiveAdder(self, objs): + def compileHtml(self, permGroups): html = '' - for obj in objs: - if isinstance(obj, webpagefolder): - html += '
' +\ - obj.name +\ - '
\n' - else: - html += f'
  • ' +\ - obj.name +\ - '
  • \n' + for page in self.pages: + html += page.compileHtml(self.name, permGroups) return html - def addHtml(self): - self.html = self.recursiveAdder(self.pages) - def addPage(self, page): self.pages.append(page) @@ -48,11 +36,28 @@ class webpagefolder(): def __init__(self): self.name = None self.pages = [] + + def compileHtml(self, tabname, permGroups): + html = '
    ' + self.name + '
    ' + return html class webpage(): def __init__(self): self.name = None + self.requiredPermGroup = '' self.location = None + + def compileHtml(self, tabname, permGroups): + html = '' +\ + self.name + else: + html += f'>{self.name}' + return html + '' @app.route('/') def index(): @@ -74,16 +79,16 @@ def loginPage(): .replace('', app.webserv.title) .replace('', '/login')) -def recursivePageLocationFinder(pagename, objs): +def recursivePageFinder(pagename, objs): returnVal = None for obj in objs: if isinstance(obj, webpagefolder): - tmp = recursivePageLocationFinder(pagename, obj.pages) + tmp = recursivePageFinder(pagename, obj.pages) if tmp != None: returnVal = tmp else: if obj.name == pagename: - returnVal = obj.location + returnVal = obj return returnVal @app.route('//') @@ -96,16 +101,23 @@ def page(tabname, pagename): try: tab = utils.getatribinarr(app.webserv.webtabs, 'name', tabname) - pageloc = recursivePageLocationFinder(pagename, tab.pages) + page = recursivePageFinder(pagename, tab.pages) + + # print(page.requiredPermGroup) + + isValid, permGroups = app.webserv.authServer.validPermGroup(page.requiredPermGroup, request) + + if not isValid: + return redirect(f'/{tab.name}/{tab.defaultPage}', code=302) return make_response(open(utils.getRoot('html/nav.html'), 'r').read() - .replace('', open(utils.getRoot(pageloc), 'r').read()) + .replace('', open(utils.getRoot(page.location), 'r').read()) .replace('', app.webserv.tabHtml) - .replace('', tab.html) + .replace('', tab.compileHtml(permGroups)) .replace('', app.webserv.title) .replace('', f'/{app.webserv.defaultTab}/{app.webserv.defaultPage}')) except: - return redirect("/login", code=302) + return redirect("/", code=302) @app.route('/src/') def src(file): @@ -138,7 +150,7 @@ class webserv(): if self.secure: dataroot = utils.getRoot("data/") - sslcontext = (f'{dataroot}selfsign.crt', f'{dataroot}selfsign.key') + sslcontext = (f'{dataroot}ssl.crt', f'{dataroot}ssl.key') else: sslcontext = None @@ -146,14 +158,11 @@ class webserv(): return f'{name}' for tab in self.webtabs: - self.tabHtml += tabHtml(f'/{tab.name}/{tab.defaultPage}', tab.name) if tab.name == self.defaultTab: + self.tabHtml = tabHtml(f'/{tab.name}/{tab.defaultPage}', tab.name) + self.tabHtml self.defaultPage = tab.defaultPage - - def testfunc1(ac, data): - print(ac) - print(data) - + else: + self.tabHtml += tabHtml(f'/{tab.name}/{tab.defaultPage}', tab.name) app.webserv = self self.app = app