basic server struct
This commit is contained in:
parent
4e74d679cc
commit
70e31009e0
11 changed files with 249 additions and 20 deletions
34
package-lock.json
generated
34
package-lock.json
generated
|
@ -10,6 +10,7 @@
|
|||
"license": "AGPL-3.0-only",
|
||||
"dependencies": {
|
||||
"commander": "^10.0.0",
|
||||
"cors": "^2.8.5",
|
||||
"dblang": "https://jusax.de/git/attachments/c13552b7-c9f0-4f50-bcce-96a124c1c286",
|
||||
"express": "^4.18.2",
|
||||
"juml": "https://jusax.de/git/attachments/208913c5-2851-4b86-a53d-ca99fed168cc",
|
||||
|
@ -18,10 +19,12 @@
|
|||
"ws": "^8.12.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.13",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/node": "^18.11.18",
|
||||
"@types/pg": "^8.6.6",
|
||||
"@types/prompts": "^2.4.2",
|
||||
"@types/ws": "^8.5.4",
|
||||
"esbuild": "^0.17.10",
|
||||
"pkg": "^5.8.0",
|
||||
"typescript": "^4.9.4"
|
||||
|
@ -529,6 +532,15 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cors": {
|
||||
"version": "2.8.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz",
|
||||
"integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/express": {
|
||||
"version": "4.17.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz",
|
||||
|
@ -612,6 +624,15 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
"version": "8.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz",
|
||||
"integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||
|
@ -1046,6 +1067,18 @@
|
|||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/cors": {
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
||||
"dependencies": {
|
||||
"object-assign": "^4",
|
||||
"vary": "^1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/data-uri-to-buffer": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
||||
|
@ -2168,7 +2201,6 @@
|
|||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
"main": "dist/main.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"main": "tsc && node . -c config.juml"
|
||||
"main": "tsc && node . -c config.juml",
|
||||
"setup": "tsc && node . -c config.juml -s"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -17,16 +18,19 @@
|
|||
"author": "jusax23, comcloudway",
|
||||
"license": "AGPL-3.0-only",
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.13",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/node": "^18.11.18",
|
||||
"@types/pg": "^8.6.6",
|
||||
"@types/prompts": "^2.4.2",
|
||||
"@types/ws": "^8.5.4",
|
||||
"esbuild": "^0.17.10",
|
||||
"pkg": "^5.8.0",
|
||||
"typescript": "^4.9.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": "^10.0.0",
|
||||
"cors": "^2.8.5",
|
||||
"dblang": "https://jusax.de/git/attachments/c13552b7-c9f0-4f50-bcce-96a124c1c286",
|
||||
"express": "^4.18.2",
|
||||
"juml": "https://jusax.de/git/attachments/208913c5-2851-4b86-a53d-ca99fed168cc",
|
||||
|
|
72
src/api/get.ts
Normal file
72
src/api/get.ts
Normal file
|
@ -0,0 +1,72 @@
|
|||
import { eq, ge, select } from "dblang";
|
||||
import express, { Request, Response } from "express";
|
||||
import { suspectRequest } from "../sys/bruteforce.js";
|
||||
import { oConf } from "../sys/config.js";
|
||||
import { accounts, db, rooms } from "../sys/db.js";
|
||||
import { error } from "../sys/log.js";
|
||||
import { getSettings, SETTINGS } from "../sys/settings.js";
|
||||
|
||||
var Methods: ([string, (req: Request, res: Response) => Promise<void>])[] = [
|
||||
["users", async (req: Request, res: Response) => {
|
||||
let resp = await select([accounts.name], accounts)
|
||||
.where(eq(accounts.viewable, true))
|
||||
.query(db);
|
||||
res.json(resp.map(d => d[accounts.name]));
|
||||
}],
|
||||
["server/publicKey", async (req: Request, res: Response) => {
|
||||
let publicKey = await getSettings(SETTINGS.publicKey);
|
||||
let expires = await getSettings(SETTINGS.certExpires);
|
||||
if (publicKey && expires) {
|
||||
res.json({
|
||||
publicKey,
|
||||
expires
|
||||
});
|
||||
}
|
||||
}],
|
||||
["isUser/:user", async (req: suspectRequest, res: Response) => {
|
||||
var user = req.params.user;
|
||||
let data = await select([accounts.accID], accounts)
|
||||
.where(eq(accounts.name, user))
|
||||
.query(db);
|
||||
if (data.length == 0) {
|
||||
if (req.suspect) req.suspect();
|
||||
res.send("error");
|
||||
} else {
|
||||
res.send("ok");
|
||||
}
|
||||
}],
|
||||
["publicRooms", async (req: Request, res: Response) => {
|
||||
let data = await select([rooms.name, rooms.title, rooms.description, rooms.icon], rooms)
|
||||
.where(ge(rooms.public, 1))
|
||||
.query(db);
|
||||
var out = data.map(d => {
|
||||
let name = d[rooms.name];
|
||||
let title = d[rooms.title];
|
||||
let description = d[rooms.description];
|
||||
let icon = d[rooms.icon];
|
||||
if (name != null && title != null && description != null && icon != null) {
|
||||
return { name, title, description, icon };
|
||||
}
|
||||
return null;
|
||||
});
|
||||
res.json(out.filter(d => d != null));
|
||||
}]
|
||||
];
|
||||
|
||||
export const addGetMethods = (server: express.Express) => {
|
||||
server.get("/.well-known/outbag/server", (req, res) => {
|
||||
res.json({
|
||||
port: oConf.get("System", "PORTexposed"),
|
||||
path: oConf.get("System", "PATHexposed"),
|
||||
})
|
||||
});
|
||||
Methods.forEach((d) => void server.get("/api/" + d[0], async (req, res) => {
|
||||
try {
|
||||
await d[1](req, res);
|
||||
if (!res.headersSent) res.status(500).send();
|
||||
} catch (e) {
|
||||
error("API", "Get Request Error:", e);
|
||||
res.status(500).send();
|
||||
}
|
||||
}));
|
||||
}
|
5
src/api/post.ts
Normal file
5
src/api/post.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import express from "express";
|
||||
|
||||
export const addPostMethods = (server: express.Express) => {
|
||||
|
||||
}
|
16
src/api/user.ts
Normal file
16
src/api/user.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
export const STATE = {
|
||||
no: 0b0001,
|
||||
remoteP: 0b0010,
|
||||
remote: 0b0100,
|
||||
client: 0b1000,
|
||||
};
|
||||
|
||||
export abstract class Client{
|
||||
name: String;
|
||||
server: String;
|
||||
ip: String;
|
||||
rights: number;
|
||||
state: number;
|
||||
accID = -1;
|
||||
|
||||
}
|
6
src/api/ws.ts
Normal file
6
src/api/ws.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
import ws from "ws";
|
||||
import http from "http";
|
||||
|
||||
export const wsOnConnection = (socket:ws.WebSocket, req: http.IncomingMessage) => {
|
||||
|
||||
}
|
68
src/main.ts
68
src/main.ts
|
@ -4,14 +4,20 @@ declare global {
|
|||
import express from "express";
|
||||
import https from "https";
|
||||
import http from "http";
|
||||
import nman from "nman";
|
||||
import cors from "cors";
|
||||
import { WebSocketServer } from "ws";
|
||||
import { Command } from "commander";
|
||||
import { oConf } from "./sys/config.js"
|
||||
import { log } from "./sys/log.js"
|
||||
import { connectToDB } from "./sys/db.js"
|
||||
import bruteforce from "./sys/bruteforce.js"
|
||||
import { getSettings, setSettings } from "./sys/settings.js"
|
||||
import { oConf } from "./sys/config.js";
|
||||
import { error, log } from "./sys/log.js";
|
||||
import { connectToDB } from "./sys/db.js";
|
||||
import bruteforce, { suspectRequest } from "./sys/bruteforce.js";
|
||||
import { fullSetup, partiellSetup } from "./setup/config.js";
|
||||
import { addGetMethods } from "./api/get.js";
|
||||
import { addPostMethods } from "./api/post.js";
|
||||
import { wsOnConnection } from "./api/ws.js";
|
||||
import { startUpdateCerts } from "./server/serverCerts.js";
|
||||
|
||||
import { fullSetup, partiellSetup } from "./setup/config.js"
|
||||
|
||||
const config = {
|
||||
version: "0.0.1"
|
||||
|
@ -32,13 +38,13 @@ program
|
|||
global.debug = debug != null;
|
||||
if (config) {
|
||||
log("System", "Starting with config:", config);
|
||||
if(!oConf.connect(config)) dofullSetup = true;
|
||||
if (!oConf.connect(config)) dofullSetup = true;
|
||||
}
|
||||
|
||||
if(setup || dofullSetup){
|
||||
if(dofullSetup) fullSetup();
|
||||
|
||||
if (setup || dofullSetup) {
|
||||
if (dofullSetup) fullSetup();
|
||||
else partiellSetup();
|
||||
}else{
|
||||
} else {
|
||||
startServer();
|
||||
}
|
||||
});
|
||||
|
@ -46,10 +52,50 @@ program
|
|||
|
||||
program.parse();
|
||||
|
||||
var serverclose = { close: (d: () => void) => d() };
|
||||
nman.addShutdownTask(() => new Promise(async (res, rej) => {
|
||||
//await closeWebSocket();
|
||||
serverclose.close(() => res());
|
||||
}), 30000);
|
||||
|
||||
async function startServer() {
|
||||
await connectToDB();
|
||||
|
||||
const server = express();
|
||||
server.use(express.json({ limit: '100mb' }));
|
||||
server.use(express.urlencoded({ limit: '100mb', extended: false }));
|
||||
server.use(cors());
|
||||
server.use(bruteforce);
|
||||
addGetMethods(server);
|
||||
addPostMethods(server);
|
||||
if (oConf.get("ssl", "enable")) {
|
||||
log("Server", "SSL Enabled");
|
||||
oConf.readPathes(oConf.get("ssl", "privkey"), oConf.get("ssl", "cert"), oConf.get("ssl", "chain"))
|
||||
.then(([privkey, cert, chain]: any) => {
|
||||
const HTTPserver = https.createServer({ key: privkey, cert: cert, ca: chain }, server);
|
||||
const wssServer = new WebSocketServer({ server: HTTPserver });
|
||||
wssServer.on('connection', wsOnConnection);
|
||||
serverclose = HTTPserver.listen(oConf.get("System", "PORT"), () => {
|
||||
log("Server", 'Listening...');
|
||||
complete_loaded();
|
||||
});
|
||||
}).catch(err => {
|
||||
error("Server", err);
|
||||
nman.shutdown();
|
||||
});
|
||||
} else {
|
||||
log("Server", "SSL Disabled");
|
||||
const HTTPserver = http.createServer({}, server);
|
||||
const wssServer = new WebSocketServer({ server: HTTPserver });
|
||||
wssServer.on('connection', wsOnConnection);
|
||||
serverclose = HTTPserver.listen(oConf.get("System", "PORT"), () => {
|
||||
log("Server", 'Listening...');
|
||||
complete_loaded();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function complete_loaded() {
|
||||
startUpdateCerts();
|
||||
}
|
|
@ -1,3 +1,6 @@
|
|||
import { eq, select, update } from "dblang";
|
||||
import { accounts, db } from "../sys/db.js";
|
||||
|
||||
export const PERMISSIONS = {
|
||||
NONE: 0b0000000000000000, // equal to no account or blocked account
|
||||
|
||||
|
@ -14,3 +17,23 @@ export const PERMISSIONS = {
|
|||
EDIT_USERS: 0b1000000000000000,
|
||||
ALL: 0b1111111111111111,
|
||||
};
|
||||
|
||||
export const checkRight = async (accID: number, right: number) => {
|
||||
try {
|
||||
if (right == 0) return true;
|
||||
let data = await select([accounts.rights], accounts)
|
||||
.where(eq(accounts.accID, accID))
|
||||
.query(db);
|
||||
return ((data[0][accounts.rights]) & right) == right;
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const setRights = async (accID: number, rights: number) => {
|
||||
await update(accounts)
|
||||
.set(accounts.rights, rights)
|
||||
.where(eq(accounts.accID, accID))
|
||||
.query(db);
|
||||
};
|
|
@ -1,8 +1,31 @@
|
|||
import { outbagURL } from "./outbagURL.js";
|
||||
import { db, serverCerts } from "../sys/db.js"
|
||||
import { eq, exists, insert, not, select, update } from "dblang";
|
||||
import { error } from "../sys/log.js";
|
||||
import { uts } from "../sys/tools.js"
|
||||
import { eq, exists, insert, not, remove, select, update } from "dblang";
|
||||
import { error, log } from "../sys/log.js";
|
||||
import { uts } from "../sys/tools.js";
|
||||
import { getSettings, setSettings, SETTINGS } from "../sys/settings.js"
|
||||
import { generateSigningKey } from "../sys/crypto.js"
|
||||
import { oConf } from "../sys/config.js";
|
||||
import nman from "nman";
|
||||
|
||||
export const startUpdateCerts = () => {
|
||||
const update = async () => {
|
||||
var exp = parseInt(await getSettings(SETTINGS.certExpires));
|
||||
if (uts() - 60 >= (exp || 0)) {
|
||||
log("serverCert", "generete new Cert");
|
||||
let { privateKey, publicKey } = await generateSigningKey();
|
||||
await setSettings(SETTINGS.publicKey, publicKey);
|
||||
await setSettings(SETTINGS.privateKey, privateKey);
|
||||
await setSettings(SETTINGS.certExpires, String(uts() + oConf.get("System", "CertLiveSec")));
|
||||
}
|
||||
};
|
||||
let intervalId = setInterval(update, 1000 * 60);
|
||||
update();
|
||||
|
||||
nman.addShutdownTask(() => {
|
||||
clearInterval(intervalId);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
|
||||
async function updateRemote(url: string, pKey: string = ""): Promise<boolean | string> {
|
||||
|
|
|
@ -22,10 +22,10 @@ const isFile = async (path: string) => {
|
|||
}
|
||||
|
||||
const loading = () => {
|
||||
var P = ["\\", "|", "/", "-"];
|
||||
var P = "⣾⣽⣻⢿⡿⣟⣯⣷";
|
||||
var x = 0;
|
||||
let intID = setInterval(function () {
|
||||
process.stdout.write("\r" + P[(x++) % P.length]);
|
||||
process.stdout.write("\r\x1b[1m" + P[(x++) % P.length]+" ");
|
||||
}, 150);
|
||||
return () => {
|
||||
process.stdout.write("\r");
|
||||
|
@ -214,7 +214,7 @@ const database = async () => {
|
|||
oConf.set("Database", "password", resp.password);
|
||||
oConf.set("Database", "database", resp.database);
|
||||
oConf.save();
|
||||
db.close();
|
||||
await db.close();
|
||||
return true;
|
||||
} catch (e) {
|
||||
cancle();
|
||||
|
@ -235,7 +235,7 @@ const outbag = async () => {
|
|||
}, {
|
||||
type: "number",
|
||||
name: "defaultMaxRooms",
|
||||
message: "Please enter the default maximum nuber of rooms!",
|
||||
message: "Please enter the default maximum number of rooms!",
|
||||
initial: oConf.get("Settings", "defaultMaxRooms"),
|
||||
validate: i => i >= -1
|
||||
}, {
|
||||
|
|
|
@ -47,6 +47,8 @@ accounts.addAttributes({
|
|||
accID: { type: INT, primaryKey: true, autoIncrement: true },
|
||||
name: { type: VARCHAR(255), default: PERMISSIONS.DEFAULT },
|
||||
|
||||
rights: { type: BIGINT, default: PERMISSIONS.DEFAULT },
|
||||
|
||||
accountKeySalt: { type: VARCHAR(64) },
|
||||
accountKey: { type: VARCHAR(64) },
|
||||
|
||||
|
|
Loading…
Reference in a new issue