Update - still working

This commit is contained in:
Astatin3
2024-02-09 18:52:05 -07:00
parent 0ea56990de
commit ef75228361
22 changed files with 461 additions and 85 deletions
+2
View File
@@ -42,3 +42,5 @@ window.addListener('popupError', (data)=>{
window.addListener('popupColor', (data)=>{
window.utils.addPopup(data.data.color, data.data.isDark, data.data.title, data.data.msg)
})
window.main()
+3
View File
@@ -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
+19 -3
View File
@@ -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;
}
+35 -13
View File
@@ -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 += `
<dialog class="example ${textColor}" open>
<article style="background-color:${bgcolor};">
<header style="background-color:${header};">
<p class='noselect' style='font-size:10px;opacity:0.75'>${formatTime(getUnixTime())}</p>
<a class="close ${textColor}" onclick="${identifier}.removeChild(this.parentElement.parentElement.parentElement)"></a>
${title}
</header>
${innerHTML}
</article>
</dialog>
`
}
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 += `
<dialog class="example ${textColor}" open>
<article style="background-color:${bgcolor};">
<header style="background-color:${header};">
<p class='noselect' style='font-size:10px;opacity:0.75'>${formatTime(getUnixTime())}</p>
<a class="close ${textColor}" onclick="elem=document.getElementById('popupBox');elem.removeChild(this.parentElement.parentElement.parentElement)"></a>
${title}
</header>
<p class='${textColor}'>${content}</p>
</article>
</dialog>
`
modal(elem, "document.getElementById('popupBox')", bgcolor, header, textColor, title, `<p class='${textColor}'>${content}</p>`)
}
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, `
<button class="outline half-left" onclick="document.body.removeChild(this.parentElement.parentElement);${yesFunc}">Yes</button>
<button class="half-right" onclick="document.body.removeChild(this.parentElement.parentElement);${noFunc}">No</button>`)
}
export function getUnixTime() {
return (+ new Date())
}
function formatTime(Millis){
export function formatTime(Millis){
const date = new Date(Millis)
if(date.getDate() != (new Date()).getDate()){
+3 -3
View File
@@ -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)
+33
View File
@@ -0,0 +1,33 @@
<link rel="stylesheet" href="https://unpkg.com/xterm@4.11.0/css/xterm.css"/>
<script src="https://unpkg.com/xterm@4.11.0/lib/xterm.js"></script>
<script src="https://unpkg.com/xterm-addon-fit@0.5.0/lib/xterm-addon-fit.js"></script>
<script src="https://unpkg.com/xterm-addon-web-links@0.4.0/lib/xterm-addon-web-links.js"></script>
<script src="https://unpkg.com/xterm-addon-search@0.8.0/lib/xterm-addon-search.js"></script>
<h4>This is an example chat module</h4>
<div id="term"></div>
<script>
window.main = ()=>{
const term = new Terminal({
cursorBlink: true,
macOptionIsMeta: true,
scrollback: true,
});
const fit = new FitAddon.FitAddon()
term.loadAddon(fit)
term.loadAddon(new WebLinksAddon.WebLinksAddon())
term.loadAddon(new SearchAddon.SearchAddon())
term.open(utils.getEl("term"))
fit.fit()
term.onData((data) => {
term.write(data);
})
function resize(){fit.fit()}
window.onresize = resize
}
</script>
+12
View File
@@ -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
+20
View File
@@ -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"
}
]
}
]
}
+11
View File
@@ -0,0 +1,11 @@
<h4>This is a very simple example module!</h4>
<button id="testButton" onclick="testFunc()">test!</button>
<script>
function getel(el) {return document.getElementById(el)}
function testFunc() {
window.sendRaw('test1', {
data: 'test!'
})
}
</script>
+12
View File
@@ -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
+20
View File
@@ -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"
}
]
}
]
}
-1
View File
@@ -1 +0,0 @@
<p>Test123123!</p>
+11
View File
@@ -0,0 +1,11 @@
<p>Test!</p>
<button id="testButton" onclick="testFunc()">test!</button>
<script>
function getel(el) {return document.getElementById(el)}
function testFunc() {
window.sendRaw('test1', {
data: 'test!'
})
}
</script>
+34 -5
View File
@@ -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
+13 -10
View File
@@ -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": "Program",
"requiredPermGroup": "Admin",
"location": "modules/main/programSettings.html"
},
{
"type": "page",
"name": "dashboardcopy",
"location": "modules/main/Dashboard-copy.html"
}
]
"name": "Admin",
"requiredPermGroup": "Admin",
"location": "modules/main/adminSettings.html"
}
]
}
+11
View File
@@ -0,0 +1,11 @@
<p>Test!</p>
<button id="testButton" onclick="testFunc()">test!</button>
<script>
function getel(el) {return document.getElementById(el)}
function testFunc() {
window.sendRaw('test1', {
data: 'test!'
})
}
</script>
-2
View File
@@ -1,2 +0,0 @@
def test():
return "testsjdhgkjrhsgkhjertestsjdhgkjrhsgkhjertestsjdhgkjrhsgkhjer"
+86
View File
@@ -0,0 +1,86 @@
<main class="container">
<h3>User Settings</h3>
<p>Sessions</p>
<table role="grid">
<thead>
<tr>
<th scope="col">Username</th>
<th scope="col">Address</th>
<th scope="col">Path</th>
<th scope="col">Expires</th>
<th scope="col">Remove</th>
</tr>
</thead>
<tbody id="sessionTable"></tbody>
</table>
<button id="changePassword" onclick="changePassword()">Change Password</button>
<button id="logoutButton" onclick="promptLogout()">Logout</button>
</main>
<script>
function promptLogout() {
utils.confirmBox('var(--card-sectionning-background-color)', true, 'Are you sure you want to log out?', 'logout()', '')
}
function promptUnauth(clientid) {
utils.confirmBox('var(--card-sectionning-background-color)', true, 'Are you sure you want to log this session out?', `unauthClient('${clientid}')`, '')
}
function logout() {
window.sendRaw('logout', {})
utils.setCookie('session', '')
}
function unauthClient(id) {
window.sendRaw('unauth', id)
}
function changePassword() {
const elem = document.body
const bgcolor = 'var(--card-sectionning-background-color)'
const header = 'rgba(255,255,255,0.05)'
const textColor = 'text-white'
const title = "Change password"
utils.modal(elem, 'document.body',bgcolor, header, textColor, title, `
<input type="password" placeholder="Old Password"></input>
<input type="password" placeholder="New Password"></input>
<input type="password" placeholder="Retype new Password"></input>
<button>Submit</button>`)
}
window.main = ()=>{
const sessionTable = document.getElementById('sessionTable')
window.addListener("sessions", (data)=>{
sessions = data.data
let html = ""
for(let i=0;i<sessions.length;i++){
html += `
<tr>
<td>${sessions[i].username}</td>
<td>${sessions[i].address}</td>
<td>${sessions[i].currentPage}</td>
<td>${utils.formatTime(sessions[i].timeout)}</td>
<td><a href="#" onclick="promptUnauth('${sessions[i].clientid}')">Logout</a></td>
</tr>
`
}
sessionTable.innerHTML = html
})
}
</script>
<!--
#################################################
New Credentials - THESE ONLY WILL BE PRINTED ONCE
########
Username: User
Password: 67FFCdfb9dB827fB
########
Username: Admin
Password: eB0BB402900DfE5A
#################################################
-->
+48 -6
View File
@@ -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)
+40 -3
View File
@@ -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 = []
@@ -20,9 +22,14 @@ class module():
def init(self, 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,
+6 -6
View File
@@ -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')
delFile(f'{path}ssl.cnf')
delFile(f'{path}ssl.csr')
+38 -29
View File
@@ -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 += '<details><summary>' +\
obj.name +\
'</summary><ul>\n' +\
self.recursiveAdder(obj.pages) +\
'</ul></details>\n'
else:
html += f'<li onclick=\'window.location="/{self.name}/{obj.name}"\'>' +\
obj.name +\
'</li>\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)
@@ -49,11 +37,28 @@ class webpagefolder():
self.name = None
self.pages = []
def compileHtml(self, tabname, permGroups):
html = '<details><summary>' + self.name + '</summary><ul>'
for page in self.pages:
html += page.compileHtml(tabname, permGroups)
html += '</ul></details>'
return html
class webpage():
def __init__(self):
self.name = None
self.requiredPermGroup = ''
self.location = None
def compileHtml(self, tabname, permGroups):
html = '<li'
if self.requiredPermGroup == '' or (self.requiredPermGroup in permGroups):
html += f' onclick=\'window.location="/{tabname}/{self.name}"\'>' +\
self.name
else:
html += f'><del>{self.name}</del>'
return html + '</li>'
@app.route('/')
def index():
isValid = app.webserv.authServer.cookieLogin(request)
@@ -74,16 +79,16 @@ def loginPage():
.replace('<!--Place title here!!!-->', app.webserv.title)
.replace('<!--Place defaultPage here!!!-->', '/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('/<tabname>/<pagename>')
@@ -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('<!--Place body here!!!-->', open(utils.getRoot(pageloc), 'r').read())
.replace('<!--Place body here!!!-->', open(utils.getRoot(page.location), 'r').read())
.replace('<!--Place tabs here!!!-->', app.webserv.tabHtml)
.replace('<!--Place pages here!!!-->', tab.html)
.replace('<!--Place pages here!!!-->', tab.compileHtml(permGroups))
.replace('<!--Place title here!!!-->', app.webserv.title)
.replace('<!--Place defaultPage here!!!-->', f'/{app.webserv.defaultTab}/{app.webserv.defaultPage}'))
except:
return redirect("/login", code=302)
return redirect("/", code=302)
@app.route('/src/<file>')
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'<a href="{path}" role="button" class="outline topnav-button text-white">{name}</a>'
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