This commit is contained in:
jusax23 2023-03-10 12:44:23 +01:00
parent 869f1503c2
commit 694dff14fc
Signed by: jusax23
GPG key ID: 499E2AA870C1CD41
13 changed files with 288 additions and 18 deletions

2
.gitignore vendored
View file

@ -4,3 +4,5 @@ config.juml
.vscode .vscode
test test
build build
testLocal.juml
openssl

View file

@ -10,6 +10,12 @@ pipeline:
- mkdir build - mkdir build
- npm run prepublish - npm run prepublish
- npm run bundleRelease - npm run bundleRelease
test:
image: node:18-alpine
commands:
- apk add openssl
- sh genSelfSignedCert.sh
- node tests/tester.js ci
buildBin: buildBin:
image: node:18 image: node:18
commands: commands:
@ -35,3 +41,12 @@ pipeline:
when: when:
event: tag event: tag
secrets: [ gitea_token, api_url ] secrets: [ gitea_token, api_url ]
services:
database:
image: mysql
environment:
- MYSQL_DATABASE=outbag
- MYSQL_USER=outbag
- MYSQL_PASSWORD=12345678

3
genSelfSignedCert.sh Normal file
View file

@ -0,0 +1,3 @@
mkdir -p openssl
openssl req -nodes -new -x509 -keyout openssl/server.key -out openssl/server.cert -subj '/CN=localhost'
touch openssl/server.chain

View file

@ -45,22 +45,29 @@ export const signup: Act = {
return; return;
} }
let salt = get64(16); let salt = get64(16);
let req = await insert(accounts.name, accounts.rights, accounts.accountKey, accounts.accountKeySalt) try {
.add(data.name, userNum == 0 ? PERMISSIONS.ALL : PERMISSIONS.DEFAULT, sha256(salt + data.accountKey), salt) let req = await insert(accounts.name, accounts.rights, accounts.accountKey, accounts.accountKeySalt)
.query(db); .add(data.name, userNum == 0 ? PERMISSIONS.ALL : PERMISSIONS.DEFAULT, sha256(salt + data.accountKey), salt)
if (req.affectedRows > 0) { .query(db);
let accID = Number(req.insertId); if (req.affectedRows > 0) {
if (!isNaN(accID)) { let accID = Number(req.insertId);
aws("ok", ""); if (!isNaN(accID)) {
client.state = STATE.client; aws("ok", "");
client.accID = accID; client.state = STATE.client;
client.name = data.name; client.accID = accID;
client.server = new outbagServer(data.server, oConf.get("System", "URL") + "", oConf.get("System", "PATHexposed") + "", oConf.get("System", "PORTexposed") + ""); client.name = data.name;
client.server = new outbagServer(data.server, oConf.get("System", "URL") + "", oConf.get("System", "PATHexposed") + "", oConf.get("System", "PORTexposed") + "");
}
} else {
client.suspect();
aws("error", "existence");
} }
} else { } catch (error) {
client.suspect(); client.suspect();
aws("error", "existence"); aws("error", "existence");
} }
} }
}; };

View file

@ -369,4 +369,4 @@ export const roomMeta: Act = {
.query(db); .query(db);
aws("ok", ""); aws("ok", "");
} }
} };

View file

@ -37,6 +37,9 @@ program
.action(({ config, debug, setup }) => { .action(({ config, debug, setup }) => {
let dofullSetup = false; let dofullSetup = false;
global.debug = debug != null; global.debug = debug != null;
if(global.debug){
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = "0";
}
if (config) { if (config) {
log("System", "Starting with config:", config); log("System", "Starting with config:", config);
if (!oConf.connect(config)) dofullSetup = true; if (!oConf.connect(config)) dofullSetup = true;
@ -75,7 +78,9 @@ async function startServer() {
log("Server", "SSL Enabled"); log("Server", "SSL Enabled");
oConf.readPathes(oConf.get("ssl", "privkey"), oConf.get("ssl", "cert"), oConf.get("ssl", "chain")) oConf.readPathes(oConf.get("ssl", "privkey"), oConf.get("ssl", "cert"), oConf.get("ssl", "chain"))
.then(([privkey, cert, chain]: any) => { .then(([privkey, cert, chain]: any) => {
const HTTPserver = https.createServer({ key: privkey, cert: cert, ca: chain }, server); const HTTPserver = chain != "" ?
https.createServer({ key: privkey, cert: cert, ca: chain }, server) :
https.createServer({ key: privkey, cert: cert }, server);
const wssServer = new WebSocketServer({ server: HTTPserver }); const wssServer = new WebSocketServer({ server: HTTPserver });
wssServer.on('connection', wsOnConnection); wssServer.on('connection', wsOnConnection);
serverclose = HTTPserver.listen(oConf.get("System", "PORT"), () => { serverclose = HTTPserver.listen(oConf.get("System", "PORT"), () => {
@ -101,7 +106,7 @@ async function complete_loaded() {
startUpdateCert(); startUpdateCert();
await wait(500); await wait(500);
let succ = await generateTag(); let succ = await generateTag();
if(!succ) error("Outbag", "Could not check own Server Tag. Remote-Auth may not work! Check if the Server is reachable and the config ist correct!"); if (!succ) error("Outbag", "Could not check own Server Tag. Remote-Auth may not work! Check if the Server is reachable and the config ist correct!");
activatePost(); activatePost();
activateWS(); activateWS();
log("Server", 'Listening...'); log("Server", 'Listening...');

View file

@ -46,7 +46,7 @@ nMan.addShutdownTask(db.close, 3000, 10);
export const accounts = db.newTable("accounts"); export const accounts = db.newTable("accounts");
accounts.addAttributes({ accounts.addAttributes({
accID: { type: INT, primaryKey: true, autoIncrement: true }, accID: { type: INT, primaryKey: true, autoIncrement: true },
name: { type: VARCHAR(100), default: PERMISSIONS.DEFAULT }, name: { type: VARCHAR(100), unique: true, default: PERMISSIONS.DEFAULT },
rights: { type: INT, default: PERMISSIONS.DEFAULT }, rights: { type: INT, default: PERMISSIONS.DEFAULT },

27
test.juml Normal file
View file

@ -0,0 +1,27 @@
[System]
#The Server will listen on this Port!
PORT=7224
PORTexposed=7224
PATHexposed=/
URL=localhost
CertLiveSec=2592000
[ssl]
enable=true
privkey=openssl/server.key
cert=openssl/server.cert
chain=openssl/server.chain
[Database]
host=database
port=3306
user=root
password=12345678
database=outbag
[Settings]
maxUsers=2
defaultMaxRooms=3
defaultMaxRoomSize=10
defaultMaxUsersPerRoom=2

3
tests/post.js Normal file
View file

@ -0,0 +1,3 @@
export async function postTester(){
}

43
tests/tester.js Normal file
View file

@ -0,0 +1,43 @@
import { spawn } from "child_process";
import { postTester } from "./post.js";
import { wsTester } from "./ws.js";
let inCI = process.argv.includes("ci");
const ls = spawn('node', ['.', '-c', inCI ? 'test.juml' : 'testLocal.juml', '-d']);
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
ls.stdout.on('data', (data) => {
process.stdout.write(data);
if(data.includes("Listening...")) test();
});
ls.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
ls.on('close', (code) => {
console.log(`child process exited with code ${code}`);
process.exit(code);
});
function kill() {
ls.kill('SIGINT');
}
let startet = false;
async function test() {
if(startet) return;
startet = true;
console.log("Start testing");
let url = "localhost:7224";
await wsTester("wss://" + url + "/", kill);
await postTester("https://" + url + "/", kill);
kill();
}

132
tests/ws.js Normal file
View file

@ -0,0 +1,132 @@
import WebSocket from 'ws';
import { generateSigningKey, sign } from '../dist/sys/crypto.js';
import { uts, wait } from '../dist/sys/tools.js';
import * as ws from "./ws/ws.js"
function conn(url) {
const ws = new WebSocket(url);
ws.on('close', function open() {
wsOpen = false;
});
let wsOpen = true;
var list = [];
var c = 0;
ws.on('message', function message(data) {
data = data.toString();
if (data == "error") return void console.log("Server error");
var json = JSON.parse(data);
for (let i = 0; i < list.length; i++) {
const e = list[i];
if (e[0] == json.id) {
e[2]({ state: json.state, data: json.data });
list.splice(i, 1);
return;
}
}
});
this.close = function () {
ws.close();
}
setInterval(() => {
for (let i = 0; i < list.length; i++) {
const e = list[i];
if (e[1] + 5 < uts()) {
e[2]("timeout");
list.splice(i, 1);
}
}
}, 1000);
function req(act, data) {
return new Promise((res, rej) => {
if (!wsOpen) {
console.error("WebSocket is closed");
rej("WebSocket is closed");
return;
}
var id = ++c;
list.push([id, uts(), res, rej]);
ws.send(JSON.stringify({
id,
act,
data
}));
})
}
this.req = req;
};
function shallowEqual(object1, object2) {
const keys1 = Object.keys(object1);
const keys2 = Object.keys(object2);
if (keys1.length < keys2.length) {
return false;
}
for (let key of keys1) {
if (object1[key] != object2[key]) {
return false;
}
}
return true;
}
export async function wsTester(url, kill) {
async function test(conn, act, data, expState, expData) {
console.log("Testing Act:", act, "with Data:", data);
let resp = await conn.req(act, data);
if (resp.state != expState) {
console.error(`Expected state: '${expState}', but got: '${resp.state}'`);
kill();
process.exit(1);
}
if (typeof expData == "object" && expData != null) {
if (!shallowEqual(expData, resp.data)) {
console.error(`Expected data: '${expData}', but got: '${resp.data}'`);
kill();
process.exit(1);
}
} else {
if (expData != resp.data) {
console.error(`Expected data: '${expData}', but got: '${resp.data}'`);
kill();
process.exit(1);
}
}
return resp.data;
}
for (const k in ws) {
console.log(`Testing '${k}':`);
const handler = [new conn(url)];
await wait(100);
const currTest = ws[k];
let resp = true;
try {
resp = await currTest(handler[0], test, async ()=>{
let h = new conn(url);
await wait(100);
handler.push(h);
return h;
});
} catch (error) {
console.error("Test Error: ", error);
kill();
process.exit(1);
}
handler.forEach(h=>h.close());
if (resp === false) {
console.log("Test respond with error indication!");
kill();
process.exit(1);
}
}
}

32
tests/ws/login.js Normal file
View file

@ -0,0 +1,32 @@
let name1 = "testUser1";
let name2 = "testUser2";
let name3 = "testUser3";
let accountKey = "123456789";
export const signup = async (handler, req, newHandler) => {
await req(handler, "signup", {
name: name1,
server: "localhost:7224",
accountKey
}, "ok", "");
await req(handler, "signup", {
name: name1,
server: "localhost:7224",
accountKey
}, "error", "wrongstate");
await req(await newHandler(), "signup", {
name: name1,
server: "localhost:7224",
accountKey
}, "error", "existence");
await req(await newHandler(), "signup", {
name: name2,
server: "localhost:7224",
accountKey
}, "ok", "");
await req(await newHandler(), "signup", {
name: name2,
server: "localhost:7224",
accountKey
}, "error", "config");
};

1
tests/ws/ws.js Normal file
View file

@ -0,0 +1 @@
export * from "./login.js";