mirror of
https://github.com/Astatin3/Auto-Shodanner.git
synced 2026-06-08 16:18:09 -06:00
Very WIP
This commit is contained in:
Vendored
+15
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Python Debugger: Current File",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "./main.py",
|
||||||
|
"console": "integratedTerminal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2024 Astatin3
|
Copyright (c) 2023 Astatin3
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -1,2 +1,9 @@
|
|||||||
# Auto-Shodanner
|
# Polyboard
|
||||||
A tool to scrape Shodan
|
|
||||||
|
### A very dynamic dashboard, with many features
|
||||||
|
|
||||||
|
Polyboard is basically just a fancy dashboard template, but with a very extensible module system, and security features!
|
||||||
|
|
||||||
|
[Read the wiki!](https://github.com/Astatin3/Modulator/wiki)
|
||||||
|
|
||||||
|

|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"created": 1713223622034,
|
||||||
|
"id": "C9Be3ffc8bD4AAd5",
|
||||||
|
"passwordUpdated": 1713223622034,
|
||||||
|
"permGroups": [
|
||||||
|
"Users"
|
||||||
|
],
|
||||||
|
"sha256passwordhash": "3F76939A78A3A229B680159FE77E396034407EB5D6C3C6D478C83C9C89022085",
|
||||||
|
"username": "User"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"created": 1713223622034,
|
||||||
|
"id": "067A14d766fDa6D8",
|
||||||
|
"passwordUpdated": 1713223622034,
|
||||||
|
"permGroups": [
|
||||||
|
"Users",
|
||||||
|
"Admins"
|
||||||
|
],
|
||||||
|
"sha256passwordhash": "FE851A5602AC9769E24B4D09B24298877AB0C0BA4D9AE1DEBF1CD11935A46299",
|
||||||
|
"username": "Admin"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDWzCCAkMCFERTJjsw8qFSMc10A9A3SmqMHowpMA0GCSqGSIb3DQEBCwUAMGkx
|
||||||
|
CzAJBgNVBAYTAklEMSUwIwYDVQQKDBxMb2NhbCBEaWdpdGFsIENlcnQgQXV0aG9y
|
||||||
|
aXR5MRUwEwYDVQQLDAx3d3cuY2EubG9jYWwxHDAaBgNVBAMME1NlbGYtU2lnbmVk
|
||||||
|
IFJvb3QgQ0EwIBcNMjQwMzIwMTkxOTMzWhgPMjEyNDAyMjUxOTE5MzNaMGkxCzAJ
|
||||||
|
BgNVBAYTAklEMSUwIwYDVQQKDBxMb2NhbCBEaWdpdGFsIENlcnQgQXV0aG9yaXR5
|
||||||
|
MRUwEwYDVQQLDAx3d3cuY2EubG9jYWwxHDAaBgNVBAMME1NlbGYtU2lnbmVkIFJv
|
||||||
|
b3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxc2AUbcE9UDvQ
|
||||||
|
ba+WV3YY2TDrgodsv0FTAbCKQBgfqYcZroXVrYoyK9/8zOQ8k6lQT7fUOCAmjUCQ
|
||||||
|
77BKwFXnAZUeJc5ctnKYS9KZIW3JRA3Nc14tTXjRi+Xe1FMLTDWBE/1bYP4To56Y
|
||||||
|
e1+xq0I9Ojv0oUS4JYjFO9YWM1bZCBZsbUzv93zyY4v3P/Bjk02vGfsSqGZ5WmAc
|
||||||
|
q7Kz2luYfgmQ0X8h/ZYidGw9azGQEEu53VqGT1xlw4XHF/FxsUg0918JH1gzrBc4
|
||||||
|
yl1bWxV1TN8Ph5xLoeF8s0wTZgGLErn54ZwVvSZ8cqUTROv251PqXMu54z23HwxP
|
||||||
|
YjcddRNhAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAFAI/9cxxZqq95xs2WmnyUov
|
||||||
|
ks9lCJloON3g40cL4As+fTiTwsXA8ZEOiGex6OQ+A3/5hChpP/A95i43bba2QbK7
|
||||||
|
7eoQhMp7SEj5ybOhIhW0gUsyT449Pp4nl/tnylzyXKTnumPfpl3zmL1nlUadxNDV
|
||||||
|
7s4roFlNEfLM5ybEfYvjueo5lZecS/U07Ttqs7FM+YAtwx48b/a+wXGCSBbXlImb
|
||||||
|
Ar+Yy2jEEY+XARdzqns1HHJLaoi3y4K47pozXTfAHpE2GzBVLhWOxqpRGrxzO8X7
|
||||||
|
sa4cVhB15/brMFwBvnhUHi+fogrbVCEEvnzqj+aKQ7ISWATGCrirtV20Uw7jktA=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxc2AUbcE9UDvQ
|
||||||
|
ba+WV3YY2TDrgodsv0FTAbCKQBgfqYcZroXVrYoyK9/8zOQ8k6lQT7fUOCAmjUCQ
|
||||||
|
77BKwFXnAZUeJc5ctnKYS9KZIW3JRA3Nc14tTXjRi+Xe1FMLTDWBE/1bYP4To56Y
|
||||||
|
e1+xq0I9Ojv0oUS4JYjFO9YWM1bZCBZsbUzv93zyY4v3P/Bjk02vGfsSqGZ5WmAc
|
||||||
|
q7Kz2luYfgmQ0X8h/ZYidGw9azGQEEu53VqGT1xlw4XHF/FxsUg0918JH1gzrBc4
|
||||||
|
yl1bWxV1TN8Ph5xLoeF8s0wTZgGLErn54ZwVvSZ8cqUTROv251PqXMu54z23HwxP
|
||||||
|
YjcddRNhAgMBAAECggEAJWEFUyhPdUfqYZxJSWUBBnjxuhpTxo9/Bior8uNPcZP3
|
||||||
|
VmyR2pHks27Ujt7mEPCV0MoKEhUEiLpmaGFlBEoBjlih/ai/EH6KIxSNtx34j1Xb
|
||||||
|
hnSP2QEhuxo6ALc/CvkxqA/65X3H54Emzj3myXkmydjzejNiU1vstIdHMIP9/ldA
|
||||||
|
+ghiEv8MUPjheGa1M++Tyc0z0VP45wsaPKa10soku89IvgRs0sA+N6188iWJPeac
|
||||||
|
yvi9nYXDiSVDF/2bI20cXSVKapt15BUXHzWBjEFS99r+nD4H7IQfUU3+jMsVuwmz
|
||||||
|
9ZlIIAVG82d02pLS94FsK5fa54p0PEg4tidU4kGB8QKBgQDZhTe78VDh3mzeA9n5
|
||||||
|
Yxd/1XeGBBhDkxILeIwk1YlQ7Ii6cM6jIOZDt5ci3/5jBUvqPGQc7eq0iQRflANj
|
||||||
|
UOwe70fkRpNbkcZRDH/8/AgyhwjJDuyNUVzXegCoSa1zlNgoQ/T1qyLFL9ep1ApD
|
||||||
|
STn2lAIbPpPdTYde25K4e8+9pQKBgQDQ14hrROlp/dsA7hKnaulnf62EPA4s9/ky
|
||||||
|
uos/u7bNLj+DD6u5XF0MSRUqqbAFiRUSS+CFE9omQonZbDOO8X8y1g6U0PBy858P
|
||||||
|
4T/1kDVJPBPJ6XNtSEPRewFq3J/AYXXyd7ktUYYq6mOHsuAitd3Ou87bvM0EMrGa
|
||||||
|
KN+XFIAKDQKBgQCw/B/ZIAQ7g4r5KhEVRXc9YCccOAC2Gtg31SHSZpyP56VobZj0
|
||||||
|
SjSRLLQggDivwQN/1xtuHnc15bZVPk1zZch5cx//sRz9CKNgFtectETHN/ACB86Z
|
||||||
|
PXZZLL+ULj6fKKCoQoLx0Qk9gCvt1sVy8gXjh5IfMM+G5SocGHRM/xCMsQKBgBom
|
||||||
|
QrCbylY5MQjmxnMsEdmhxQo/ss6ypgNSFEmAqZz7Y3x3o9rr08LMC9hxstaemYLW
|
||||||
|
+V/wYmpT/oq436PQXUryPpUnrFPYaVxFqgqHagSnfxrTHl7ao5NBQaYtxdsC2Q/p
|
||||||
|
Kcig4pnRC3FcVnBCMWnHXllpRIp4BoD1CToTmQypAoGBALg2BbzMgg4pCIbC/cVw
|
||||||
|
H2Con5VRYc+uyOvoxiiXNJmhfkg9i5bYXtDFMFBAM0N2NDABIRgSZboSKWg+Bne9
|
||||||
|
CBFkN67+Q5mlNxBmvfZVEqZypxyReVrlijpNjG3tBayB2zonH1PLyl/ciKNGhFK8
|
||||||
|
/abtipqo94ece5zPnBXVHywv
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
+1450
File diff suppressed because it is too large
Load Diff
Executable
+26
@@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
<section>
|
||||||
|
<div class="container ubuntuMono">
|
||||||
|
<h4 class="noselect ubuntuMono"><!--Place title here!!!--> - Log in</h4>
|
||||||
|
<input id="usernamebox" name="username" placeholder="B0b5m1th" required>
|
||||||
|
<label for="username" class="noselect">Username</label>
|
||||||
|
<input type="password" class="form-control" id="passwordbox" name="password" placeholder="Password" value="" required>
|
||||||
|
<label for="password" class="noselect">Password</label>
|
||||||
|
|
||||||
|
<button onclick="submit()">Log in</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function submit(){
|
||||||
|
const usernamebox = utils.getel('usernamebox')
|
||||||
|
const passwordbox = utils.getel('passwordbox')
|
||||||
|
|
||||||
|
authLogin(usernamebox.value, passwordbox.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.main = ()=>{}
|
||||||
|
|
||||||
|
</script>
|
||||||
Executable
+33
@@ -0,0 +1,33 @@
|
|||||||
|
<html data-theme="dark">
|
||||||
|
<head>
|
||||||
|
<link href="/src/pico.min.css" rel="stylesheet">
|
||||||
|
<link href="/src/style.css" rel="stylesheet">
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="color-scheme" content="light dark" />
|
||||||
|
<title><!--Place title here!!!--></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar text-invert noselect">
|
||||||
|
<ul class="nav">
|
||||||
|
<!--Place tabs here!!!-->
|
||||||
|
<h2 class="navconntext text-invert" id="connecticon" onclick="window.location.reload()" style="cursor:pointer;">
|
||||||
|
Disconnected
|
||||||
|
</h2>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<div class="navpanel text-invert noselect">
|
||||||
|
<a href="<!--Place defaultPage here!!!-->" class="text-invert navTitle">
|
||||||
|
<!--Place title here!!!-->
|
||||||
|
</a>
|
||||||
|
<hr>
|
||||||
|
<!--Place pages here!!!-->
|
||||||
|
<hr>
|
||||||
|
</div>
|
||||||
|
<div class="maindiv">
|
||||||
|
<!--Place body here!!!-->
|
||||||
|
</div>
|
||||||
|
<div id="popupBox" class="popupBox"> </div>
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Executable
BIN
Binary file not shown.
Executable
+65
@@ -0,0 +1,65 @@
|
|||||||
|
import * as utils from '/src/utils.js'
|
||||||
|
import * as jsonpack from '/src/jsonpack.js'
|
||||||
|
|
||||||
|
let c = null
|
||||||
|
|
||||||
|
export function authClient(rawClient) {
|
||||||
|
c = this
|
||||||
|
this.username = null
|
||||||
|
this.permGroups = null
|
||||||
|
this.accountCreated = null
|
||||||
|
this.passwordUpdated = null
|
||||||
|
this.id = null
|
||||||
|
this.rawClient = rawClient
|
||||||
|
|
||||||
|
this.login = (username, password)=>{
|
||||||
|
const salt = utils.getUnixTime()
|
||||||
|
const key = (utils.sha256(
|
||||||
|
username +
|
||||||
|
utils.sha256(password) +
|
||||||
|
salt
|
||||||
|
))
|
||||||
|
//console.log(c.rawClient.send)
|
||||||
|
c.rawClient.send('login', {
|
||||||
|
data: key,
|
||||||
|
salt: salt
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.clidata = (data)=>{
|
||||||
|
const session = utils.getCookie('session')
|
||||||
|
if(session != ''){
|
||||||
|
this.rawClient.send('reauth', {
|
||||||
|
session: session
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loginSuccess = (data)=>{
|
||||||
|
utils.popupSuccess('Connection', 'Successfully logged in!')
|
||||||
|
utils.iconauth()
|
||||||
|
console.log(data.data.session)
|
||||||
|
if(data.data.session != null){
|
||||||
|
utils.setCookie('session', data.data.session)
|
||||||
|
}
|
||||||
|
window.location = data.data.redir
|
||||||
|
}
|
||||||
|
|
||||||
|
this.reauth = (data)=>{
|
||||||
|
|
||||||
|
this.username = data.data.username
|
||||||
|
this.id = data.data.id
|
||||||
|
this.permGroups = data.data.permGroups
|
||||||
|
this.accountCreated = data.data.created
|
||||||
|
this.passwordUpdated = data.data.passwordUpdated
|
||||||
|
|
||||||
|
if(window.location.pathname == "/login"){
|
||||||
|
utils.popupSuccess('Connection', 'Successfully logged in!')
|
||||||
|
}
|
||||||
|
utils.iconauth()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.rawClient.addRawTypeListener('clidata', this.clidata)
|
||||||
|
this.rawClient.addRawTypeListener('loginSuccess', this.loginSuccess)
|
||||||
|
this.rawClient.addRawTypeListener('reauth', this.reauth)
|
||||||
|
}
|
||||||
Executable
+559
@@ -0,0 +1,559 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013, Rodrigo González, Sapienlab All Rights Reserved.
|
||||||
|
Available via MIT LICENSE. See https://github.com/roro89/jsonpack/blob/master/LICENSE.md for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
var TOKEN_TRUE = -1;
|
||||||
|
var TOKEN_FALSE = -2;
|
||||||
|
var TOKEN_NULL = -3;
|
||||||
|
var TOKEN_EMPTY_STRING = -4;
|
||||||
|
var TOKEN_UNDEFINED = -5;
|
||||||
|
|
||||||
|
export function pack(json, options) {
|
||||||
|
|
||||||
|
// Canonizes the options
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
// A shorthand for debugging
|
||||||
|
var verbose = options.verbose || false;
|
||||||
|
|
||||||
|
verbose && console.log('Normalize the JSON Object');
|
||||||
|
|
||||||
|
// JSON as Javascript Object (Not string representation)
|
||||||
|
json = typeof json === 'string' ? this.JSON.parse(json) : json;
|
||||||
|
|
||||||
|
verbose && console.log('Creating a empty dictionary');
|
||||||
|
|
||||||
|
// The dictionary
|
||||||
|
var dictionary = {
|
||||||
|
strings : [],
|
||||||
|
integers : [],
|
||||||
|
floats : []
|
||||||
|
};
|
||||||
|
|
||||||
|
verbose && console.log('Creating the AST');
|
||||||
|
|
||||||
|
// The AST
|
||||||
|
var ast = (function recursiveAstBuilder(item) {
|
||||||
|
|
||||||
|
verbose && console.log('Calling recursiveAstBuilder with ' + this.JSON.stringify(item));
|
||||||
|
|
||||||
|
// The type of the item
|
||||||
|
var type = typeof item;
|
||||||
|
|
||||||
|
// Case 7: The item is null
|
||||||
|
if (item === null) {
|
||||||
|
return {
|
||||||
|
type : 'null',
|
||||||
|
index : TOKEN_NULL
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//add undefined
|
||||||
|
if (typeof item === 'undefined') {
|
||||||
|
return {
|
||||||
|
type : 'undefined',
|
||||||
|
index : TOKEN_UNDEFINED
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 1: The item is Array Object
|
||||||
|
if ( item instanceof Array) {
|
||||||
|
|
||||||
|
// Create a new sub-AST of type Array (@)
|
||||||
|
var ast = ['@'];
|
||||||
|
|
||||||
|
// Add each items
|
||||||
|
for (var i in item) {
|
||||||
|
|
||||||
|
if (!item.hasOwnProperty(i)) continue;
|
||||||
|
|
||||||
|
ast.push(recursiveAstBuilder(item[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// And return
|
||||||
|
return ast;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 2: The item is Object
|
||||||
|
if (type === 'object') {
|
||||||
|
|
||||||
|
// Create a new sub-AST of type Object ($)
|
||||||
|
var ast = ['$'];
|
||||||
|
|
||||||
|
// Add each items
|
||||||
|
for (var key in item) {
|
||||||
|
|
||||||
|
if (!item.hasOwnProperty(key))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ast.push(recursiveAstBuilder(key));
|
||||||
|
ast.push(recursiveAstBuilder(item[key]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// And return
|
||||||
|
return ast;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 3: The item empty string
|
||||||
|
if (item === '') {
|
||||||
|
return {
|
||||||
|
type : 'empty',
|
||||||
|
index : TOKEN_EMPTY_STRING
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 4: The item is String
|
||||||
|
if (type === 'string') {
|
||||||
|
|
||||||
|
// The index of that word in the dictionary
|
||||||
|
var index = _indexOf.call(dictionary.strings, item);
|
||||||
|
|
||||||
|
// If not, add to the dictionary and actualize the index
|
||||||
|
if (index == -1) {
|
||||||
|
dictionary.strings.push(_encode(item));
|
||||||
|
index = dictionary.strings.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the token
|
||||||
|
return {
|
||||||
|
type : 'strings',
|
||||||
|
index : index
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 5: The item is integer
|
||||||
|
if (type === 'number' && item % 1 === 0) {
|
||||||
|
|
||||||
|
// The index of that number in the dictionary
|
||||||
|
var index = _indexOf.call(dictionary.integers, item);
|
||||||
|
|
||||||
|
// If not, add to the dictionary and actualize the index
|
||||||
|
if (index == -1) {
|
||||||
|
dictionary.integers.push(_base10To36(item));
|
||||||
|
index = dictionary.integers.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the token
|
||||||
|
return {
|
||||||
|
type : 'integers',
|
||||||
|
index : index
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 6: The item is float
|
||||||
|
if (type === 'number') {
|
||||||
|
// The index of that number in the dictionary
|
||||||
|
var index = _indexOf.call(dictionary.floats, item);
|
||||||
|
|
||||||
|
// If not, add to the dictionary and actualize the index
|
||||||
|
if (index == -1) {
|
||||||
|
// Float not use base 36
|
||||||
|
dictionary.floats.push(item);
|
||||||
|
index = dictionary.floats.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the token
|
||||||
|
return {
|
||||||
|
type : 'floats',
|
||||||
|
index : index
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 7: The item is boolean
|
||||||
|
if (type === 'boolean') {
|
||||||
|
return {
|
||||||
|
type : 'boolean',
|
||||||
|
index : item ? TOKEN_TRUE : TOKEN_FALSE
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default
|
||||||
|
throw new Error('Unexpected argument of type ' + typeof (item));
|
||||||
|
|
||||||
|
})(json);
|
||||||
|
|
||||||
|
// A set of shorthands proxies for the length of the dictionaries
|
||||||
|
var stringLength = dictionary.strings.length;
|
||||||
|
var integerLength = dictionary.integers.length;
|
||||||
|
var floatLength = dictionary.floats.length;
|
||||||
|
|
||||||
|
verbose && console.log('Parsing the dictionary');
|
||||||
|
|
||||||
|
// Create a raw dictionary
|
||||||
|
var packed = dictionary.strings.join('|');
|
||||||
|
packed += '^' + dictionary.integers.join('|');
|
||||||
|
packed += '^' + dictionary.floats.join('|');
|
||||||
|
|
||||||
|
verbose && console.log('Parsing the structure');
|
||||||
|
|
||||||
|
// And add the structure
|
||||||
|
packed += '^' + (function recursiveParser(item) {
|
||||||
|
|
||||||
|
verbose && console.log('Calling a recursiveParser with ' + this.JSON.stringify(item));
|
||||||
|
|
||||||
|
// If the item is Array, then is a object of
|
||||||
|
// type [object Object] or [object Array]
|
||||||
|
if ( item instanceof Array) {
|
||||||
|
|
||||||
|
// The packed resulting
|
||||||
|
var packed = item.shift();
|
||||||
|
|
||||||
|
for (var i in item) {
|
||||||
|
|
||||||
|
if (!item.hasOwnProperty(i))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
packed += recursiveParser(item[i]) + '|';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (packed[packed.length - 1] === '|' ? packed.slice(0, -1) : packed) + ']';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// A shorthand proxies
|
||||||
|
var type = item.type, index = item.index;
|
||||||
|
|
||||||
|
if (type === 'strings') {
|
||||||
|
// Just return the base 36 of index
|
||||||
|
return _base10To36(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'integers') {
|
||||||
|
// Return a base 36 of index plus stringLength offset
|
||||||
|
return _base10To36(stringLength + index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'floats') {
|
||||||
|
// Return a base 36 of index plus stringLength and integerLength offset
|
||||||
|
return _base10To36(stringLength + integerLength + index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'boolean') {
|
||||||
|
return item.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'null') {
|
||||||
|
return TOKEN_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'undefined') {
|
||||||
|
return TOKEN_UNDEFINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'empty') {
|
||||||
|
return TOKEN_EMPTY_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new TypeError('The item is alien!');
|
||||||
|
|
||||||
|
})(ast);
|
||||||
|
|
||||||
|
verbose && console.log('Ending parser');
|
||||||
|
|
||||||
|
// If debug, return a internal representation of dictionary and stuff
|
||||||
|
if (options.debug)
|
||||||
|
return {
|
||||||
|
dictionary : dictionary,
|
||||||
|
ast : ast,
|
||||||
|
packed : packed
|
||||||
|
};
|
||||||
|
|
||||||
|
return packed;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
export function unpack(packed, options) {
|
||||||
|
|
||||||
|
// Canonizes the options
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
// A raw buffer
|
||||||
|
var rawBuffers = packed.split('^');
|
||||||
|
|
||||||
|
// Create a dictionary
|
||||||
|
options.verbose && console.log('Building dictionary');
|
||||||
|
var dictionary = [];
|
||||||
|
|
||||||
|
// Add the strings values
|
||||||
|
var buffer = rawBuffers[0];
|
||||||
|
if (buffer !== '') {
|
||||||
|
buffer = buffer.split('|');
|
||||||
|
options.verbose && console.log('Parse the strings dictionary');
|
||||||
|
for (var i=0, n=buffer.length; i<n; i++){
|
||||||
|
dictionary.push(_decode(buffer[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the integers values
|
||||||
|
buffer = rawBuffers[1];
|
||||||
|
if (buffer !== '') {
|
||||||
|
buffer = buffer.split('|');
|
||||||
|
options.verbose && console.log('Parse the integers dictionary');
|
||||||
|
for (var i=0, n=buffer.length; i<n; i++){
|
||||||
|
dictionary.push(_base36To10(buffer[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the floats values
|
||||||
|
buffer = rawBuffers[2];
|
||||||
|
if (buffer !== '') {
|
||||||
|
buffer = buffer.split('|')
|
||||||
|
options.verbose && console.log('Parse the floats dictionary');
|
||||||
|
for (var i=0, n=buffer.length; i<n; i++){
|
||||||
|
dictionary.push(parseFloat(buffer[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Free memory
|
||||||
|
buffer = null;
|
||||||
|
|
||||||
|
options.verbose && console.log('Tokenizing the structure');
|
||||||
|
|
||||||
|
// Tokenizer the structure
|
||||||
|
var number36 = '';
|
||||||
|
var tokens = [];
|
||||||
|
var len=rawBuffers[3].length;
|
||||||
|
for (var i = 0; i < len; i++) {
|
||||||
|
var symbol = rawBuffers[3].charAt(i);
|
||||||
|
if (symbol === '|' || symbol === '$' || symbol === '@' || symbol === ']') {
|
||||||
|
if (number36) {
|
||||||
|
tokens.push(_base36To10(number36));
|
||||||
|
number36 = '';
|
||||||
|
}
|
||||||
|
symbol !== '|' && tokens.push(symbol);
|
||||||
|
} else {
|
||||||
|
number36 += symbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A shorthand proxy for tokens.length
|
||||||
|
var tokensLength = tokens.length;
|
||||||
|
|
||||||
|
// The index of the next token to read
|
||||||
|
var tokensIndex = 0;
|
||||||
|
|
||||||
|
options.verbose && console.log('Starting recursive parser');
|
||||||
|
|
||||||
|
return (function recursiveUnpackerParser() {
|
||||||
|
|
||||||
|
// Maybe '$' (object) or '@' (array)
|
||||||
|
var type = tokens[tokensIndex++];
|
||||||
|
|
||||||
|
options.verbose && console.log('Reading collection type ' + (type === '$' ? 'object' : 'Array'));
|
||||||
|
|
||||||
|
// Parse an array
|
||||||
|
if (type === '@') {
|
||||||
|
|
||||||
|
var node = [];
|
||||||
|
|
||||||
|
for (; tokensIndex < tokensLength; tokensIndex++) {
|
||||||
|
var value = tokens[tokensIndex];
|
||||||
|
options.verbose && console.log('Read ' + value + ' symbol');
|
||||||
|
if (value === ']')
|
||||||
|
return node;
|
||||||
|
if (value === '@' || value === '$') {
|
||||||
|
node.push(recursiveUnpackerParser());
|
||||||
|
} else {
|
||||||
|
switch(value) {
|
||||||
|
case TOKEN_TRUE:
|
||||||
|
node.push(true);
|
||||||
|
break;
|
||||||
|
case TOKEN_FALSE:
|
||||||
|
node.push(false);
|
||||||
|
break;
|
||||||
|
case TOKEN_NULL:
|
||||||
|
node.push(null);
|
||||||
|
break;
|
||||||
|
case TOKEN_UNDEFINED:
|
||||||
|
node.push(undefined);
|
||||||
|
break;
|
||||||
|
case TOKEN_EMPTY_STRING:
|
||||||
|
node.push('');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
node.push(dictionary[value]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
options.verbose && console.log('Parsed ' + this.JSON.stringify(node));
|
||||||
|
|
||||||
|
return node;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse a object
|
||||||
|
if (type === '$') {
|
||||||
|
var node = {};
|
||||||
|
|
||||||
|
for (; tokensIndex < tokensLength; tokensIndex++) {
|
||||||
|
|
||||||
|
var key = tokens[tokensIndex];
|
||||||
|
|
||||||
|
if (key === ']')
|
||||||
|
return node;
|
||||||
|
|
||||||
|
if (key === TOKEN_EMPTY_STRING)
|
||||||
|
key = '';
|
||||||
|
else
|
||||||
|
key = dictionary[key];
|
||||||
|
|
||||||
|
var value = tokens[++tokensIndex];
|
||||||
|
|
||||||
|
if (value === '@' || value === '$') {
|
||||||
|
node[key] = recursiveUnpackerParser();
|
||||||
|
} else {
|
||||||
|
switch(value) {
|
||||||
|
case TOKEN_TRUE:
|
||||||
|
node[key] = true;
|
||||||
|
break;
|
||||||
|
case TOKEN_FALSE:
|
||||||
|
node[key] = false;
|
||||||
|
break;
|
||||||
|
case TOKEN_NULL:
|
||||||
|
node[key] = null;
|
||||||
|
break;
|
||||||
|
case TOKEN_UNDEFINED:
|
||||||
|
node[key] = undefined;
|
||||||
|
break;
|
||||||
|
case TOKEN_EMPTY_STRING:
|
||||||
|
node[key] = '';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
node[key] = dictionary[value];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
options.verbose && console.log('Parsed ' + this.JSON.stringify(node));
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new TypeError('Bad token ' + type + ' isn\'t a type');
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get the index value of the dictionary
|
||||||
|
* @param {Object} dictionary a object that have two array attributes: 'string' and 'number'
|
||||||
|
* @param {Object} data
|
||||||
|
*/
|
||||||
|
var _indexOfDictionary = function(dictionary, value) {
|
||||||
|
|
||||||
|
// The type of the value
|
||||||
|
var type = typeof value;
|
||||||
|
|
||||||
|
// If is boolean, return a boolean token
|
||||||
|
if (type === 'boolean')
|
||||||
|
return value ? TOKEN_TRUE : TOKEN_FALSE;
|
||||||
|
|
||||||
|
// If is null, return a... yes! the null token
|
||||||
|
if (value === null)
|
||||||
|
return TOKEN_NULL;
|
||||||
|
|
||||||
|
//add undefined
|
||||||
|
if (typeof value === 'undefined')
|
||||||
|
return TOKEN_UNDEFINED;
|
||||||
|
|
||||||
|
|
||||||
|
if (value === '') {
|
||||||
|
return TOKEN_EMPTY_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'string') {
|
||||||
|
value = _encode(value);
|
||||||
|
var index = _indexOf.call(dictionary.strings, value);
|
||||||
|
if (index === -1) {
|
||||||
|
dictionary.strings.push(value);
|
||||||
|
index = dictionary.strings.length - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If has an invalid JSON type (example a function)
|
||||||
|
if (type !== 'string' && type !== 'number') {
|
||||||
|
throw new Error('The type is not a JSON type');
|
||||||
|
};
|
||||||
|
|
||||||
|
if (type === 'string') {// string
|
||||||
|
value = _encode(value);
|
||||||
|
} else if (value % 1 === 0) {// integer
|
||||||
|
value = _base10To36(value);
|
||||||
|
} else {// float
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// If is number, "serialize" the value
|
||||||
|
value = type === 'number' ? _base10To36(value) : _encode(value);
|
||||||
|
|
||||||
|
// Retrieve the index of that value in the dictionary
|
||||||
|
var index = _indexOf.call(dictionary[type], value);
|
||||||
|
|
||||||
|
// If that value is not in the dictionary
|
||||||
|
if (index === -1) {
|
||||||
|
// Push the value
|
||||||
|
dictionary[type].push(value);
|
||||||
|
// And return their index
|
||||||
|
index = dictionary[type].length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the type is a number, then add the '+' prefix character
|
||||||
|
// to differentiate that they is a number index. If not, then
|
||||||
|
// just return a 36-based representation of the index
|
||||||
|
return type === 'number' ? '+' + index : index;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
var _encode = function(str) {
|
||||||
|
if ( typeof str !== 'string')
|
||||||
|
return str;
|
||||||
|
|
||||||
|
return str.replace(/[\+ \|\^\%]/g, function(a) {
|
||||||
|
return ({
|
||||||
|
' ' : '+',
|
||||||
|
'+' : '%2B',
|
||||||
|
'|' : '%7C',
|
||||||
|
'^' : '%5E',
|
||||||
|
'%' : '%25'
|
||||||
|
})[a]
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var _decode = function(str) {
|
||||||
|
if ( typeof str !== 'string')
|
||||||
|
return str;
|
||||||
|
|
||||||
|
return str.replace(/\+|%2B|%7C|%5E|%25/g, function(a) {
|
||||||
|
return ({
|
||||||
|
'+' : ' ',
|
||||||
|
'%2B' : '+',
|
||||||
|
'%7C' : '|',
|
||||||
|
'%5E' : '^',
|
||||||
|
'%25' : '%'
|
||||||
|
})[a]
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
var _base10To36 = function(number) {
|
||||||
|
return Number.prototype.toString.call(number, 36).toUpperCase();
|
||||||
|
};
|
||||||
|
|
||||||
|
var _base36To10 = function(number) {
|
||||||
|
return parseInt(number, 36);
|
||||||
|
};
|
||||||
|
|
||||||
|
var _indexOf = Array.prototype.indexOf ||
|
||||||
|
function(obj, start) {
|
||||||
|
for (var i = (start || 0), j = this.length; i < j; i++) {
|
||||||
|
if (this[i] === obj) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
Executable
+45
@@ -0,0 +1,45 @@
|
|||||||
|
import * as utils from "/src/utils.js"
|
||||||
|
import * as packets from "/src/packets.js"
|
||||||
|
import * as auth from "/src/auth.js"
|
||||||
|
import * as jsonpack from "/src/jsonpack.js"
|
||||||
|
|
||||||
|
const hostname = window.location.href.split('/')[2]
|
||||||
|
|
||||||
|
//import * as crypto from "/src/crypto-js.min.js"
|
||||||
|
|
||||||
|
let client = new packets.rawClient('/listen')
|
||||||
|
let authClient = new auth.authClient(client)
|
||||||
|
|
||||||
|
window.utils = utils
|
||||||
|
window.packets = packets
|
||||||
|
window.auth = auth
|
||||||
|
window.jsonpack = jsonpack
|
||||||
|
|
||||||
|
window.client = client
|
||||||
|
window.authClient = authClient
|
||||||
|
|
||||||
|
window.authLogin = authClient.login
|
||||||
|
window.send = client.send
|
||||||
|
window.addListener = client.addRawTypeListener
|
||||||
|
|
||||||
|
window.addListener('popupInfo', (data)=>{
|
||||||
|
window.utils.popupInfo(data.data.title, data.data.msg)
|
||||||
|
})
|
||||||
|
|
||||||
|
window.addListener('popupSuccess', (data)=>{
|
||||||
|
window.utils.popupSuccess(data.data.title, data.data.msg)
|
||||||
|
})
|
||||||
|
|
||||||
|
window.addListener('popupWarning', (data)=>{
|
||||||
|
window.utils.popupWarning(data.data.title, data.data.msg)
|
||||||
|
})
|
||||||
|
|
||||||
|
window.addListener('popupError', (data)=>{
|
||||||
|
window.utils.popupError(data.data.title, data.data.msg)
|
||||||
|
})
|
||||||
|
|
||||||
|
window.addListener('popupColor', (data)=>{
|
||||||
|
window.utils.addPopup(data.data.color, data.data.isDark, data.data.title, data.data.msg)
|
||||||
|
})
|
||||||
|
|
||||||
|
window.main()
|
||||||
Executable
+106
@@ -0,0 +1,106 @@
|
|||||||
|
import * as jsonpack from '/src/jsonpack.js'
|
||||||
|
import * as utils from "/src/utils.js"
|
||||||
|
|
||||||
|
|
||||||
|
let cID = null
|
||||||
|
let evListeners = []
|
||||||
|
let c = null
|
||||||
|
|
||||||
|
function getErrorDesc(error){
|
||||||
|
switch(error){
|
||||||
|
case 'invalidLogin':
|
||||||
|
return 'Invalid username or password'
|
||||||
|
case 'invalidLoginRequest':
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
function processData(data){
|
||||||
|
data = jsonpack.unpack(data)
|
||||||
|
switch(data.type){
|
||||||
|
case 'clidata':
|
||||||
|
c.cID = data.data.cid
|
||||||
|
if(window.location.pathname == "/login") {
|
||||||
|
utils.popupWarning('Connection', 'Connected to server!')
|
||||||
|
utils.iconunauth()
|
||||||
|
}else{
|
||||||
|
utils.popupInfo('Connection', 'Connected to server!')
|
||||||
|
utils.iconauth()
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'redir':
|
||||||
|
window.location.pathname = data.location
|
||||||
|
case 'data':
|
||||||
|
console.log(data.data)
|
||||||
|
break
|
||||||
|
case 'error':
|
||||||
|
utils.popupError(`Error: ${data.data}`, getErrorDesc(data.data))
|
||||||
|
}
|
||||||
|
for(let i=0;i<evListeners.length;i++){
|
||||||
|
const ev = evListeners[i]
|
||||||
|
if(ev.type == data.type){
|
||||||
|
ev.func(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function rawClient(loc) {
|
||||||
|
c = this
|
||||||
|
this.connected = false
|
||||||
|
this.location = loc
|
||||||
|
this.evtSource = new EventSource(loc);
|
||||||
|
|
||||||
|
this.onopen = ()=>{}
|
||||||
|
this.onclose = ()=>{}
|
||||||
|
|
||||||
|
this.cID = null
|
||||||
|
|
||||||
|
this.evtSource.onmessage = (event) => {
|
||||||
|
console.log(`Data: ${event.data}`)
|
||||||
|
processData(event.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.evtSource.onerror = (event) => {
|
||||||
|
console.log('Error!')
|
||||||
|
this.connected = false
|
||||||
|
utils.icondisconnect()
|
||||||
|
utils.popupError('Connection', 'Disconnected from server')
|
||||||
|
this.onclose()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.evtSource.onopen = (event) => {
|
||||||
|
console.log('Connected!')
|
||||||
|
this.connected = true
|
||||||
|
utils.iconunauth()
|
||||||
|
this.onopen()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.send = (type, data)=>{
|
||||||
|
//console.log({type, data})
|
||||||
|
fetch(this.location, {
|
||||||
|
method: "post",
|
||||||
|
headers: {
|
||||||
|
'Accept': '*',
|
||||||
|
'Content-Type': 'text/plain'
|
||||||
|
},
|
||||||
|
body: jsonpack.pack({
|
||||||
|
type: type,
|
||||||
|
data: data,
|
||||||
|
cid: this.cID
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addRawTypeListener = (type, func)=>{
|
||||||
|
evListeners.push({
|
||||||
|
type: type,
|
||||||
|
func: func
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
File diff suppressed because one or more lines are too long
Executable
+293
@@ -0,0 +1,293 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: "UbuntuMono";
|
||||||
|
src: url(/src/UbuntuMono-R.ttf) format("truetype");
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--topnavheight: 45px;
|
||||||
|
--sidenavwidth: 150px;
|
||||||
|
--popupBoxWidth: 300px;
|
||||||
|
|
||||||
|
--background-0: #212529;
|
||||||
|
--background-1: #404040;
|
||||||
|
|
||||||
|
--nav-color: rgba(0,0,0,0.3);
|
||||||
|
|
||||||
|
--text-0: #242424;
|
||||||
|
--text-1: #d3d3d3;
|
||||||
|
|
||||||
|
--text-black: #242424;
|
||||||
|
--text-white: var(--pico-primary-inverse);
|
||||||
|
|
||||||
|
--success-1:#059100;
|
||||||
|
--warning-1:#ffdc3e;
|
||||||
|
--error-1: #b60f0f;
|
||||||
|
|
||||||
|
--font: "UbuntuMono";
|
||||||
|
--pico-font-family: UbuntuMono, regular;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
font-family: var(--font) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
position:fixed;
|
||||||
|
right: 0;
|
||||||
|
height: 0;
|
||||||
|
overflow: scroll;
|
||||||
|
width: calc( 100vw - var(--sidenavwidth) + 32px );
|
||||||
|
height: calc( 100vh - var(--topnavheight) + 32px );
|
||||||
|
}
|
||||||
|
|
||||||
|
.maindiv {
|
||||||
|
position: fixed;
|
||||||
|
top: var(--topnavheight);
|
||||||
|
left: var(--sidenavwidth);
|
||||||
|
width: calc(100% - var(--sidenavwidth));
|
||||||
|
height: calc(100% - var(--topnavheight));
|
||||||
|
padding: 5px;
|
||||||
|
overflow: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-invert {
|
||||||
|
color: var(--pico-primary-inverse) !important;
|
||||||
|
font-family: var(--font);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* .text-black {
|
||||||
|
color: var(--text-black) !important;
|
||||||
|
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;
|
||||||
|
left:0;
|
||||||
|
right:0;
|
||||||
|
height:var(--topnavheight);
|
||||||
|
padding:5px;
|
||||||
|
padding-left: calc(var(--sidenavwidth) + 10px);
|
||||||
|
z-index: 10;
|
||||||
|
background-color: var(--nav-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar ul {
|
||||||
|
position: fixed;
|
||||||
|
top: calc(var(--topnavheight) * 0.1);
|
||||||
|
padding: 0px;
|
||||||
|
/* height: var(--topnavheight); */
|
||||||
|
height: calc(var(--topnavheight) * 0.8);
|
||||||
|
padding-right: calc(var(--topnavheight) * 2.8);
|
||||||
|
left: var(--sidenavwidth);
|
||||||
|
width: calc(100% - var(--sidenavwidth));
|
||||||
|
overflow-x: scroll;
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navpanel {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 24px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding-left: 14px;
|
||||||
|
|
||||||
|
|
||||||
|
position:fixed;
|
||||||
|
top: var(--topnavheight);
|
||||||
|
bottom:0;
|
||||||
|
left:0;
|
||||||
|
width: var(--sidenavwidth);
|
||||||
|
height:100%;
|
||||||
|
resize: left;
|
||||||
|
z-index: 20;
|
||||||
|
background-color: var(--nav-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navpanel details {
|
||||||
|
padding-bottom: 0px;
|
||||||
|
padding-left: 5px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navpanel summary {
|
||||||
|
font-size: 15px;
|
||||||
|
padding-top: 10px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
margin-bottom: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navpanel summary:hover {
|
||||||
|
color: var(--primary);
|
||||||
|
background-color: rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.navpanel ul {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.navpanel li {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-left: -5px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navpanel li:hover {
|
||||||
|
color: var(--primary);
|
||||||
|
background-color: rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
li::marker {
|
||||||
|
content: "- ";
|
||||||
|
padding-left: -20px;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.navconntext {
|
||||||
|
position: fixed;
|
||||||
|
font-size: calc(var(--topnavheight) * 0.3);
|
||||||
|
margin: calc((var(--topnavheight) * 0.25 * 0.75) - 5px);
|
||||||
|
background-color: rgba(255, 0, 0, 0.2);
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px !important;
|
||||||
|
border-color: #ff0000;
|
||||||
|
padding: 8px;
|
||||||
|
right:0;
|
||||||
|
top:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidenav-button {
|
||||||
|
width:100%;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topnav-button {
|
||||||
|
margin-left: 13px !important;
|
||||||
|
height: 100% !important;
|
||||||
|
|
||||||
|
font-size: calc( var(--topnavheight) * ( 3 / 9 ) );
|
||||||
|
line-height: calc( var(--topnavheight) * ( 3 / 9 ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.navTitle {
|
||||||
|
position: fixed;
|
||||||
|
margin-bottom: 1px;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: var(--sidenavwidth);
|
||||||
|
height: var(--topnavheight);
|
||||||
|
|
||||||
|
text-align:center;
|
||||||
|
line-height: var(--topnavheight);
|
||||||
|
|
||||||
|
text-decoration:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navTitle:hover {
|
||||||
|
background-color: rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.popupBox {
|
||||||
|
position: fixed;
|
||||||
|
|
||||||
|
/* display: flex;
|
||||||
|
box-sizing: content-box;
|
||||||
|
justify-content: flex-end;
|
||||||
|
flex-direction: column; */
|
||||||
|
|
||||||
|
width: var(--popupBoxWidth);
|
||||||
|
height: calc(100% - var(--topnavheight) - 10px);
|
||||||
|
pointer-events: none;
|
||||||
|
bottom: 0;
|
||||||
|
right: 20px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popupBox dialog {
|
||||||
|
display: flex;
|
||||||
|
z-index: inherit;
|
||||||
|
position: relative;
|
||||||
|
top: inherit;
|
||||||
|
right: inherit;
|
||||||
|
bottom: inherit;
|
||||||
|
left: inherit;
|
||||||
|
align-items: inherit;
|
||||||
|
justify-content: inherit;
|
||||||
|
width: inherit;
|
||||||
|
min-width: inherit;
|
||||||
|
height: auto;
|
||||||
|
min-height: inherit;
|
||||||
|
padding: 0;
|
||||||
|
background-color: inherit;
|
||||||
|
|
||||||
|
pointer-events: all;
|
||||||
|
|
||||||
|
left: 0;
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
justify-content:right;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popupBox article {
|
||||||
|
margin: 0;
|
||||||
|
opacity: 0.5;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popupBox header {
|
||||||
|
border: 0;
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 15px;
|
||||||
|
padding-top: 10px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popupBox article:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog article a {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.popupBox article p {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.noselect {
|
||||||
|
-webkit-touch-callout: none; /* iOS Safari */
|
||||||
|
-webkit-user-select: none; /* Safari */
|
||||||
|
-khtml-user-select: none; /* Konqueror HTML */
|
||||||
|
-moz-user-select: none; /* Old versions of Firefox */
|
||||||
|
-ms-user-select: none; /* Internet Explorer/Edge */
|
||||||
|
user-select: none; /* Non-prefixed version, currently
|
||||||
|
supported by Chrome, Edge, Opera and Firefox */
|
||||||
|
}
|
||||||
Executable
+274
@@ -0,0 +1,274 @@
|
|||||||
|
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`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getCookie = (name) => {
|
||||||
|
return document.cookie.split('; ').reduce((r, v) => {
|
||||||
|
const parts = v.split('=')
|
||||||
|
return parts[0] === name ? decodeURIComponent(parts[1]) : r
|
||||||
|
}, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function genID(length = 8){
|
||||||
|
// Declare all characters
|
||||||
|
let chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
|
||||||
|
// Pick characers randomly
|
||||||
|
let str = '';
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
str += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function icondisconnect() {
|
||||||
|
let icon = document.getElementById('connecticon')
|
||||||
|
icon.style.backgroundColor = "rgba(255, 0, 0, 0.2)"
|
||||||
|
icon.style.borderColor = "#ff0000"
|
||||||
|
icon.innerText = "Disconnected"
|
||||||
|
}
|
||||||
|
|
||||||
|
export function iconunauth() {
|
||||||
|
let icon = document.getElementById('connecticon')
|
||||||
|
icon.style.backgroundColor = "rgba(255, 255, 0, 0.2)"
|
||||||
|
icon.style.borderColor = "#ffff00"
|
||||||
|
icon.innerText = "Unauthenticated"
|
||||||
|
}
|
||||||
|
|
||||||
|
export function iconauth() {
|
||||||
|
let icon = document.getElementById('connecticon')
|
||||||
|
icon.style.backgroundColor = "rgba(0, 255, 0, 0.2)"
|
||||||
|
icon.style.borderColor = "#00ff00"
|
||||||
|
icon.innerText = "Authenticated"
|
||||||
|
}
|
||||||
|
|
||||||
|
// function addPopup(bgcolor, fgcolor, innerHTML) {
|
||||||
|
// const elem = document.getElementById('popupBox')
|
||||||
|
// const id = 'popup-'+genID(16)
|
||||||
|
// elem.innerHTML = `<div class="popup"
|
||||||
|
// class="popup"
|
||||||
|
// style="background-color: ${bgcolor};
|
||||||
|
// color: ${fgcolor}"
|
||||||
|
// id='${id}'
|
||||||
|
// onclick="elem=document.getElementById('${id}');elem.parentNode.removeChild(elem)">
|
||||||
|
// ${innerHTML}
|
||||||
|
// </div>` +
|
||||||
|
// elem.innerHTML
|
||||||
|
|
||||||
|
// setTimeout(()=>{
|
||||||
|
// elem.parentNode.removeChild(elem)
|
||||||
|
// }, 30000)
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
export function getatribinarr(arr, atribname, value){
|
||||||
|
for(let i=0;i<arr.length;i++){
|
||||||
|
if(arr[i][atribname] == value){
|
||||||
|
return arr[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export function modal(elem, 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 ${textColor}' style='font-size:10px;opacity:0.75'>${formatTime(getUnixTime())}</p>
|
||||||
|
<a class="close ${textColor}" onclick="this.parentElement.parentElement.parentElement.remove()"></a>
|
||||||
|
${title}
|
||||||
|
</header>
|
||||||
|
${innerHTML}
|
||||||
|
</article>
|
||||||
|
</dialog>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addPopup(bgcolor, isDark, title, content) {
|
||||||
|
const elem = document.getElementById('popupBox')
|
||||||
|
let header
|
||||||
|
let textColor
|
||||||
|
if(isDark){
|
||||||
|
header = 'rgba(255,255,255,0.05)'
|
||||||
|
textColor = "text-invert"
|
||||||
|
}else{
|
||||||
|
header = 'rgba(0,0,0,0.2)'
|
||||||
|
textColor = ""
|
||||||
|
}
|
||||||
|
modal(elem, bgcolor, header, textColor, title, `<p class='${textColor}'>${content}</p>`)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function popupInfo(title, text){
|
||||||
|
addPopup('var(--card-sectionning-background-color)', true, title, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function popupSuccess(title, text){
|
||||||
|
addPopup('#005000', true, title, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function popupWarning(title, text){
|
||||||
|
addPopup('#393900', true, title, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
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-invert"
|
||||||
|
}else{
|
||||||
|
header = 'rgba(0,0,0,0.2)'
|
||||||
|
textColor = ""
|
||||||
|
}
|
||||||
|
modal(elem, bgcolor, header, textColor, title, `
|
||||||
|
<button class="outline half-left" onclick="${yesFunc};document.body.removeChild(this.parentElement.parentElement)">Yes</button>
|
||||||
|
<button class="half-right" onclick="${noFunc};document.body.removeChild(this.parentElement.parentElement)">No</button>`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUnixTime() {
|
||||||
|
return (+ new Date())
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatTime(Millis){
|
||||||
|
const date = new Date(Millis)
|
||||||
|
|
||||||
|
if(date.getDate() != (new Date()).getDate()){
|
||||||
|
return date.getMonth()+1 + "/" + date.getDate() + "/" + date.getFullYear()
|
||||||
|
}else{
|
||||||
|
var Hour = ""
|
||||||
|
var Minute = ""
|
||||||
|
var AmPm = ""
|
||||||
|
|
||||||
|
if(date.getHours() == 0){
|
||||||
|
Hour = "12"
|
||||||
|
AmPm = "AM"
|
||||||
|
}else if(date.getHours() < 12){
|
||||||
|
Hour = date.getHours()
|
||||||
|
AmPm = "AM"
|
||||||
|
}else if(date.getHours() == 12){
|
||||||
|
Hour = "12"
|
||||||
|
AmPm = "PM"
|
||||||
|
}else{
|
||||||
|
Hour = date.getHours() - 12
|
||||||
|
AmPm = "PM"
|
||||||
|
}
|
||||||
|
|
||||||
|
if(date.getMinutes() < 10){
|
||||||
|
Minute = "0" + date.getMinutes()
|
||||||
|
}else{
|
||||||
|
Minute = date.getMinutes()
|
||||||
|
}
|
||||||
|
|
||||||
|
return Hour + ":" + Minute + " " + AmPm
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sha256(ascii) {
|
||||||
|
function rightRotate(value, amount) {
|
||||||
|
return (value>>>amount) | (value<<(32 - amount));
|
||||||
|
};
|
||||||
|
|
||||||
|
var mathPow = Math.pow;
|
||||||
|
var maxWord = mathPow(2, 32);
|
||||||
|
var lengthProperty = 'length'
|
||||||
|
var i, j; // Used as a counter across the whole file
|
||||||
|
var result = ''
|
||||||
|
|
||||||
|
var words = [];
|
||||||
|
var asciiBitLength = ascii[lengthProperty]*8;
|
||||||
|
|
||||||
|
//* caching results is optional - remove/add slash from front of this line to toggle
|
||||||
|
// Initial hash value: first 32 bits of the fractional parts of the square roots of the first 8 primes
|
||||||
|
// (we actually calculate the first 64, but extra values are just ignored)
|
||||||
|
var hash = sha256.h = sha256.h || [];
|
||||||
|
// Round constants: first 32 bits of the fractional parts of the cube roots of the first 64 primes
|
||||||
|
var k = sha256.k = sha256.k || [];
|
||||||
|
var primeCounter = k[lengthProperty];
|
||||||
|
/*/
|
||||||
|
var hash = [], k = [];
|
||||||
|
var primeCounter = 0;
|
||||||
|
//*/
|
||||||
|
|
||||||
|
var isComposite = {};
|
||||||
|
for (var candidate = 2; primeCounter < 64; candidate++) {
|
||||||
|
if (!isComposite[candidate]) {
|
||||||
|
for (i = 0; i < 313; i += candidate) {
|
||||||
|
isComposite[i] = candidate;
|
||||||
|
}
|
||||||
|
hash[primeCounter] = (mathPow(candidate, .5)*maxWord)|0;
|
||||||
|
k[primeCounter++] = (mathPow(candidate, 1/3)*maxWord)|0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ascii += '\x80' // Append Ƈ' bit (plus zero padding)
|
||||||
|
while (ascii[lengthProperty]%64 - 56) ascii += '\x00' // More zero padding
|
||||||
|
for (i = 0; i < ascii[lengthProperty]; i++) {
|
||||||
|
j = ascii.charCodeAt(i);
|
||||||
|
if (j>>8) return; // ASCII check: only accept characters in range 0-255
|
||||||
|
words[i>>2] |= j << ((3 - i)%4)*8;
|
||||||
|
}
|
||||||
|
words[words[lengthProperty]] = ((asciiBitLength/maxWord)|0);
|
||||||
|
words[words[lengthProperty]] = (asciiBitLength)
|
||||||
|
|
||||||
|
// process each chunk
|
||||||
|
for (j = 0; j < words[lengthProperty];) {
|
||||||
|
var w = words.slice(j, j += 16); // The message is expanded into 64 words as part of the iteration
|
||||||
|
var oldHash = hash;
|
||||||
|
// This is now the undefinedworking hash", often labelled as variables a...g
|
||||||
|
// (we have to truncate as well, otherwise extra entries at the end accumulate
|
||||||
|
hash = hash.slice(0, 8);
|
||||||
|
|
||||||
|
for (i = 0; i < 64; i++) {
|
||||||
|
var i2 = i + j;
|
||||||
|
// Expand the message into 64 words
|
||||||
|
// Used below if
|
||||||
|
var w15 = w[i - 15], w2 = w[i - 2];
|
||||||
|
|
||||||
|
// Iterate
|
||||||
|
var a = hash[0], e = hash[4];
|
||||||
|
var temp1 = hash[7]
|
||||||
|
+ (rightRotate(e, 6) ^ rightRotate(e, 11) ^ rightRotate(e, 25)) // S1
|
||||||
|
+ ((e&hash[5])^((~e)&hash[6])) // ch
|
||||||
|
+ k[i]
|
||||||
|
// Expand the message schedule if needed
|
||||||
|
+ (w[i] = (i < 16) ? w[i] : (
|
||||||
|
w[i - 16]
|
||||||
|
+ (rightRotate(w15, 7) ^ rightRotate(w15, 18) ^ (w15>>>3)) // s0
|
||||||
|
+ w[i - 7]
|
||||||
|
+ (rightRotate(w2, 17) ^ rightRotate(w2, 19) ^ (w2>>>10)) // s1
|
||||||
|
)|0
|
||||||
|
);
|
||||||
|
// This is only used once, so *could* be moved below, but it only saves 4 bytes and makes things unreadble
|
||||||
|
var temp2 = (rightRotate(a, 2) ^ rightRotate(a, 13) ^ rightRotate(a, 22)) // S0
|
||||||
|
+ ((a&hash[1])^(a&hash[2])^(hash[1]&hash[2])); // maj
|
||||||
|
|
||||||
|
hash = [(temp1 + temp2)|0].concat(hash); // We don't bother trimming off the extra ones, they're harmless as long as we're truncating when we do the slice()
|
||||||
|
hash[4] = (hash[4] + temp1)|0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
hash[i] = (hash[i] + oldHash[i])|0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
for (j = 3; j + 1; j--) {
|
||||||
|
var b = (hash[i]>>(j*8))&255;
|
||||||
|
result += ((b < 16) ? 0 : '') + b.toString(16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toUpperCase();
|
||||||
|
};
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import subprocess
|
||||||
|
import random
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
from threading import Thread
|
||||||
|
|
||||||
|
import src.utils as utils
|
||||||
|
|
||||||
|
threads = []
|
||||||
|
|
||||||
|
def start(settings):
|
||||||
|
global threads
|
||||||
|
utils.makeDir("data/scans")
|
||||||
|
|
||||||
|
|
||||||
|
for i in range(0,settings['numJobs']):
|
||||||
|
c = ScanTask()
|
||||||
|
t = Thread(target = c.run, args=(settings['maxPingTimeout'],))
|
||||||
|
t.start()
|
||||||
|
|
||||||
|
# def getStdout():
|
||||||
|
# global process
|
||||||
|
# return subprocess.check_output(process).decode()
|
||||||
|
# return "eee" + process.stdout.readline()
|
||||||
|
|
||||||
|
|
||||||
|
def stop():
|
||||||
|
global threads
|
||||||
|
for thread in threads:
|
||||||
|
thread.stop()
|
||||||
|
threads = []
|
||||||
|
print("\n\nstopped Scanner!")
|
||||||
|
|
||||||
|
|
||||||
|
def processStarted():
|
||||||
|
global threads
|
||||||
|
return len(threads) != 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ScanTask:
|
||||||
|
def __init__(self):
|
||||||
|
self.running = True
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
def run(self, maxPingTimeout):
|
||||||
|
while True:
|
||||||
|
address = socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff)))
|
||||||
|
|
||||||
|
pingCommand = f"ping {address} -c 1 -W {maxPingTimeout}"
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.check_output(pingCommand.split(" "))
|
||||||
|
# print(f"{address}: FOUND")
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
# print(f"{address}: FAIL")
|
||||||
|
continue
|
||||||
|
|
||||||
|
nmapCommand = f"sudo nmap {address} -O --send-eth --privileged -v -sS"
|
||||||
|
|
||||||
|
try:
|
||||||
|
print(subprocess.check_output(nmapCommand.split(" ")).decode())
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
continue
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import src.utils as utils
|
||||||
|
|
||||||
|
def countScannedIps():
|
||||||
|
files = utils.listSubdirs("data/")
|
||||||
|
count = 0
|
||||||
|
for file in files:
|
||||||
|
if file.split("-")[0] != "scan":
|
||||||
|
continue
|
||||||
|
with open('data/'+file) as f:
|
||||||
|
#Count lines in scan files, Masscan has a 2 line header, so hence -2
|
||||||
|
count += sum(1 for _ in f)-2
|
||||||
|
return count
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import subprocess
|
||||||
|
import random
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
from threading import Thread
|
||||||
|
|
||||||
|
maxPingTimeout = 3
|
||||||
|
|
||||||
|
class ScanTask:
|
||||||
|
def __init__(self):
|
||||||
|
self.running = True
|
||||||
|
|
||||||
|
def terminate(self):
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
while True:
|
||||||
|
address = socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff)))
|
||||||
|
|
||||||
|
pingCommand = f"ping {address} -c 1 -W {maxPingTimeout}"
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.check_output(pingCommand.split(" "))
|
||||||
|
# print(f"{address}: FOUND")
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
# print(f"{address}: FAIL")
|
||||||
|
continue
|
||||||
|
|
||||||
|
nmapCommand = f"sudo nmap {address} -O --send-eth --privileged -v -sS"
|
||||||
|
|
||||||
|
try:
|
||||||
|
print(subprocess.check_output(nmapCommand.split(" ")).decode())
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
threads = []
|
||||||
|
|
||||||
|
for i in range(0,500):
|
||||||
|
c = ScanTask()
|
||||||
|
t = Thread(target = c.run)
|
||||||
|
t.start()
|
||||||
|
# threads.push(c)
|
||||||
|
|
||||||
|
for thread in threads:
|
||||||
|
thread.join()
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
import src.web as web
|
||||||
|
import src.utils as utils
|
||||||
|
import src.modules as modules
|
||||||
|
from sys import argv
|
||||||
|
|
||||||
|
webserv = web.webserv()
|
||||||
|
moduleMaster = modules.moduleMaster()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
if not utils.pathExists('data'):
|
||||||
|
utils.makeDir('data')
|
||||||
|
|
||||||
|
if not utils.pathExists('data/creds.json'):
|
||||||
|
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/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/ssl.key'):
|
||||||
|
utils.genKey(utils.getRoot('data/'))
|
||||||
|
|
||||||
|
if not utils.pathExists('data/ssl.crt'):
|
||||||
|
utils.genCert(utils.getRoot('data/'))
|
||||||
|
|
||||||
|
moduleMaster.addModules(webserv)
|
||||||
|
webserv.init()
|
||||||
|
moduleMaster.initModules(webserv)
|
||||||
|
webserv.start()
|
||||||
|
moduleMaster.runModules()
|
||||||
|
|
||||||
|
# for m in modules:
|
||||||
|
# m.module.main()
|
||||||
|
|
||||||
|
def printHelp():
|
||||||
|
print("""
|
||||||
|
Modulator usage:
|
||||||
|
|
||||||
|
-h -? --help - Print this help information
|
||||||
|
-v --verbose - Print verbose information, default: false
|
||||||
|
-u --unsecure - Use http instead of https, default: false
|
||||||
|
-p --port <int> - Set port of the webserver, default: 80 or 44
|
||||||
|
-h --host <str> - Set host of the webserver, default: 0.0.0.0
|
||||||
|
|
||||||
|
--defaultTab <str> - Set the default tab on visit, default: 'main'
|
||||||
|
--title <str> - Set the title of the html pages, default: 'Modulator'
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
$ python3 ./main.py
|
||||||
|
$ python3 ./main.py -vo 127.0.0.1
|
||||||
|
$ python3 ./main.py -p 12345 -h 192.168.0.123
|
||||||
|
""")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
i = 1
|
||||||
|
|
||||||
|
while i < len(argv):
|
||||||
|
arg = argv[i]
|
||||||
|
sargs = list(arg)
|
||||||
|
if sargs[0] == '-' and sargs[1] == '-':
|
||||||
|
match arg:
|
||||||
|
case '--help':
|
||||||
|
printHelp()
|
||||||
|
exit()
|
||||||
|
case '--verbose':
|
||||||
|
webserv.verbose = True
|
||||||
|
i+=1; continue
|
||||||
|
case '--unsecure':
|
||||||
|
webserv.secure = False
|
||||||
|
if webserv.port == 443:
|
||||||
|
webserv.port = 80
|
||||||
|
i+=1; continue
|
||||||
|
case '--port':
|
||||||
|
webserv.port = int(argv[i+1])
|
||||||
|
i+=2; continue
|
||||||
|
case '--host':
|
||||||
|
webserv.host = str(argv[i+1])
|
||||||
|
i+=2; continue
|
||||||
|
case '--defaultTab':
|
||||||
|
webserv.defaultTab = str(argv[i+1])
|
||||||
|
i+=2; continue
|
||||||
|
case '--title':
|
||||||
|
webserv.title = str(argv[i+1])
|
||||||
|
i+=2; continue
|
||||||
|
elif sargs[0] == '-':
|
||||||
|
for sarg in sargs:
|
||||||
|
match sarg:
|
||||||
|
case 'h' | '?':
|
||||||
|
printHelp()
|
||||||
|
exit()
|
||||||
|
case 'v':
|
||||||
|
webserv.verbose = True
|
||||||
|
case 'u':
|
||||||
|
webserv.secure = False
|
||||||
|
if webserv.port == 443:
|
||||||
|
webserv.port = 80
|
||||||
|
case 'p':
|
||||||
|
webserv.port = int(argv[i+1])
|
||||||
|
i+=1; continue
|
||||||
|
case 'o':
|
||||||
|
webserv.host = str(argv[i+1])
|
||||||
|
i+=1; continue
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
main()
|
||||||
Executable
+19
@@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
|
||||||
|
<main class="container">
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
window.main = () => {
|
||||||
|
window.addListener('Scanner-Metrics', (data)=>{
|
||||||
|
document.getElementsByClassName("container")[0].innerHTML = `
|
||||||
|
<h1>Auto-Shodanner</h1>
|
||||||
|
<h3>Addresses Scanned: ${data.data.scanCount} (${data.data.scanCount/42949672.96}% Of the internet.)</h3>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
Executable
+248
@@ -0,0 +1,248 @@
|
|||||||
|
<main class="container">
|
||||||
|
<h3>User Settings</h3>
|
||||||
|
<h4>Users</h4>
|
||||||
|
<table role="grid">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">Username</th>
|
||||||
|
<th scope="col">Created</th>
|
||||||
|
<th scope="col">Pass Updated</th>
|
||||||
|
<th scope="col">Groups</th>
|
||||||
|
<th scope="col">Manage</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="userTable"></tbody>
|
||||||
|
</table>
|
||||||
|
<h4>Sessions</h4>
|
||||||
|
<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">Manage</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="sessionTable"></tbody>
|
||||||
|
</table>
|
||||||
|
<button onclick="addUser()">Add New User</button>
|
||||||
|
</main>
|
||||||
|
<script>
|
||||||
|
let userData = {}
|
||||||
|
|
||||||
|
function promptUnauth(clientid) {
|
||||||
|
utils.confirmBox('var(--card-sectionning-background-color)', true, 'Are you sure you want to log this session out?', `unauthSession('${clientid}')`, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
function unauthSession(id) {
|
||||||
|
window.send('unauth', id)
|
||||||
|
}
|
||||||
|
|
||||||
|
function addUser() {
|
||||||
|
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 = "Add user"
|
||||||
|
|
||||||
|
utils.modal(elem, bgcolor, header, textColor, title, `
|
||||||
|
<input autocomplete="new-password" id="username" placeholder="Username"></input>
|
||||||
|
<input autocomplete="new-password" id="groups" placeholder="User groups (Users, Admins, ...)"></input>
|
||||||
|
<input autocomplete="new-password" id="password1" type="password" placeholder="New Password"></input>
|
||||||
|
<input autocomplete="new-password" id="password2" type="password" placeholder="Retype new Password"></input>
|
||||||
|
<button class="outline half-left" onclick="this.parentElement.parentElement.remove()">Cancel</button>
|
||||||
|
<button class="half-right" onclick="addUserPrompt()">Submit</button>`)
|
||||||
|
// For some reason, after opening a second modal, the first one is not deleted.
|
||||||
|
// So I have to maually delete it using document.body.children[5].remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
function addUserPrompt() {
|
||||||
|
const username = utils.getel("username").value
|
||||||
|
const groups = utils.getel("groups").value
|
||||||
|
const password1 = utils.getel("password1").value
|
||||||
|
const password2 = utils.getel("password2").value
|
||||||
|
|
||||||
|
document.body.children[5].remove()
|
||||||
|
|
||||||
|
if(username == "" || password1 == "" || password2 == ""){
|
||||||
|
utils.popupError("Error", "Please fill out all areas of form")
|
||||||
|
return
|
||||||
|
}else if(password1 != password2){
|
||||||
|
utils.popupError("Error", "Passwords don't match")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = "Add user"
|
||||||
|
|
||||||
|
utils.modal(elem, bgcolor, header, textColor, title, `
|
||||||
|
<p>Are you sure you want to add this user?</p>
|
||||||
|
<p>Username: ${username}</p>
|
||||||
|
<p>Groups: ${groups}</p>
|
||||||
|
<p>Password: (hidden)</p>
|
||||||
|
<br>
|
||||||
|
<button class="outline half-left" onclick="addUserSubmit('${username}','${groups}','${password1}');this.parentElement.parentElement.remove()">Yes</button>
|
||||||
|
<button class="half-right" onclick="this.parentElement.parentElement.remove()">No</button>`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
function addUserSubmit(username, groups, password) {
|
||||||
|
client.send("addUserRequest", {
|
||||||
|
username: username,
|
||||||
|
groups: groups.split(", "),
|
||||||
|
password: utils.sha256(password)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function manageUser(id) {
|
||||||
|
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 = "Manage user"
|
||||||
|
|
||||||
|
utils.modal(elem, bgcolor, textColor, header, title, `
|
||||||
|
<button onclick="promptDisconnectSessions('${id}')">Disconnect all sessions</button>
|
||||||
|
<button onclick="promptChangePassword('${id}');this.parentElement.parentElement.remove()">Edit Password</button>
|
||||||
|
<button onclick="promptChangeGroups('${id}');this.parentElement.parentElement.remove()">Edit Groups</button>
|
||||||
|
<button onclick="promptRemoveUser('${id}');this.parentElement.parentElement.remove()">Delete</button>
|
||||||
|
<button class="outline" onclick="this.parentElement.parentElement.remove()">Cancel</button>
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function promptDisconnectSessions(id) {
|
||||||
|
document.body.children[5].remove()
|
||||||
|
utils.confirmBox('var(--card-sectionning-background-color)', true, 'Are you sure you want to disconnect all sessions for this user?', `disconnectSessions('${id}')`, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
function disconnectSessions(id) {
|
||||||
|
client.send("disconnectAllSessions", {
|
||||||
|
id: id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function promptChangePassword(id) {
|
||||||
|
document.body.children[5].remove()
|
||||||
|
|
||||||
|
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 = "Manage user"
|
||||||
|
|
||||||
|
utils.modal(elem, bgcolor, textColor, header, title, `
|
||||||
|
<input autocomplete="new-password" id="password1" type="password" placeholder="New Password"></input>
|
||||||
|
<input autocomplete="new-password" id="password2" type="password" placeholder="Retype new Password"></input>
|
||||||
|
<button class="outline half-left" onclick="this.parentElement.parentElement.remove()">Cancel</button>
|
||||||
|
<button class="half-right" onclick="changePassword('${id}')">Submit</button>
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function changePassword(id) {
|
||||||
|
const password1 = utils.getel("password1").value
|
||||||
|
const password2 = utils.getel("password2").value
|
||||||
|
|
||||||
|
document.body.children[5].remove()
|
||||||
|
|
||||||
|
if(password1 == "" || password2 == ""){
|
||||||
|
utils.popupError("Error", "Please fill out all areas of form")
|
||||||
|
return
|
||||||
|
}else if(password1 != password2){
|
||||||
|
utils.popupError("Error", "Passwords don't match")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
client.send("passwordChangeRequest", {
|
||||||
|
id: id,
|
||||||
|
new: utils.sha256(password1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function promptChangeGroups(id) {
|
||||||
|
document.body.children[5].remove()
|
||||||
|
|
||||||
|
const user = utils.getatribinarr(userData, 'id', id)
|
||||||
|
|
||||||
|
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 = "Edit groups"
|
||||||
|
|
||||||
|
utils.modal(elem, bgcolor, textColor, header, title, `
|
||||||
|
<input autocomplete="new-password" id="groups" placeholder="User groups (Users, Admins, ...)" value="${user.permGroups.join(", ")}"></input>
|
||||||
|
<button class="half-left" onclick="this.parentElement.parentElement.remove()">Cancel</button>
|
||||||
|
<button class="outline half-right" onclick="changeGroups('${id}')">Submit</button>
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeGroups(id) {
|
||||||
|
const groups = utils.getel("groups").value
|
||||||
|
|
||||||
|
document.body.children[5].remove()
|
||||||
|
|
||||||
|
if(groups == ""){
|
||||||
|
utils.popupError("Error", "Please fill out all areas of form")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
client.send("changeGroupsRequest", {
|
||||||
|
id: id,
|
||||||
|
groups: groups.split(", ")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function promptRemoveUser(id) {
|
||||||
|
document.body.children[5].remove()
|
||||||
|
utils.confirmBox('var(--card-sectionning-background-color)', true, 'Are you sure you want to remove this user?', `removeUser('${id}')`, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeUser(id) {
|
||||||
|
client.send("deleteUserRequest", {
|
||||||
|
id: id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
window.main = ()=>{
|
||||||
|
|
||||||
|
window.addListener("sessions", (data)=>{
|
||||||
|
users = data.data.users
|
||||||
|
html = ""
|
||||||
|
userData = users
|
||||||
|
for(let i=0;i<users.length;i++){
|
||||||
|
html += `
|
||||||
|
<tr>
|
||||||
|
<td>${users[i].username}</td>
|
||||||
|
<td>${utils.formatTime(users[i].created)}</td>
|
||||||
|
<td>${utils.formatTime(users[i].passwordUpdated)}</td>
|
||||||
|
<td>${users[i].permGroups.join(", ")}</td>
|
||||||
|
<td><a href="#" onclick="manageUser('${users[i].id}')">Manage</a></td>
|
||||||
|
</tr>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
utils.getel('userTable').innerHTML = html
|
||||||
|
|
||||||
|
sessions = data.data.sessions
|
||||||
|
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>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.getel('sessionTable').innerHTML = html
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
Executable
+206
@@ -0,0 +1,206 @@
|
|||||||
|
import libs.scanutils as scanutils
|
||||||
|
mm = None
|
||||||
|
|
||||||
|
def dashboardMetrics(ac):
|
||||||
|
ac.send('Scanner-Metrics', {
|
||||||
|
"scanCount": scanutils.countScannedIps()
|
||||||
|
})
|
||||||
|
|
||||||
|
def init(moduleMaster):
|
||||||
|
global mm
|
||||||
|
mm = moduleMaster
|
||||||
|
|
||||||
|
mm.addPageEventListener('/main/dashboard', dashboardMetrics)
|
||||||
|
|
||||||
|
# User settings
|
||||||
|
mm.addAuthEventListener('logout', logout)
|
||||||
|
mm.addAuthEventListener('unauth', unauth)
|
||||||
|
|
||||||
|
mm.addAuthEventListener('passwordChangeRequest', changePassword)
|
||||||
|
|
||||||
|
# Admin settings
|
||||||
|
mm.addAuthEventListener('addUserRequest', addUser)
|
||||||
|
mm.addAuthEventListener('disconnectAllSessions', disconnectAllSessions)
|
||||||
|
mm.addAuthEventListener('changeGroupsRequest', changeGroups)
|
||||||
|
mm.addAuthEventListener('deleteUserRequest', deleteUser)
|
||||||
|
# mm.addAuthEventListener('login', disconnectAllSessions)
|
||||||
|
|
||||||
|
mm.addPageEventListener('/main/User', loadSessions)
|
||||||
|
mm.addPageEventListener('/main/Admin', loadSessionsAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def logout(ac, data):
|
||||||
|
mm.unauth(ac)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def unauth(ac, data):
|
||||||
|
removeClient = mm.getAuthClientByID(data['data'])
|
||||||
|
if removeClient == None:
|
||||||
|
return
|
||||||
|
if removeClient.user != ac.user and not mm.userInGroup(ac, "Admins"):
|
||||||
|
mm.sendPopupError(ac.rawClient, "Error", "You are not authorised")
|
||||||
|
return
|
||||||
|
mm.unauth(removeClient)
|
||||||
|
mm.sendPopupSuccess(ac.rawClient, "Success", "Client removed!")
|
||||||
|
if(ac.currentPage == "/main/Admin" and mm.userInGroup(ac, "Admins")):
|
||||||
|
loadSessionsAdmin(ac)
|
||||||
|
else:
|
||||||
|
loadSessions(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 changePassword(ac, data):
|
||||||
|
# If the account is not an admin, and the username is the same, and the password is correct => Change password
|
||||||
|
# If the account is not an admin, and the username is the same, and the password not correct and => Incorrect Password
|
||||||
|
# If the account is not an admin, and the username is not the same => Access denied
|
||||||
|
# If the account is an admin, and the username is the same, and the password is correct => Change password
|
||||||
|
# If the account is an admin, and the username is the same, and the password is not correct => Incorrect Password
|
||||||
|
# If the account is an admin, and the username is not the same => Change password
|
||||||
|
|
||||||
|
isAdmin = mm.userInGroup(ac, 'Admins')
|
||||||
|
correctName = ac.user.id == data['data']['id']
|
||||||
|
|
||||||
|
|
||||||
|
if isAdmin and correctName and not 'old' in data['data']:
|
||||||
|
mm.sendPopupError(ac.rawClient, "Error", "You are not authorised")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
if isAdmin or correctName:
|
||||||
|
if not isAdmin and ac.user.sha256passwordhash != data['data']['old']:
|
||||||
|
mm.sendPopupError(ac.rawClient, "Error", "Incorrect Password")
|
||||||
|
return
|
||||||
|
elif isAdmin and correctName and ac.user.sha256passwordhash != data['data']['old']:
|
||||||
|
mm.sendPopupError(ac.rawClient, "Error", "Incorrect Password")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
mm.sendPopupError(ac.rawClient, "Error", "You are not authorised")
|
||||||
|
return
|
||||||
|
|
||||||
|
user = mm.getUserById(data['data']['id'])
|
||||||
|
if user == None:
|
||||||
|
mm.sendPopupError(ac.rawClient, "Error", "Invalid id")
|
||||||
|
return
|
||||||
|
|
||||||
|
mm.setUserPassword(user, data['data']['new'])
|
||||||
|
mm.sendPopupSuccess(ac.rawClient, "Success", "Password updated!")
|
||||||
|
|
||||||
|
if isAdmin:
|
||||||
|
loadSessionsAdmin(ac)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def loadSessionsAdmin(ac):
|
||||||
|
if not mm.userInGroup(ac, 'Admins'):
|
||||||
|
return
|
||||||
|
|
||||||
|
obj = {
|
||||||
|
'users': [],
|
||||||
|
'sessions': []
|
||||||
|
}
|
||||||
|
for client in mm.authServer.clients:
|
||||||
|
obj['sessions'].append({
|
||||||
|
'username': client.username,
|
||||||
|
'address': client.rawClient.address,
|
||||||
|
'currentPage': client.currentPage,
|
||||||
|
'clientid': client.rawClient.clientid,
|
||||||
|
'timeout': client.timeout
|
||||||
|
})
|
||||||
|
for user in mm.authServer.users:
|
||||||
|
obj['users'].append({
|
||||||
|
'username': user.username,
|
||||||
|
'permGroups': user.permGroups,
|
||||||
|
'id': user.id,
|
||||||
|
'created': user.created,
|
||||||
|
'passwordUpdated': user.passwordUpdated
|
||||||
|
})
|
||||||
|
ac.send('sessions', obj)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def addUser(ac, data):
|
||||||
|
if not mm.userInGroup(ac, 'Admins'):
|
||||||
|
mm.sendPopupError(ac.rawClient, "Error", "You are not authorised")
|
||||||
|
return
|
||||||
|
|
||||||
|
mm.addUser(
|
||||||
|
data['data']['username'],
|
||||||
|
data['data']['groups'],
|
||||||
|
data['data']['password'])
|
||||||
|
loadSessionsAdmin(ac)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def disconnectAllSessions(ac, data):
|
||||||
|
if not mm.userInGroup(ac, 'Admins'):
|
||||||
|
mm.sendPopupError(ac.rawClient, "Error", "You are not authorised")
|
||||||
|
return
|
||||||
|
|
||||||
|
user = mm.getUserById(data['data']['id'])
|
||||||
|
|
||||||
|
for client in mm.authServer.clients:
|
||||||
|
if client.user == user:
|
||||||
|
mm.unauth(client)
|
||||||
|
loadSessionsAdmin(ac)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def changeGroups(ac, data):
|
||||||
|
if not mm.userInGroup(ac, 'Admins'):
|
||||||
|
mm.sendPopupError(ac.rawClient, "Error", "You are not authorised")
|
||||||
|
return
|
||||||
|
|
||||||
|
user = mm.getUserById(data['data']['id'])
|
||||||
|
if user == None:
|
||||||
|
mm.sendPopupError(ac.rawClient, "Error", "Invalid id")
|
||||||
|
return
|
||||||
|
if user == ac.user:
|
||||||
|
mm.sendPopupError(ac.rawClient, "Error", "You are not authorised")
|
||||||
|
return
|
||||||
|
|
||||||
|
mm.setUserGroups(user, data['data']['groups'])
|
||||||
|
mm.sendPopupSuccess(ac.rawClient, "Success", "Groups updated!")
|
||||||
|
loadSessionsAdmin(ac)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def deleteUser(ac, data):
|
||||||
|
if not mm.userInGroup(ac, 'Admins'):
|
||||||
|
mm.sendPopupError(ac.rawClient, "Error", "You are not authorised")
|
||||||
|
return
|
||||||
|
|
||||||
|
user = mm.getUserById(data['data']['id'])
|
||||||
|
if user == None:
|
||||||
|
mm.sendPopupError(ac.rawClient, "Error", "Invalid id")
|
||||||
|
return
|
||||||
|
if user == ac.user:
|
||||||
|
mm.sendPopupError(ac.rawClient, "Error", "You are not authorised")
|
||||||
|
return
|
||||||
|
|
||||||
|
mm.deleteUser(user)
|
||||||
|
mm.sendPopupSuccess(ac.rawClient, "Success", "User deleted!")
|
||||||
|
loadSessionsAdmin(ac)
|
||||||
Executable
+38
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"name": "main",
|
||||||
|
"creators": ["ASTATIN3"],
|
||||||
|
"version": "1.0",
|
||||||
|
"entrypoint": "modules/main/main.py",
|
||||||
|
"tabs": [
|
||||||
|
{
|
||||||
|
"name": "main",
|
||||||
|
"defaultPage": "dashboard",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"type": "page",
|
||||||
|
"name": "dashboard",
|
||||||
|
"requiredPermGroup": "",
|
||||||
|
"location": "modules/main/Dashboard.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "folder",
|
||||||
|
"name": "Settings",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"type": "page",
|
||||||
|
"name": "User",
|
||||||
|
"requiredPermGroup": "",
|
||||||
|
"location": "modules/main/userSettings.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "page",
|
||||||
|
"name": "Admin",
|
||||||
|
"requiredPermGroup": "Admins",
|
||||||
|
"location": "modules/main/adminSettings.html"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Executable
+105
@@ -0,0 +1,105 @@
|
|||||||
|
<main class="container">
|
||||||
|
<h3>User Settings</h3>
|
||||||
|
<div id="details"></div>
|
||||||
|
<h4>Sessions</h4>
|
||||||
|
<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">Manage</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.send('logout', {})
|
||||||
|
utils.setCookie('session', '')
|
||||||
|
}
|
||||||
|
|
||||||
|
function unauthSession(id) {
|
||||||
|
window.send('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, bgcolor, header, textColor, title, `
|
||||||
|
<input id="oldPassword" type="password" placeholder="Old Password"></input>
|
||||||
|
<input autocomplete="new-password" id="password1" type="password" placeholder="New Password"></input>
|
||||||
|
<input autocomplete="new-password" id="password2" type="password" placeholder="Retype new Password"></input>
|
||||||
|
<button onclick="passwordSubmit();document.body.removeChild(this.parentElement.parentElement)">Submit</button>`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function passwordSubmit() {
|
||||||
|
const oldPassword = utils.getel("oldPassword").value
|
||||||
|
const password1 = utils.getel("password1").value
|
||||||
|
const password2 = utils.getel("password2").value
|
||||||
|
|
||||||
|
if(oldPassword == "" || password1 == "" || password2 == ""){
|
||||||
|
utils.popupError("Error", "Please fill out all areas of form")
|
||||||
|
return
|
||||||
|
}else if(password1 != password2){
|
||||||
|
utils.popupError("Error", "Passwords don't match")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
client.send("passwordChangeRequest", {
|
||||||
|
id: authClient.id,
|
||||||
|
old: utils.sha256(oldPassword),
|
||||||
|
new: utils.sha256(password1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
window.main = ()=>{
|
||||||
|
|
||||||
|
|
||||||
|
window.addListener("reauth", (data)=>{
|
||||||
|
let details = utils.getel('details')
|
||||||
|
|
||||||
|
details.innerHTML += "<p>Username: " + authClient.username + "</p>"
|
||||||
|
details.innerHTML += "<p>Groups: " + authClient.permGroups.join(", ") + "</p>"
|
||||||
|
details.innerHTML += "<p>Created: " + utils.formatTime(authClient.accountCreated) + "</p>"
|
||||||
|
details.innerHTML += "<p>Password Updated: " + utils.formatTime(authClient.passwordUpdated) + "</p>"
|
||||||
|
})
|
||||||
|
|
||||||
|
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="unauthSession('${sessions[i].clientid}')">Logout</a></td>
|
||||||
|
</tr>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
utils.getel('sessionTable').innerHTML = html
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
Executable
+46
@@ -0,0 +1,46 @@
|
|||||||
|
import libs.scanner as scan
|
||||||
|
import time
|
||||||
|
|
||||||
|
mm = None
|
||||||
|
|
||||||
|
|
||||||
|
def loadSettings(ac):
|
||||||
|
ac.send('Scanner-Settings', mm.vars['Scanner-Settings'])
|
||||||
|
|
||||||
|
|
||||||
|
def setSettings(ac, data):
|
||||||
|
mm.vars['Scanner-Settings'] = data['data']
|
||||||
|
|
||||||
|
|
||||||
|
def startScanner(ac, data):
|
||||||
|
scan.start(mm.vars['Scanner-Settings'])
|
||||||
|
|
||||||
|
|
||||||
|
def stopScanner(ac, data):
|
||||||
|
scan.stop()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def init(moduleMaster):
|
||||||
|
global mm
|
||||||
|
mm = moduleMaster
|
||||||
|
|
||||||
|
mm.vars['Scanner-Settings'] = {
|
||||||
|
"range": [[0,0,0,0], [255,255,255,255]],
|
||||||
|
"numJobs": 50,
|
||||||
|
"maxPingTimeout": 3,
|
||||||
|
"output": "./data/scan.txt"
|
||||||
|
}
|
||||||
|
|
||||||
|
mm.addPageEventListener('Scanner-LoadSettings', loadSettings)
|
||||||
|
|
||||||
|
mm.addAuthEventListener('Scanner-StartScanner', startScanner)
|
||||||
|
mm.addAuthEventListener('Scanner-StopScanner', stopScanner)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
while True:
|
||||||
|
if scan.processStarted():
|
||||||
|
print("eee")
|
||||||
|
# print(scan.getStdout())
|
||||||
|
# print("eee")
|
||||||
|
time.sleep(1)
|
||||||
Executable
+20
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "Scan",
|
||||||
|
"creators": ["ASTATIN3"],
|
||||||
|
"version": "1.0",
|
||||||
|
"entrypoint": "modules/scan/main.py",
|
||||||
|
"tabs": [
|
||||||
|
{
|
||||||
|
"name": "Scan",
|
||||||
|
"defaultPage": "Scan",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"type": "page",
|
||||||
|
"name": "Scan",
|
||||||
|
"requiredPermGroup": "",
|
||||||
|
"location": "modules/scan/scan.html"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Executable
+23
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
<main class="container">
|
||||||
|
<h4>This is a very simple example module!</h4>
|
||||||
|
<button class="half-left" onclick="startScanner()">Start Scanner</button>
|
||||||
|
<button class="half-right" onclick="stopScanner()">Stop Scanner</button>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.main = ()=>{
|
||||||
|
window.addListener('Scanner-LoadSettings', (data)=>{})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getel(el) {return document.getElementById(el)}
|
||||||
|
|
||||||
|
function startScanner() {
|
||||||
|
window.send('Scanner-StartScanner', {})
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopScanner() {
|
||||||
|
window.send('Scanner-StopScanner', {})
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
+150
@@ -0,0 +1,150 @@
|
|||||||
|
|
||||||
|
# resume information
|
||||||
|
resume-index = 275723
|
||||||
|
seed = 11690600974265531384
|
||||||
|
rate = 1000
|
||||||
|
shard = 1/1
|
||||||
|
nocapture = servername
|
||||||
|
|
||||||
|
output-filename = ./data/scan-1713225964108.txt
|
||||||
|
output-format = grepable
|
||||||
|
|
||||||
|
adapter-ip = 192.168.0.241
|
||||||
|
# TARGET SELECTION (IP, PORTS, EXCLUDES)
|
||||||
|
ports = 1,3-4,6-7,9,13,17,19-26,30,32-33,37,42-43,49,53,70,79-85,88-90,99-100,106,109-111,113,119,125,135,139,143-144,146,161,163,179,199,211-212,222,254-256,259,264,280,301,306,311,340,366,389,406-407,416-417,425,427,443-445,458,464-465,481,497,500,512-515,524,541,543-545,548,554-555,563,587,593,616-617,625,631,636,646,648,666-668,683,687,691,700,705,711,714,720,722,726,749,765,777,783,787,800-801,808,843,873,880,888,898,900-903,911-912,981,987,990,992-993,995,999-1002,1007,1009-1011,1021-1100,1102,1104-1108,1110-1114,1117,1119,1121-1124,1126,1130-1132,1137-1138,1141,1145,1147-1149,1151-1152,1154,1163-1166,1169,1174-1175,1183,1185-1187,1192,1198-1199,1201,1213,1216-1218,1233-1234,1236,1244,1247-1248,1259,1271-1272,1277,1287,1296,1300-1301,1309-1311,1322,1328,1334,1352,1417,1433-1434,1443,1455,1461,1494,1500-1501,1503,1521,1524,1533,1556,1580,1583,1594,1600,1641,1658,1666,1687-1688,1700,1717-1721,1723,1755,1761,1782-1783,1801,1805,1812,1839-1840,1862-1864,1875,1900,1914,1935,1947,1971-1972,1974,1984,1998-2010,2013,2020-2022,2030,2033-2035,2038,2040-2043,2045-2049,2065,2068,2099-2100,2103,2105-2107,2111,2119,2121,2126,2135,2144,2160-2161,2170,2179,2190-2191,2196,2200,2222,2251,2260,2288,2301,2323,2366,2381-2383,2393-2394,2399,2401,2492,2500,2522,2525,2557,2601-2602,2604-2605,2607-2608,2638,2701-2702,2710,2717-2718,2725,2800,2809,2811,2869,2875,2909-2910,2920,2967-2968,2998,3000-3001,3003,3005-3007,3011,3013,3017,3030-3031,3052,3071,3077,3128,3168,3211,3221,3260-3261,3268-3269,3283,3300-3301,3306,3322-3325,3333,3351,3367,3369-3372,3389-3390,3404,3476,3493,3517,3527,3546,3551,3580,3659,3689-3690,3703,3737,3766,3784,3800-3801,3809,3814,3826-3828,3851,3869,3871,3878,3880,3889,3905,3914,3918,3920,3945,3971,3986,3995,3998,4000-4006,4045,4111,4125-4126,4129,4224,4242,4279,4321,4343,4443-4446,4449,4550,4567,4662,4848,4899-4900,4998,5000-5004,5009,5030,5033,5050-5051,5054,5060-5061,5080,5087,5100-5102,5120,5190,5200,5214,5221-5222,5225-5226,5269,5280,5298,5357,5405,5414,5431-5432,5440,5500,5510,5544,5550,5555,5560,5566,5631,5633,5666,5678-5679,5718,5730,5800-5802,5810-5811,5815,5822,5825,5850,5859,5862,5877,5900-5904,5906-5907,5910-5911,5915,5922,5925,5950,5952,5959-5963,5987-5989,5998-6007,6009,6025,6059,6100-6101,6106,6112,6123,6129,6156,6346,6389,6502,6510,6543,6547,6565-6567,6580,6646,6666-6669,6689,6692,6699,6779,6788-6789,6792,6839,6881,6901,6969,7000-7002,7004,7007,7019,7025,7070,7100,7103,7106,7200-7201,7402,7435,7443,7496,7512,7625,7627,7676,7741,7777-7778,7800,7911,7920-7921,7937-7938,7999-8002,8007-8011,8021-8022,8031,8042,8045,8080-8090,8093,8099-8100,8180-8181,8192-8194,8200,8222,8254,8290-8292,8300,8333,8383,8400,8402,8443,8500,8600,8649,8651-8652,8654,8701,8800,8873,8888,8899,8994,9000-9003,9009-9011,9040,9050,9071,9080-9081,9090-9091,9099-9103,9110-9111,9200,9207,9220,9290,9415,9418,9485,9500,9502-9503,9535,9575,9593-9595,9618,9666,9876-9878,9898,9900,9917,9929,9943-9944,9968,9998-10004,10009-10010,10012,10024-10025,10082,10180,10215,10243,10566,10616-10617,10621,10626,10628-10629,10778,11110-11111,11967,12000,12174,12265,12345,13456,13722,13782-13783,14000,14238,14441-14442,15000,15002-15004,15660,15742,16000-16001,16012,16016,16018,16080,16113,16992-16993,17877,17988,18040,18101,18988,19101,19283,19315,19350,19780,19801,19842,20000,20005,20031,20221-20222,20828,21571,22939,23502,24444,24800,25734-25735,26214,27000,27352-27353,27355-27356,27715,28201,30000,30718,30951,31038,31337,32768-32785,33354,33899,34571-34573,35500,38292,40193,40911,41511,42510,44176,44442-44443,44501,45100,48080,49152-49161,49163,49165,49167,49175-49176,49400,49999-50003,50006,50300,50389,50500,50636,50800,51103,51493,52673,52822,52848,52869,54045,54328,55055-55056,55555,55600,56737-56738,57294,57797,58080,60020,60443,61532,61900,62078,63331,64623,64680,65000,65129,65389
|
||||||
|
range = 1.0.0.0-4.53.200.255
|
||||||
|
range = 4.53.202.0-5.152.178.255
|
||||||
|
range = 5.152.180.0-5.255.255.255
|
||||||
|
range = 7.0.0.0-8.12.161.255
|
||||||
|
range = 8.12.165.0-8.14.83.255
|
||||||
|
range = 8.14.88.0-8.14.144.255
|
||||||
|
range = 8.14.148.0-8.17.249.255
|
||||||
|
range = 8.17.253.0-9.255.255.255
|
||||||
|
range = 11.0.0.0-20.255.255.255
|
||||||
|
range = 23.0.0.0-23.26.255.255
|
||||||
|
range = 23.28.0.0-23.231.127.255
|
||||||
|
range = 23.232.0.0-23.255.255.255
|
||||||
|
range = 24.16.0.0-24.87.255.255
|
||||||
|
range = 24.89.0.0-24.111.255.255
|
||||||
|
range = 24.112.128.0-24.131.255.255
|
||||||
|
range = 24.132.3.0-24.187.255.255
|
||||||
|
range = 24.192.0.0-37.72.171.255
|
||||||
|
range = 37.72.174.0-38.72.199.255
|
||||||
|
range = 38.72.204.0-50.93.191.255
|
||||||
|
range = 50.93.198.0-50.115.127.255
|
||||||
|
range = 50.115.144.0-50.116.255.255
|
||||||
|
range = 50.117.128.0-50.118.127.255
|
||||||
|
range = 50.119.0.0-63.141.221.255
|
||||||
|
range = 63.141.223.0-64.62.252.255
|
||||||
|
range = 64.62.254.0-64.92.95.255
|
||||||
|
range = 64.92.128.0-64.145.78.255
|
||||||
|
range = 64.145.80.0/23
|
||||||
|
range = 64.145.84.0-64.158.145.255
|
||||||
|
range = 64.158.148.0-65.49.23.255
|
||||||
|
range = 65.49.25.0-65.49.92.255
|
||||||
|
range = 65.49.94.0-65.162.191.255
|
||||||
|
range = 65.162.196.0-66.79.159.255
|
||||||
|
range = 66.79.192.0-66.160.190.255
|
||||||
|
range = 66.160.192.0-68.68.95.255
|
||||||
|
range = 68.68.112.0-69.46.63.255
|
||||||
|
range = 69.46.96.0-69.176.79.255
|
||||||
|
range = 69.176.96.0-72.13.79.255
|
||||||
|
range = 72.13.96.0-72.52.75.255
|
||||||
|
range = 72.52.77.0-74.82.42.255
|
||||||
|
range = 74.82.44.0-74.82.159.255
|
||||||
|
range = 74.82.192.0-74.114.87.255
|
||||||
|
range = 74.114.92.0-74.114.255.255
|
||||||
|
range = 74.115.1.0/24
|
||||||
|
range = 74.115.3.0/24
|
||||||
|
range = 74.115.5.0-74.122.99.255
|
||||||
|
range = 74.122.104.0-75.126.255.255
|
||||||
|
range = 75.127.1.0-100.63.255.255
|
||||||
|
range = 100.128.0.0-103.251.90.255
|
||||||
|
range = 103.251.92.0-108.171.31.255
|
||||||
|
range = 108.171.33.0-108.171.41.255
|
||||||
|
range = 108.171.43.0-108.171.51.255
|
||||||
|
range = 108.171.53.0-108.171.61.255
|
||||||
|
range = 108.171.63.0-118.193.77.255
|
||||||
|
range = 118.193.80.0-126.255.255.255
|
||||||
|
range = 128.0.0.0-130.93.15.255
|
||||||
|
range = 130.93.18.0-131.214.255.255
|
||||||
|
range = 131.216.0.0-134.3.255.255
|
||||||
|
range = 134.5.0.0-135.255.255.255
|
||||||
|
range = 136.1.0.0-142.110.255.255
|
||||||
|
range = 142.112.0.0-142.251.255.255
|
||||||
|
range = 142.253.0.0-146.82.55.92
|
||||||
|
range = 146.82.55.94-149.54.135.255
|
||||||
|
range = 149.54.144.0/21
|
||||||
|
range = 149.54.160.0-153.10.255.255
|
||||||
|
range = 153.12.0.0-165.159.255.255
|
||||||
|
range = 165.161.0.0-166.87.255.255
|
||||||
|
range = 166.89.0.0-169.253.255.255
|
||||||
|
range = 169.255.0.0-172.15.255.255
|
||||||
|
range = 172.32.0.0-172.251.255.255
|
||||||
|
range = 172.253.0.0-173.245.63.255
|
||||||
|
range = 173.245.96.0-173.245.193.255
|
||||||
|
range = 173.245.196.0-173.245.219.255
|
||||||
|
range = 173.245.224.0-173.252.191.255
|
||||||
|
range = 173.253.0.0-178.18.15.255
|
||||||
|
range = 178.18.20.0-178.18.25.255
|
||||||
|
range = 178.18.30.0-183.182.21.255
|
||||||
|
range = 183.182.23.0-191.255.255.255
|
||||||
|
range = 192.0.1.0/24
|
||||||
|
range = 192.0.3.0-192.12.18.255
|
||||||
|
range = 192.12.20.0-192.31.42.255
|
||||||
|
range = 192.31.44.0-192.41.207.255
|
||||||
|
range = 192.41.209.0-192.43.242.255
|
||||||
|
range = 192.43.244.0-192.54.248.255
|
||||||
|
range = 192.54.250.0-192.88.98.255
|
||||||
|
range = 192.88.100.0-192.92.113.255
|
||||||
|
range = 192.92.115.0-192.155.159.255
|
||||||
|
range = 192.155.192.0-192.167.255.255
|
||||||
|
range = 192.169.0.0-192.176.255.255
|
||||||
|
range = 192.178.0.0-192.185.255.255
|
||||||
|
range = 192.186.64.0-192.249.63.255
|
||||||
|
range = 192.249.80.0-192.250.239.255
|
||||||
|
range = 192.251.0.0-194.77.40.241
|
||||||
|
range = 194.77.40.243-194.77.40.245
|
||||||
|
range = 194.77.40.247-194.110.213.255
|
||||||
|
range = 194.110.215.0-198.12.119.255
|
||||||
|
range = 198.12.123.0-198.17.255.255
|
||||||
|
range = 198.20.0.0-198.51.99.255
|
||||||
|
range = 198.51.101.0-198.144.239.255
|
||||||
|
range = 198.145.0.0-199.33.119.255
|
||||||
|
range = 199.33.121.0-199.33.123.255
|
||||||
|
range = 199.33.128.0-199.48.146.255
|
||||||
|
range = 199.48.148.0-199.68.195.255
|
||||||
|
range = 199.68.200.0-199.127.239.255
|
||||||
|
range = 199.127.248.0-199.187.167.255
|
||||||
|
range = 199.187.172.0-199.188.237.255
|
||||||
|
range = 199.188.240.0-199.255.207.255
|
||||||
|
range = 199.255.209.0-203.0.112.255
|
||||||
|
range = 203.0.114.0-203.12.5.255
|
||||||
|
range = 203.12.7.0-204.13.63.255
|
||||||
|
range = 204.13.72.0-204.16.191.255
|
||||||
|
range = 204.16.200.0-204.19.237.255
|
||||||
|
range = 204.19.239.0-204.74.207.255
|
||||||
|
range = 204.74.224.0-205.159.188.255
|
||||||
|
range = 205.159.190.0-205.163.255.255
|
||||||
|
range = 205.164.64.0-205.209.127.255
|
||||||
|
range = 205.209.192.0-206.108.51.255
|
||||||
|
range = 206.108.54.0-206.165.3.255
|
||||||
|
range = 206.165.5.0-208.77.39.255
|
||||||
|
range = 208.77.48.0-208.80.3.255
|
||||||
|
range = 208.80.8.0-208.123.222.255
|
||||||
|
range = 208.123.224.0-209.51.184.255
|
||||||
|
range = 209.51.186.0-209.54.47.255
|
||||||
|
range = 209.54.64.0-209.107.191.255
|
||||||
|
range = 209.107.194.0-209.107.209.255
|
||||||
|
range = 209.107.211.0/24
|
||||||
|
range = 209.107.213.0-211.156.109.255
|
||||||
|
range = 211.156.112.0-216.83.32.255
|
||||||
|
range = 216.83.50.0/24
|
||||||
|
range = 216.83.64.0-216.151.182.255
|
||||||
|
range = 216.151.184.0-216.151.189.255
|
||||||
|
range = 216.151.192.0-216.172.127.255
|
||||||
|
range = 216.172.160.0-216.185.35.255
|
||||||
|
range = 216.185.37.0-216.218.232.255
|
||||||
|
range = 216.218.234.0-216.224.111.255
|
||||||
|
range = 216.224.128.0-239.255.255.255
|
||||||
|
|
||||||
Executable
+192
@@ -0,0 +1,192 @@
|
|||||||
|
import os
|
||||||
|
import base64
|
||||||
|
import json
|
||||||
|
from hashlib import sha256
|
||||||
|
from flask import Flask, render_template, Response
|
||||||
|
from flask import request, redirect, url_for, make_response
|
||||||
|
|
||||||
|
import src.packets as packets
|
||||||
|
import src.utils as utils
|
||||||
|
|
||||||
|
class authUser:
|
||||||
|
def __init__(self):
|
||||||
|
self.username = None
|
||||||
|
self.permGroups = []
|
||||||
|
self.id = None
|
||||||
|
self.sha256passwordhash = None
|
||||||
|
self.passwordUpdated = None
|
||||||
|
self.created = None
|
||||||
|
|
||||||
|
class authClient:
|
||||||
|
def __init__(self):
|
||||||
|
self.username = None
|
||||||
|
self.session = utils.randID(32)
|
||||||
|
self.currentPage = "/login"
|
||||||
|
self.user = None
|
||||||
|
|
||||||
|
self.timeout = utils.getUnixTime() + (6 * 60 * 60 * 1000)
|
||||||
|
self.loginTime = utils.getUnixTime()
|
||||||
|
self.lastReauth = utils.getUnixTime()
|
||||||
|
|
||||||
|
self.rawClient = None
|
||||||
|
|
||||||
|
def send(self, type, data):
|
||||||
|
self.rawClient.send(type, data)
|
||||||
|
|
||||||
|
class authServer:
|
||||||
|
def __init__(self, webserv):
|
||||||
|
self.rawServer = None
|
||||||
|
self.app = None
|
||||||
|
self.clients = []
|
||||||
|
self.users = []
|
||||||
|
|
||||||
|
self.webserv = webserv
|
||||||
|
|
||||||
|
self.pageListeners = []
|
||||||
|
|
||||||
|
self.reloadUsers()
|
||||||
|
self.rawServer = webserv.rawServer
|
||||||
|
self.initRawServer()
|
||||||
|
|
||||||
|
def login(self, c, data):
|
||||||
|
if c.clientid != data['cid']:
|
||||||
|
c.send('error', 'invalidLoginRequest')
|
||||||
|
return
|
||||||
|
|
||||||
|
if int(data['data']['salt']) > (utils.getUnixTime() + 5000):
|
||||||
|
c.send('error', 'invalidLoginRequest')
|
||||||
|
return
|
||||||
|
|
||||||
|
logins = json.loads(utils.readFile(utils.getRoot('data/')+'creds.json'))
|
||||||
|
isValid = False
|
||||||
|
validAcc = None
|
||||||
|
for acc in self.users:
|
||||||
|
hash = utils.hash(
|
||||||
|
str(acc.username)+
|
||||||
|
str(acc.sha256passwordhash)+
|
||||||
|
str(data['data']['salt']))
|
||||||
|
|
||||||
|
if hash == str(data['data']['data']):
|
||||||
|
isValid = True
|
||||||
|
validAcc = acc
|
||||||
|
break
|
||||||
|
|
||||||
|
if isValid:
|
||||||
|
if utils.getatribinarr(self.clients, 'rawClient', c):
|
||||||
|
c.send('error', 'prelogin')
|
||||||
|
return
|
||||||
|
|
||||||
|
ac = authClient()
|
||||||
|
ac.username = validAcc.username
|
||||||
|
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
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
c.send('error', 'invalidLogin')
|
||||||
|
return
|
||||||
|
|
||||||
|
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:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def reauth(self, c, data):
|
||||||
|
session = data['data']['session']
|
||||||
|
|
||||||
|
ac = utils.getatribinarr(self.clients, 'session', session)
|
||||||
|
|
||||||
|
if not self.validAc(ac):
|
||||||
|
c.send('error', 'invalidLoginRequest')
|
||||||
|
return
|
||||||
|
|
||||||
|
ac.rawClient = c
|
||||||
|
ac.lastReauth = utils.getUnixTime()
|
||||||
|
|
||||||
|
ac.send('reauth', {
|
||||||
|
'username': ac.username,
|
||||||
|
'id': ac.user.id,
|
||||||
|
'permGroups': ac.user.permGroups,
|
||||||
|
'created': ac.user.created,
|
||||||
|
'passwordUpdated': ac.user.passwordUpdated,
|
||||||
|
'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:
|
||||||
|
return None
|
||||||
|
|
||||||
|
ac = utils.getatribinarr(self.clients, 'session', session)
|
||||||
|
|
||||||
|
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)
|
||||||
|
self.rawServer.addEventListener('reauth', self.reauth)
|
||||||
|
|
||||||
|
def reloadUsers(self):
|
||||||
|
data = json.loads(utils.readFile(utils.getRoot('data/')+'creds.json'))
|
||||||
|
|
||||||
|
self.users = []
|
||||||
|
|
||||||
|
for acc in data:
|
||||||
|
user = authUser()
|
||||||
|
user.username = acc['username']
|
||||||
|
user.id = acc['id']
|
||||||
|
user.sha256passwordhash = acc['sha256passwordhash']
|
||||||
|
user.permGroups = acc['permGroups']
|
||||||
|
user.created = acc['created']
|
||||||
|
user.passwordUpdated = acc['passwordUpdated']
|
||||||
|
self.users.append(user)
|
||||||
Executable
+273
@@ -0,0 +1,273 @@
|
|||||||
|
# Copyright (c) 2013, Rodrigo González, Sapienlab All Rights Reserved.
|
||||||
|
# Available via MIT LICENSE. See https://github.com/roro89/jsonpack/blob/master/LICENSE.md for details.
|
||||||
|
|
||||||
|
TOKEN_TRUE = -1
|
||||||
|
TOKEN_FALSE = -2
|
||||||
|
TOKEN_NULL = -3
|
||||||
|
TOKEN_EMPTY_STRING = -4
|
||||||
|
TOKEN_UNDEFINED = -5
|
||||||
|
|
||||||
|
def pack(json):
|
||||||
|
json = json if isinstance(json, str) else json
|
||||||
|
dictionary = {
|
||||||
|
'strings': [],
|
||||||
|
'integers': [],
|
||||||
|
'floats': []
|
||||||
|
}
|
||||||
|
|
||||||
|
def recursiveAstBuilder(item):
|
||||||
|
if item is None:
|
||||||
|
return {
|
||||||
|
'type': 'null',
|
||||||
|
'index': TOKEN_NULL
|
||||||
|
}
|
||||||
|
if item == '':
|
||||||
|
return {
|
||||||
|
'type': '',
|
||||||
|
'index': TOKEN_UNDEFINED
|
||||||
|
}
|
||||||
|
if isinstance(item, list):
|
||||||
|
ast = ['@']
|
||||||
|
for i in item:
|
||||||
|
ast.append(recursiveAstBuilder(i))
|
||||||
|
return ast
|
||||||
|
if isinstance(item, dict):
|
||||||
|
ast = ['$']
|
||||||
|
for key, value in item.items():
|
||||||
|
ast.append(recursiveAstBuilder(key))
|
||||||
|
ast.append(recursiveAstBuilder(value))
|
||||||
|
return ast
|
||||||
|
if item == '':
|
||||||
|
return {
|
||||||
|
'type': 'empty',
|
||||||
|
'index': TOKEN_EMPTY_STRING
|
||||||
|
}
|
||||||
|
if type(item) == type(True):
|
||||||
|
return {
|
||||||
|
'type': 'boolean',
|
||||||
|
'index': TOKEN_TRUE if item else TOKEN_FALSE
|
||||||
|
}
|
||||||
|
if isinstance(item, str):
|
||||||
|
index = dictionary['strings'].index(item) if item in dictionary['strings'] else -1
|
||||||
|
if index == -1:
|
||||||
|
dictionary['strings'].append((item))
|
||||||
|
index = len(dictionary['strings']) - 1
|
||||||
|
return {
|
||||||
|
'type': 'strings',
|
||||||
|
'index': index
|
||||||
|
}
|
||||||
|
if isinstance(item, int):
|
||||||
|
index = dictionary['integers'].index(item) if item in dictionary['integers'] else -1
|
||||||
|
if index == -1:
|
||||||
|
dictionary['integers'].append(_base10To36(item))
|
||||||
|
index = len(dictionary['integers']) - 1
|
||||||
|
return {
|
||||||
|
'type': 'integers',
|
||||||
|
'index': index
|
||||||
|
}
|
||||||
|
if isinstance(item, float):
|
||||||
|
index = dictionary['floats'].index(item) if item in dictionary['floats'] else -1
|
||||||
|
if index == -1:
|
||||||
|
dictionary['floats'].append(item)
|
||||||
|
index = len(dictionary['floats']) - 1
|
||||||
|
return {
|
||||||
|
'type': 'floats',
|
||||||
|
'index': index
|
||||||
|
}
|
||||||
|
raise TypeError('Unexpected argument of type ' + str(type(item)))
|
||||||
|
|
||||||
|
def recursiveParser(item):
|
||||||
|
if isinstance(item, list):
|
||||||
|
packed = item[0]
|
||||||
|
for i in item[1:]:
|
||||||
|
packed += recursiveParser(i) + '|'
|
||||||
|
return (packed[:-1] if packed[-1] == '|' else packed) + ']'
|
||||||
|
type = item['type']
|
||||||
|
index = item['index']
|
||||||
|
if type == 'strings':
|
||||||
|
return _base10To36(index)
|
||||||
|
if type == 'integers':
|
||||||
|
return _base10To36(stringLength + index)
|
||||||
|
if type == 'floats':
|
||||||
|
return _base10To36(stringLength + integerLength + index)
|
||||||
|
if type == 'boolean':
|
||||||
|
return str(index)
|
||||||
|
if type == 'null':
|
||||||
|
return str(TOKEN_NULL)
|
||||||
|
if type == '':
|
||||||
|
return str(TOKEN_UNDEFINED)
|
||||||
|
if type == 'empty':
|
||||||
|
return str(TOKEN_EMPTY_STRING)
|
||||||
|
raise TypeError('The item is alien!')
|
||||||
|
|
||||||
|
ast = recursiveAstBuilder(json)
|
||||||
|
|
||||||
|
stringLength = len(dictionary['strings'])
|
||||||
|
integerLength = len(dictionary['integers'])
|
||||||
|
floatLength = len(dictionary['floats'])
|
||||||
|
packed = '|'.join(dictionary['strings'])
|
||||||
|
packed += '^' + '|'.join(dictionary['integers'])
|
||||||
|
dictionary['floats'] = [str(n) for n in dictionary['floats']]
|
||||||
|
packed += '^' + '|'.join(dictionary['floats'])
|
||||||
|
packed += '^' + recursiveParser(ast)
|
||||||
|
|
||||||
|
return packed
|
||||||
|
|
||||||
|
def unpack(packed):
|
||||||
|
rawBuffers = packed.split('^')
|
||||||
|
dictionary = []
|
||||||
|
buffer = rawBuffers[0]
|
||||||
|
if buffer != '':
|
||||||
|
buffer = buffer.split('|')
|
||||||
|
for i in buffer:
|
||||||
|
dictionary.append(_decode(i))
|
||||||
|
buffer = rawBuffers[1]
|
||||||
|
if buffer != '':
|
||||||
|
buffer = buffer.split('|')
|
||||||
|
for i in buffer:
|
||||||
|
dictionary.append(_base36To10(i))
|
||||||
|
buffer = rawBuffers[2]
|
||||||
|
if buffer != '':
|
||||||
|
buffer = buffer.split('|')
|
||||||
|
for i in buffer:
|
||||||
|
dictionary.append(float(i))
|
||||||
|
tokens = []
|
||||||
|
number36 = ''
|
||||||
|
for i in rawBuffers[3]:
|
||||||
|
if i in ['|', '$', '@', ']']:
|
||||||
|
if number36:
|
||||||
|
tokens.append(_base36To10(number36))
|
||||||
|
number36 = ''
|
||||||
|
if i != '|':
|
||||||
|
tokens.append(i)
|
||||||
|
else:
|
||||||
|
number36 += i
|
||||||
|
tokensLength = len(tokens)
|
||||||
|
tokensIndex = 0
|
||||||
|
|
||||||
|
def recursiveUnpackerParser():
|
||||||
|
nonlocal tokensIndex
|
||||||
|
# Maybe '$' (object) or '@' (array)
|
||||||
|
type = tokens[tokensIndex]
|
||||||
|
tokensIndex += 1
|
||||||
|
# Parse an array
|
||||||
|
if type == '@':
|
||||||
|
node = []
|
||||||
|
while tokensIndex < tokensLength:
|
||||||
|
value = tokens[tokensIndex]
|
||||||
|
if value == ']':
|
||||||
|
return node
|
||||||
|
if value == '@' or value == '$':
|
||||||
|
node.append(recursiveUnpackerParser())
|
||||||
|
else:
|
||||||
|
if value == TOKEN_TRUE:
|
||||||
|
node.append(True)
|
||||||
|
elif value == TOKEN_FALSE:
|
||||||
|
node.append(False)
|
||||||
|
elif value == TOKEN_NULL:
|
||||||
|
node.append(None)
|
||||||
|
elif value == TOKEN_UNDEFINED:
|
||||||
|
node.append()
|
||||||
|
elif value == TOKEN_EMPTY_STRING:
|
||||||
|
node.append('')
|
||||||
|
else:
|
||||||
|
node.append(dictionary[value])
|
||||||
|
tokensIndex += 1
|
||||||
|
return node
|
||||||
|
# Parse an object
|
||||||
|
if type == '$':
|
||||||
|
node = {}
|
||||||
|
while tokensIndex < tokensLength:
|
||||||
|
key = tokens[tokensIndex]
|
||||||
|
if key == ']':
|
||||||
|
return node
|
||||||
|
if key == TOKEN_EMPTY_STRING:
|
||||||
|
key = ''
|
||||||
|
else:
|
||||||
|
key = dictionary[key]
|
||||||
|
tokensIndex += 1
|
||||||
|
value = tokens[tokensIndex]
|
||||||
|
if value == '@' or value == '$':
|
||||||
|
node[key] = recursiveUnpackerParser()
|
||||||
|
else:
|
||||||
|
if value == TOKEN_TRUE:
|
||||||
|
node[key] = True
|
||||||
|
elif value == TOKEN_FALSE:
|
||||||
|
node[key] = False
|
||||||
|
elif value == TOKEN_NULL:
|
||||||
|
node[key] = None
|
||||||
|
elif value == TOKEN_UNDEFINED:
|
||||||
|
node[key] = None
|
||||||
|
elif value == TOKEN_EMPTY_STRING:
|
||||||
|
node[key] = ''
|
||||||
|
else:
|
||||||
|
node[key] = dictionary[value]
|
||||||
|
tokensIndex += 1
|
||||||
|
return node
|
||||||
|
raise TypeError('Bad token ' + str(type) + ' isn\'t a type')
|
||||||
|
|
||||||
|
return recursiveUnpackerParser()
|
||||||
|
|
||||||
|
def _indexOfDictionary(dictionary, value):
|
||||||
|
if isinstance(value, bool):
|
||||||
|
return TOKEN_TRUE if value else TOKEN_FALSE
|
||||||
|
if value is None:
|
||||||
|
return TOKEN_NULL
|
||||||
|
if value == '':
|
||||||
|
return TOKEN_UNDEFINED
|
||||||
|
if value == '':
|
||||||
|
return TOKEN_EMPTY_STRING
|
||||||
|
if isinstance(value, str):
|
||||||
|
value = _encode(value)
|
||||||
|
index = dictionary['strings'].index(value) if value in dictionary['strings'] else -1
|
||||||
|
if index == -1:
|
||||||
|
dictionary['strings'].append(value)
|
||||||
|
index = len(dictionary['strings']) - 1
|
||||||
|
if type(value) not in [str, int]:
|
||||||
|
raise Error('The type is not a JSON type')
|
||||||
|
if isinstance(value, str):
|
||||||
|
value = _encode(value)
|
||||||
|
elif isinstance(value, int) and value % 1 == 0:
|
||||||
|
value = _base10To36(value)
|
||||||
|
value = _encode(value) if isinstance(value, str) else _base10To36(value)
|
||||||
|
index = dictionary[type(value)].index(value) if value in dictionary[type(value)] else -1
|
||||||
|
if index == -1:
|
||||||
|
dictionary[type(value)].append(value)
|
||||||
|
index = len(dictionary[type(value)]) - 1
|
||||||
|
return '+' + str(index) if type(value) == 'number' else index
|
||||||
|
|
||||||
|
def _encode(string):
|
||||||
|
if not isinstance(string, str):
|
||||||
|
return string
|
||||||
|
return string.replace(' ', '+').replace('+', '%2B').replace('|', '%7C').replace('^', '%5E').replace('%', '%25')
|
||||||
|
|
||||||
|
def _decode(string):
|
||||||
|
if not isinstance(string, str):
|
||||||
|
return string
|
||||||
|
return string.replace('+', ' ').replace('%2B', '+').replace('%7C', '|').replace('%5E', '^').replace('%25', '%')
|
||||||
|
|
||||||
|
def _base10To36(number):
|
||||||
|
if not isinstance(number, (int, float)):
|
||||||
|
raise TypeError('number must be an integer')
|
||||||
|
is_negative = number < 0
|
||||||
|
number = abs(number)
|
||||||
|
|
||||||
|
alphabet, base36 = ['0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ', '']
|
||||||
|
|
||||||
|
while number:
|
||||||
|
number, i = divmod(number, 36)
|
||||||
|
base36 = alphabet[i] + base36
|
||||||
|
if is_negative:
|
||||||
|
base36 = '-' + base36
|
||||||
|
|
||||||
|
return base36 or alphabet[0]
|
||||||
|
|
||||||
|
|
||||||
|
def _base36To10(number):
|
||||||
|
return int(number, 36)
|
||||||
|
|
||||||
|
def _indexOf(array, obj, start=0):
|
||||||
|
for i in range(start, len(array)):
|
||||||
|
if array[i] == obj:
|
||||||
|
return i
|
||||||
|
return -1
|
||||||
Executable
+280
@@ -0,0 +1,280 @@
|
|||||||
|
import json
|
||||||
|
import importlib
|
||||||
|
import sys
|
||||||
|
import multiprocessing as mupr
|
||||||
|
|
||||||
|
import src.web as web
|
||||||
|
import src.utils as utils
|
||||||
|
|
||||||
|
class module():
|
||||||
|
def __init__(self):
|
||||||
|
self.name = None
|
||||||
|
self.module = None
|
||||||
|
self.proc = None
|
||||||
|
self.rootdir = None
|
||||||
|
self.tabs = []
|
||||||
|
|
||||||
|
def add(self):
|
||||||
|
spec = importlib.util.spec_from_file_location(self.name, utils.getRoot(self.entrypoint))
|
||||||
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(module)
|
||||||
|
self.module = module
|
||||||
|
|
||||||
|
def init(self, moduleMaster):
|
||||||
|
self.module.init(moduleMaster)
|
||||||
|
self.proc = mupr.Process(target=self.module.main)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.proc.start()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.proc.stop()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class moduleMaster():
|
||||||
|
def __init__(self):
|
||||||
|
self.modules = []
|
||||||
|
|
||||||
|
self.webserv = None
|
||||||
|
self.app = None
|
||||||
|
self.rawServer = None
|
||||||
|
self.authServer = None
|
||||||
|
self.defaultPage = ""
|
||||||
|
self.vars = {}
|
||||||
|
|
||||||
|
# self.addRawEventListener('test1', test1)
|
||||||
|
|
||||||
|
def addModules(self, webserv):
|
||||||
|
self.webserv = webserv
|
||||||
|
|
||||||
|
mdirs = utils.listSubdirs(utils.getRoot('modules/'))
|
||||||
|
|
||||||
|
for mname in mdirs:
|
||||||
|
mjson = json.loads(open(utils.getRoot(f'modules/{mname}/module.json')).read())
|
||||||
|
m = module()
|
||||||
|
m.name = mjson['name']
|
||||||
|
m.entrypoint = mjson['entrypoint']
|
||||||
|
|
||||||
|
for tab in mjson['tabs']:
|
||||||
|
mtab = utils.getatribinarr(self.webserv.webtabs, 'name', tab['name'])
|
||||||
|
|
||||||
|
if mtab == None:
|
||||||
|
mtab = web.webtab()
|
||||||
|
mtab.name = tab['name']
|
||||||
|
m.tabs.append(mtab)
|
||||||
|
|
||||||
|
def recursiveAdder(objs):
|
||||||
|
tmpPages = []
|
||||||
|
for obj in objs:
|
||||||
|
if obj['type'] == 'folder':
|
||||||
|
folder = web.webpagefolder()
|
||||||
|
folder.name = obj['name']
|
||||||
|
tmpTmpPages = recursiveAdder(obj['pages'])
|
||||||
|
for tmpobj in tmpTmpPages:
|
||||||
|
folder.pages.append(tmpobj)
|
||||||
|
tmpPages.append(folder)
|
||||||
|
else:
|
||||||
|
mpage = web.webpage()
|
||||||
|
mpage.name = obj['name']
|
||||||
|
mpage.requiredPermGroup = obj['requiredPermGroup']
|
||||||
|
mpage.location = obj['location']
|
||||||
|
tmpPages.append(mpage)
|
||||||
|
return tmpPages
|
||||||
|
|
||||||
|
tmpPages = recursiveAdder(tab['pages'])
|
||||||
|
|
||||||
|
for obj in tmpPages:
|
||||||
|
mtab.pages.append(obj)
|
||||||
|
|
||||||
|
mtab.defaultPage = tab['defaultPage']
|
||||||
|
|
||||||
|
self.webserv.webtabs.append(mtab)
|
||||||
|
|
||||||
|
m.add()
|
||||||
|
self.modules.append(m)
|
||||||
|
|
||||||
|
# for tab in webserv.webtabs:
|
||||||
|
# tab.compileHtml('User')
|
||||||
|
|
||||||
|
def initModules(self, webserv):
|
||||||
|
self.webserv = webserv
|
||||||
|
self.app = webserv.app
|
||||||
|
self.rawServer = webserv.rawServer
|
||||||
|
self.authServer = webserv.authServer
|
||||||
|
|
||||||
|
self.defaultPage = f'/{webserv.defaultTab}/{webserv.defaultPage}'
|
||||||
|
|
||||||
|
for module in self.modules:
|
||||||
|
module.init(self)
|
||||||
|
|
||||||
|
def runModules(self):
|
||||||
|
for module in self.modules:
|
||||||
|
module.run()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def reloadUsers(self):
|
||||||
|
self.authServer.reloadUsers()
|
||||||
|
|
||||||
|
def editUser(self, user, varname, value):
|
||||||
|
path = utils.getRoot('data/')+'creds.json'
|
||||||
|
logins = json.loads(utils.readFile(path))
|
||||||
|
for userdata in logins:
|
||||||
|
if userdata['username'] == user.username:
|
||||||
|
userdata[varname] = value
|
||||||
|
|
||||||
|
utils.writeFile(path, json.dumps(logins, sort_keys=True, indent=2))
|
||||||
|
|
||||||
|
def setUserPassword(self, user, hash):
|
||||||
|
for ac in self.authServer.clients:
|
||||||
|
if ac.user == user:
|
||||||
|
self.unauth(ac)
|
||||||
|
self.editUser(user, 'sha256passwordhash', hash)
|
||||||
|
self.editUser(user, 'passwordUpdated', utils.getUnixTime())
|
||||||
|
self.authServer.reloadUsers()
|
||||||
|
|
||||||
|
def setUserGroups(self, user, groups):
|
||||||
|
for ac in self.authServer.clients:
|
||||||
|
if ac.user == user:
|
||||||
|
self.unauth(ac)
|
||||||
|
self.editUser(user, 'permGroups', groups)
|
||||||
|
self.authServer.reloadUsers()
|
||||||
|
|
||||||
|
def addUser(self, user, groups, hash):
|
||||||
|
path = utils.getRoot('data/')+'creds.json'
|
||||||
|
time = utils.getUnixTime()
|
||||||
|
logins = json.loads(utils.readFile(path))
|
||||||
|
logins.append({
|
||||||
|
'username': user,
|
||||||
|
'permGroups': groups,
|
||||||
|
'created': time,
|
||||||
|
'id': utils.randID(16),
|
||||||
|
'passwordUpdated': time,
|
||||||
|
'sha256passwordhash': hash
|
||||||
|
})
|
||||||
|
utils.writeFile(path, json.dumps(logins, sort_keys=True, indent=2))
|
||||||
|
self.authServer.reloadUsers()
|
||||||
|
|
||||||
|
def deleteUser(self, user):
|
||||||
|
path = utils.getRoot('data/')+'creds.json'
|
||||||
|
time = utils.getUnixTime()
|
||||||
|
logins = json.loads(utils.readFile(path))
|
||||||
|
for login in logins:
|
||||||
|
if login['id'] == user.id:
|
||||||
|
logins.remove(login)
|
||||||
|
utils.writeFile(path, json.dumps(logins, sort_keys=True, indent=2))
|
||||||
|
self.authServer.reloadUsers()
|
||||||
|
|
||||||
|
def userInGroup(self, ac, group):
|
||||||
|
if not self.authServer.validAc(ac):
|
||||||
|
return False
|
||||||
|
if (group != "") and not (group in ac.user.permGroups):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def getUserByName(self, name):
|
||||||
|
returnArr = []
|
||||||
|
for user in self.authServer.users:
|
||||||
|
if user.username == name:
|
||||||
|
returnArr.append(user)
|
||||||
|
return returnArr
|
||||||
|
|
||||||
|
def getUserById(self, id):
|
||||||
|
return utils.getatribinarr(self.authServer.users, 'id', id)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def getRawClients(self):
|
||||||
|
return self.rawServer.clients
|
||||||
|
|
||||||
|
def getAuthClients(self):
|
||||||
|
return self.authServer.clients
|
||||||
|
|
||||||
|
def addRawEventListener(self, eventName, func):
|
||||||
|
self.rawServer.eventListeners.append({
|
||||||
|
'type': eventName,
|
||||||
|
'func': func
|
||||||
|
})
|
||||||
|
|
||||||
|
def addAuthEventListener(self, eventName, func):
|
||||||
|
def tmpfunc(c, data):
|
||||||
|
if not c in self.rawServer.clients:
|
||||||
|
return
|
||||||
|
ac = utils.getatribinarr(self.authServer.clients, 'rawClient', c)
|
||||||
|
if ac == None:
|
||||||
|
return
|
||||||
|
if not self.authServer.validAc(ac):
|
||||||
|
return
|
||||||
|
|
||||||
|
func(ac, data)
|
||||||
|
|
||||||
|
self.rawServer.addEventListener(eventName, tmpfunc)
|
||||||
|
|
||||||
|
def getRawClientByID(self, ID):
|
||||||
|
return utils.getatribinarr(self.rawServer.clients, 'clientid', ID)
|
||||||
|
|
||||||
|
def getAuthClientByID(self, ID):
|
||||||
|
c = utils.getatribinarr(self.rawServer.clients, 'clientid', ID)
|
||||||
|
if c == None:
|
||||||
|
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):
|
||||||
|
ac.send('redir', {
|
||||||
|
"location": "/"
|
||||||
|
})
|
||||||
|
self.authServer.unauth(ac)
|
||||||
|
|
||||||
|
|
||||||
|
def sendPopupInfo(self, c, title, msg):
|
||||||
|
c.send('popupInfo', {
|
||||||
|
'title': title,
|
||||||
|
'msg': msg
|
||||||
|
})
|
||||||
|
|
||||||
|
def sendPopupSuccess(self, c, title, msg):
|
||||||
|
c.send('popupSuccess', {
|
||||||
|
'title': title,
|
||||||
|
'msg': msg
|
||||||
|
})
|
||||||
|
|
||||||
|
def sendPopupWarning(self, c, title, msg):
|
||||||
|
c.send('popupWarning', {
|
||||||
|
'title': title,
|
||||||
|
'msg': msg
|
||||||
|
})
|
||||||
|
|
||||||
|
def sendPopupError(self, c, title, msg):
|
||||||
|
c.send('popupError', {
|
||||||
|
'title': title,
|
||||||
|
'msg': msg
|
||||||
|
})
|
||||||
|
|
||||||
|
def sendPopupColor(self, c, title, msg, color, isDark):
|
||||||
|
c.send('popupColor', {
|
||||||
|
'title': title,
|
||||||
|
'msg': msg,
|
||||||
|
'color': color,
|
||||||
|
'isDark': isDark
|
||||||
|
})
|
||||||
Executable
+113
@@ -0,0 +1,113 @@
|
|||||||
|
import os
|
||||||
|
import base64
|
||||||
|
from hashlib import sha256
|
||||||
|
from flask import Flask, render_template, Response
|
||||||
|
from flask import request, redirect, url_for, make_response
|
||||||
|
|
||||||
|
import src.jsonpack as jsonpack
|
||||||
|
import src.utils as utils
|
||||||
|
|
||||||
|
import queue
|
||||||
|
|
||||||
|
class rawClient:
|
||||||
|
def __init__(self, rawServer):
|
||||||
|
self.clientid = utils.randID(32)
|
||||||
|
self.messages = queue.Queue()
|
||||||
|
self.rawServer = rawServer
|
||||||
|
self.address = None
|
||||||
|
def send(self, type, msg):
|
||||||
|
self.rawServer.sendClient(self, jsonpack.pack({
|
||||||
|
'type': type,
|
||||||
|
'data': msg,
|
||||||
|
'cid': self.clientid
|
||||||
|
}))
|
||||||
|
|
||||||
|
#Credit to https://github.com/MaxHalford/flask-sse-no-deps
|
||||||
|
class rawServer:
|
||||||
|
|
||||||
|
def __init__(self, webserv):
|
||||||
|
self.eventListeners = []
|
||||||
|
self.clients = []
|
||||||
|
self.webserv = webserv
|
||||||
|
self.app = webserv.app
|
||||||
|
# self.app = app
|
||||||
|
|
||||||
|
def listen(self):
|
||||||
|
c = rawClient(self)
|
||||||
|
self.clients.append(c)
|
||||||
|
return self.clients[-1]
|
||||||
|
|
||||||
|
def broadcast(self, msg):
|
||||||
|
# We go in reverse order because we might have to delete an element, which will shift the
|
||||||
|
# indices backward
|
||||||
|
ssedata = format_sse(msg)
|
||||||
|
for i in reversed(range(len(clients))):
|
||||||
|
try:
|
||||||
|
self.clients[i].messages.put_nowait(ssedata)
|
||||||
|
except queue.Full:
|
||||||
|
del self.clients[i]
|
||||||
|
|
||||||
|
def sendClient(self, c, msg):
|
||||||
|
if c not in self.clients:
|
||||||
|
return
|
||||||
|
ssedata = format_sse(msg)
|
||||||
|
c.messages.put_nowait(ssedata)
|
||||||
|
|
||||||
|
def clientByCID(self, cid):
|
||||||
|
for c in self.clients:
|
||||||
|
if c.clientid == cid:
|
||||||
|
return c
|
||||||
|
return None
|
||||||
|
|
||||||
|
def addEventListener(self, eventName, func):
|
||||||
|
self.eventListeners.append({
|
||||||
|
'type': eventName,
|
||||||
|
'func': func
|
||||||
|
})
|
||||||
|
|
||||||
|
def format_sse(data: str, event=None) -> str:
|
||||||
|
#Formats a string and an event name in order to follow the event stream convention.
|
||||||
|
msg = f'data: {data}\n\n'
|
||||||
|
if event is not None:
|
||||||
|
msg = f'event: {event}\n{msg}'
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
def startRawListener(webserv):
|
||||||
|
server = rawServer(webserv)
|
||||||
|
# app.rawServer = server
|
||||||
|
|
||||||
|
@webserv.app.route('/listen', methods=['GET', 'POST'])
|
||||||
|
def listen():
|
||||||
|
|
||||||
|
if request.method == 'GET':
|
||||||
|
|
||||||
|
c = server.listen() # returns a queue.Queue
|
||||||
|
c.address = request.remote_addr
|
||||||
|
c.send('clidata', {
|
||||||
|
'cid': c.clientid
|
||||||
|
})
|
||||||
|
|
||||||
|
def stream():
|
||||||
|
while True:
|
||||||
|
msg = c.messages.get() # blocks until a new message arrives
|
||||||
|
yield msg
|
||||||
|
|
||||||
|
return Response(stream(), mimetype='text/event-stream')
|
||||||
|
if request.method == 'POST':
|
||||||
|
|
||||||
|
data = jsonpack.unpack(request.data.decode("utf-8"))
|
||||||
|
|
||||||
|
if data['cid'] == None:
|
||||||
|
return {}, 400
|
||||||
|
c = utils.getatribinarr(server.clients, 'clientid', data['cid'])
|
||||||
|
if c == None:
|
||||||
|
return {}, 400
|
||||||
|
|
||||||
|
for event in server.eventListeners:
|
||||||
|
if event['type'] == data['type']:
|
||||||
|
event['func'](c, data)
|
||||||
|
|
||||||
|
return {}, 200
|
||||||
|
|
||||||
|
return server
|
||||||
Executable
+132
@@ -0,0 +1,132 @@
|
|||||||
|
import os
|
||||||
|
import json
|
||||||
|
import string
|
||||||
|
import random
|
||||||
|
from hashlib import sha256
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from sys import platform
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
def getRoot(path):
|
||||||
|
rootdir = os.getcwd() + f'/{path}'
|
||||||
|
|
||||||
|
if platform in ['nt', 'win32', 'win64']:
|
||||||
|
rootdir = rootdir.split(':')[1].replace('\\', '/')
|
||||||
|
|
||||||
|
return rootdir
|
||||||
|
|
||||||
|
def pathExists(path):
|
||||||
|
return os.path.exists(path)
|
||||||
|
|
||||||
|
def makeDir(path):
|
||||||
|
if not os.path.exists(path):
|
||||||
|
os.makedirs(path)
|
||||||
|
|
||||||
|
def listSubdirs(folder):
|
||||||
|
if os.path.exists(folder):
|
||||||
|
return os.listdir(folder)
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
def writeFile(path, data):
|
||||||
|
if not os.path.exists(path):
|
||||||
|
with open(path, mode='a'): pass
|
||||||
|
with open(path, 'w') as f:
|
||||||
|
f.write(data)
|
||||||
|
|
||||||
|
def readFile(path):
|
||||||
|
if not os.path.exists(path):
|
||||||
|
return ''
|
||||||
|
try:
|
||||||
|
with open(path) as f:
|
||||||
|
return f.read()
|
||||||
|
except:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def delFile(path):
|
||||||
|
if os.path.exists(path):
|
||||||
|
os.remove(path)
|
||||||
|
|
||||||
|
def getUnixTime():
|
||||||
|
return round((datetime.utcnow() - datetime(1970, 1, 1)).total_seconds() * 1000)
|
||||||
|
|
||||||
|
def hash(data):
|
||||||
|
return sha256(data.encode('utf-8')).hexdigest().upper()
|
||||||
|
|
||||||
|
def getatribinarr(arr, atribname, atrib):
|
||||||
|
for i in range(0,len(arr),1):
|
||||||
|
if getattr(arr[i], atribname) == atrib:
|
||||||
|
return arr[i]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def randID(length):
|
||||||
|
letters = string.hexdigits
|
||||||
|
return ''.join(random.choice(letters) for i in range(length))
|
||||||
|
|
||||||
|
def genDefaultAccounts():
|
||||||
|
userPassword = randID(16)
|
||||||
|
adminPassword = randID(16)
|
||||||
|
|
||||||
|
print('#################################################')
|
||||||
|
print('New Credentials - THESE ONLY WILL BE PRINTED ONCE')
|
||||||
|
print('########')
|
||||||
|
print('Username: User')
|
||||||
|
print(f'Password: {userPassword}')
|
||||||
|
print('########')
|
||||||
|
print('Username: Admin')
|
||||||
|
print(f'Password: {adminPassword}')
|
||||||
|
print('#################################################')
|
||||||
|
|
||||||
|
time = getUnixTime()
|
||||||
|
|
||||||
|
return json.dumps(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
'username': 'User',
|
||||||
|
'permGroups': [
|
||||||
|
'Users'
|
||||||
|
],
|
||||||
|
'id': randID(16),
|
||||||
|
'created': time,
|
||||||
|
'passwordUpdated': time,
|
||||||
|
'sha256passwordhash': hash(userPassword)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'username': 'Admin',
|
||||||
|
'permGroups': [
|
||||||
|
'Users',
|
||||||
|
'Admins'
|
||||||
|
],
|
||||||
|
'id': randID(16),
|
||||||
|
'created': time,
|
||||||
|
'passwordUpdated': time,
|
||||||
|
'sha256passwordhash': hash(adminPassword)
|
||||||
|
}
|
||||||
|
], sort_keys=True, indent=2)
|
||||||
|
|
||||||
|
def genKey(path):
|
||||||
|
subprocess.run(['openssl', 'genrsa', '-out', f'{path}ssl.key', '2048'])
|
||||||
|
|
||||||
|
def genCert(path):
|
||||||
|
writeFile(f'{path}/ssl.cnf',
|
||||||
|
"""[req]
|
||||||
|
default_bits = 2048
|
||||||
|
prompt = no
|
||||||
|
default_md = sha256
|
||||||
|
encrypt_key = no
|
||||||
|
distinguished_name = dn
|
||||||
|
|
||||||
|
[dn]
|
||||||
|
C = ID
|
||||||
|
O = Local Digital Cert Authority
|
||||||
|
OU = www.ca.local
|
||||||
|
CN = Self-Signed Root CA
|
||||||
|
""")
|
||||||
|
|
||||||
|
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}ssl.cnf')
|
||||||
|
delFile(f'{path}ssl.csr')
|
||||||
Executable
+187
@@ -0,0 +1,187 @@
|
|||||||
|
import os
|
||||||
|
import src.utils as utils
|
||||||
|
import multiprocessing as mupr
|
||||||
|
|
||||||
|
from flask import Flask, render_template, Response
|
||||||
|
from flask import request, redirect, url_for, make_response
|
||||||
|
|
||||||
|
import src.jsonpack as jsonpack
|
||||||
|
import src.packets as packets
|
||||||
|
import src.auth as auth
|
||||||
|
|
||||||
|
webroot = utils.getRoot('html/')
|
||||||
|
|
||||||
|
app = Flask(__name__,
|
||||||
|
static_url_path=webroot,
|
||||||
|
static_folder=webroot,
|
||||||
|
template_folder=webroot)
|
||||||
|
|
||||||
|
class webtab():
|
||||||
|
def __init__(self):
|
||||||
|
self.name = None
|
||||||
|
self.pages = []
|
||||||
|
self.defaultPage = ''
|
||||||
|
self.html = ''
|
||||||
|
|
||||||
|
def compileHtml(self, permGroups):
|
||||||
|
html = ''
|
||||||
|
for page in self.pages:
|
||||||
|
html += page.compileHtml(self.name, permGroups)
|
||||||
|
return html
|
||||||
|
|
||||||
|
def addPage(self, page):
|
||||||
|
self.pages.append(page)
|
||||||
|
|
||||||
|
class webpagefolder():
|
||||||
|
def __init__(self):
|
||||||
|
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)
|
||||||
|
if not isValid:
|
||||||
|
return redirect("/login", code=302)
|
||||||
|
else:
|
||||||
|
return redirect(f'/{app.webserv.defaultTab}/{app.webserv.defaultPage}', code=302)
|
||||||
|
|
||||||
|
@app.route('/login')
|
||||||
|
def loginPage():
|
||||||
|
isValid = app.webserv.authServer.cookieLogin(request)
|
||||||
|
if isValid:
|
||||||
|
return redirect(f'/{app.webserv.defaultTab}/{app.webserv.defaultPage}', code=302)
|
||||||
|
|
||||||
|
return make_response(open(f'{webroot}nav.html', 'r').read()
|
||||||
|
.replace('<!--Place body here!!!-->', open(f'{webroot}login.html', 'r').read())
|
||||||
|
.replace('<!--Place tabs here!!!-->', '<a href="/login" role="button" class="outline topnav-button text-white">Login</a>')
|
||||||
|
.replace('<!--Place title here!!!-->', app.webserv.title)
|
||||||
|
.replace('<!--Place defaultPage here!!!-->', '/login'))
|
||||||
|
|
||||||
|
def recursivePageFinder(pagename, objs):
|
||||||
|
returnVal = None
|
||||||
|
for obj in objs:
|
||||||
|
if isinstance(obj, webpagefolder):
|
||||||
|
tmp = recursivePageFinder(pagename, obj.pages)
|
||||||
|
if tmp != None:
|
||||||
|
returnVal = tmp
|
||||||
|
else:
|
||||||
|
if obj.name == pagename:
|
||||||
|
returnVal = obj
|
||||||
|
return returnVal
|
||||||
|
|
||||||
|
@app.route('/<tabname>/<pagename>')
|
||||||
|
def page(tabname, pagename):
|
||||||
|
|
||||||
|
isValid = app.webserv.authServer.cookieLogin(request)
|
||||||
|
if not isValid:
|
||||||
|
return redirect("/login", code=302)
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
tab = utils.getatribinarr(app.webserv.webtabs, 'name', tabname)
|
||||||
|
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(page.location), 'r').read())
|
||||||
|
.replace('<!--Place tabs here!!!-->', app.webserv.tabHtml)
|
||||||
|
.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("/", code=302)
|
||||||
|
|
||||||
|
@app.route('/src/<file>')
|
||||||
|
def src(file):
|
||||||
|
return app.send_static_file(f'src/{file}')
|
||||||
|
|
||||||
|
@app.errorhandler(404)
|
||||||
|
def err404(err):
|
||||||
|
return redirect("/", code=302)
|
||||||
|
|
||||||
|
|
||||||
|
class webserv():
|
||||||
|
def __init__(self):
|
||||||
|
self.title = 'Polyboard'
|
||||||
|
self.port = 443
|
||||||
|
self.host = '0.0.0.0'
|
||||||
|
self.verbose = False
|
||||||
|
self.secure = True
|
||||||
|
self.tabHtml = ''
|
||||||
|
self.webtabs = []
|
||||||
|
self.defaultTab = 'main'
|
||||||
|
self.defaultPage = ''
|
||||||
|
|
||||||
|
self.app = None
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
if not self.verbose:
|
||||||
|
import logging
|
||||||
|
log = logging.getLogger('werkzeug')
|
||||||
|
log.setLevel(logging.ERROR)
|
||||||
|
|
||||||
|
if self.secure:
|
||||||
|
dataroot = utils.getRoot("data/")
|
||||||
|
sslcontext = (f'{dataroot}ssl.crt', f'{dataroot}ssl.key')
|
||||||
|
else:
|
||||||
|
sslcontext = None
|
||||||
|
|
||||||
|
def tabHtml(path, name):
|
||||||
|
return f'<a href="{path}" role="button" class="outline topnav-button text-white">{name}</a>'
|
||||||
|
|
||||||
|
for tab in self.webtabs:
|
||||||
|
if tab.name == self.defaultTab:
|
||||||
|
self.tabHtml = tabHtml(f'/{tab.name}/{tab.defaultPage}', tab.name) + self.tabHtml
|
||||||
|
self.defaultPage = tab.defaultPage
|
||||||
|
else:
|
||||||
|
self.tabHtml += tabHtml(f'/{tab.name}/{tab.defaultPage}', tab.name)
|
||||||
|
|
||||||
|
app.webserv = self
|
||||||
|
self.app = app
|
||||||
|
self.rawServer = packets.startRawListener(self)
|
||||||
|
self.authServer = auth.authServer(self)
|
||||||
|
self.proc = mupr.Process(target=app.run, kwargs=dict(debug=self.verbose, port=self.port, host=self.host, ssl_context=sslcontext))
|
||||||
|
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self.proc.start()
|
||||||
|
|
||||||
|
# return self.rawServer
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.proc.terminate()
|
||||||
|
|
||||||
|
# def sendfatal(self, err):
|
||||||
|
# self.rawServer.broadcast(jsonpack.pack({
|
||||||
|
# 'type': 'error',
|
||||||
|
# 'severity': 'fatal',
|
||||||
|
# 'error': err
|
||||||
|
# }))
|
||||||
Reference in New Issue
Block a user