add file support, fix issue #2, add interactive auth form prototype

This commit is contained in:
fullgream 2025-03-22 04:06:26 +03:00
parent 0e411989ce
commit 1ef209d9a6
7 changed files with 299 additions and 151 deletions

View File

@ -1,3 +1,7 @@
const fs = require('fs');
const path = require('path');
const mime = require('mime-types');
const authModes = [ const authModes = [
"free", "free",
"confirmation", "confirmation",
@ -5,9 +9,24 @@ const authModes = [
"password", "password",
]; ];
function getBGMain () {
let bgMain = global.config.source.bgmain;
if (typeof bgMain === "string") {
if (!path.isAbsolute(bgMain))
bgMain = path.join(__dirname, "..", bgMain);
const mimetype = mime.lookup(bgMain);
const base64content = fs.readFileSync(bgMain, { encoding: 'base64' });
return `data:${mimetype};base64,${base64content}`;
}
return null;
}
module.exports = { module.exports = {
name: global.config.server.info.name, name: global.config.server.info.name,
tag: global.config.server.info.tag, tag: global.config.server.info.tag,
authMode: authModes[global.config.server["auth-mode"] ?? 1], authMode: authModes[global.config.server["auth-mode"] ?? 1],
secureMode: global.config.server.secureMode ?? false, secureMode: global.config.server.secureMode ?? false,
}; extSource: {
bgmain: getBGMain(),
}
};

View File

@ -22,5 +22,13 @@
}, },
"ai": { "ai": {
"apiType": "kobold" "apiType": "kobold"
},
"source": {
"bgmain": "/home/fullgream/Загрузки/21380429c504a974479d31c96a9c3c3f.jpg"
},
"rootuser": {
"login": "admin",
"password": "admin",
"activated": true
} }
} }

View File

@ -106,7 +106,7 @@
height: 650px; height: 650px;
margin-left: calc(50% - 250px); margin-left: calc(50% - 250px);
margin-top: calc(50vh - 325px); margin-top: calc(5%);
padding: 5px; padding: 5px;
} }

View File

@ -66,12 +66,39 @@ class ApiHTML {
this.api = api; this.api = api;
} }
async renderAuth (authMode) { async renderAuth (authMode, bgUrl = null) {
document.body.style.backgroundImage = "url('assets/hello/1.png')"; bgUrl = bgUrl ?? "assets/hello/1.png";
document.body.style.backgroundImage = `url(${
JSON.stringify(bgUrl)
})`;
document.body.style.backgroundSize = `${screen.width}px ${screen.height}px`;
document.getElementById("server.area").innerHTML = ''; document.getElementById("server.area").innerHTML = '';
$(document.getElementById("server.area")).append(ServerAuth.authForm); $(document.getElementById("server.area")).append(ServerAuth.authForm);
//switch (authMode) {}
[...$.find(".auth-act-item")].forEach(authEl => {
const authElJQ = $(authEl);
const isHidden = authEl.hidden;
authEl.hidden = false;
const buttonBlock = authElJQ.find(".btn-auth-block")[0];
const paramsBlock = authElJQ.find(".params-auth")[0];
buttonBlock.style.marginTop = `calc(100% - ${paramsBlock.offsetHeight}px)`;
authEl.hidden = isHidden;
});
$.find("#menu-log-in")[0].onclick = function () {
$.find("#log-in")[0].hidden = false;
$.find("#register")[0].hidden = true;
}
$.find("#menu-register")[0].onclick = function () {
$.find("#log-in")[0].hidden = true;
$.find("#register")[0].hidden = false;
}
$.find("#server-code-form")[0].hidden = authMode !== "password";
} }
} }
@ -97,4 +124,4 @@ export class ApiSocket {
}); });
return await promise; return await promise;
} }
} }

View File

@ -17,4 +17,75 @@ export class ServerAuth {
ServerAuth.authForm = document.createElement("div"); ServerAuth.authForm = document.createElement("div");
["auth-window"].forEach(c => ["auth-window"].forEach(c =>
ServerAuth.authForm.classList.add(c)); ServerAuth.authForm.classList.add(c));
ServerAuth.authForm.innerHTML = `<center><h1>Log-In</h1></center><hr/>`; ServerAuth.authForm.innerHTML = `
<center><h1>Authorization</h1></center>
<hr/>
<div id="auth-zone">
<center style="" id="register" class="auth-act-item">
<div class="params-auth">
<div class="btn-group" role="group" style="width: 90%; margin-bottom: 15px;">
<button type="button" class="btn btn-light text-dark btn-outline-light">Register</button>
<button type="button" class="btn btn-dark btn-outline-light" id="menu-log-in">Log-In</button>
</div>
<!-- Field: username -->
<div class="mb-3" style="width: 90%; margin-bottom: 15px;">
<label class="form-label">Username</label>
<input type="text" class="form-control text-light bg-dark" id="rg.username">
<div class="form-text text-light">Your username into server.</div>
</div>
<!-- Field: password -->
<div class="mb-3" style="width: 90%; margin-bottom: 15px;">
<label class="form-label">Password</label>
<input type="password" class="form-control text-light bg-dark" id="rg.password">
<div class="form-text text-light">Your password into server.</div>
</div>
<!-- Not field: retry password -->
<div class="mb-3" style="width: 90%; margin-bottom: 15px;">
<label class="form-label">Retry password</label>
<input type="password" class="form-control text-light bg-dark" id="rg.retry-password">
<div class="form-text text-light">Retry password for you don't forget password.</div>
</div>
<!-- Field: server-code -->
<div class="mb-3" style="width: 90%; margin-bottom: 15px;" id="server-code-form" hidden>
<label class="form-label">Server password</label>
<input type="text" class="form-control text-light bg-dark" id="rg.server-code">
<div class="form-text text-light">Enter the password from server.</div>
</div>
</div>
<div class="btn-auth-block">
<hr><button type="button" class="btn btn-dark btn-outline-light" id="reg-btn">Register</button>
</div>
</center>
<center style="" id="log-in" class="auth-act-item" hidden>
<div class="params-auth">
<div class="btn-group" role="group" style="width: 90%; margin-bottom: 15px;">
<button type="button" class="btn btn-dark btn-outline-light" id="menu-register">Register</button>
<button type="button" class="btn btn-light text-dark btn-outline-light">Log-In</button>
</div>
<!-- Field: username -->
<div class="mb-3" style="width: 90%; margin-bottom: 15px;">
<label class="form-label">Username</label>
<input type="text" class="form-control text-light bg-dark" id="username">
<div class="form-text text-light">Your username into server.</div>
</div>
<!-- Field: password -->
<div class="mb-3" style="width: 90%; margin-bottom: 15px;">
<label class="form-label">Password</label>
<input type="password" class="form-control text-light bg-dark" id="password">
<div class="form-text text-light">Your password into server.</div>
</div>
</div>
<div class="btn-auth-block">
<hr><button type="button" class="btn btn-dark btn-outline-light" id="auth-btn">Log-In</button>
</div>
</center>
`;

View File

@ -49,7 +49,7 @@ socket.run()
console.log("socket sends:", data); console.log("socket sends:", data);
document.title = data.name; document.title = data.name;
document.getElementById("server-name").innerText = data.name; document.getElementById("server-name").innerText = data.name;
await socket.html.renderAuth(data.authMode); await socket.html.renderAuth(data.authMode, data.extSource?.bgmain ?? null);
}) })
.catch(err => { .catch(err => {
console.error(err); console.error(err);

View File

@ -4,173 +4,196 @@ const parser = require("./packet-parser");
const frontend = require("./frontend"); const frontend = require("./frontend");
const websocket = require("./ws-handler"); const websocket = require("./ws-handler");
const crypt = require("./crypt"); const crypt = require("./crypt");
const EventEmitter = require('events'); const EventEmitter = require("events");
const net = require('net'); const net = require("net");
const fs = require('fs'); const fs = require("fs");
const path = require('path'); const path = require("path");
const { API } = require('./api'); const { API } = require("./api");
class Server extends EventEmitter { class Server extends EventEmitter {
constructor () { constructor() {
super(); super();
this.on("config.update", ({ this.on("config.update", ({ oldConfig, newConfig }) => {});
oldConfig, newConfig }
}) => {
}); run(address, port) {
} this.address = address;
this.port = port;
run (address, port) { const wsPort = global.config.server?.staticInfo?.wsPort ?? 57891;
this.address = address; const httpPort = global.config.server?.staticInfo?.httpPort ?? 49901;
this.port = port;
const wsPort = global.config.server?.staticInfo?.wsPort ?? 57891; logger.log({
const httpPort = global.config.server?.staticInfo?.httpPort ?? 49901; wsPort,
httpPort,
});
logger.log({ this.api = new API();
wsPort, httpPort
});
this.api = new API(); if (global.config.server.useFrontend)
this.frontend = frontend("127.0.0.1", httpPort);
if (global.config.server.useWebSocketAPI)
this.websocket = websocket("127.0.0.1", wsPort, this.api);
if (global.config.server.useFrontend) this.server = net.createServer((srvSocket) => {
this.frontend = frontend("127.0.0.1", httpPort); srvSocket.on("error", (err) => {
if (global.config.server.useWebSocketAPI) logger.log("Caught server socket error: ");
this.websocket = websocket("127.0.0.1", wsPort, this.api); logger.log(err.stack);
});
});
this.server = net.createServer((srvSocket) => { function socketErrHanler(err) {
srvSocket.on("error", (err) => { if (err) {
logger.log("Caught server socket error: "); logger.log("Caught server socket error: ");
logger.log(err.stack); logger.log(err.stack);
}); }
}); }
function socketErrHanler (err) { function socketDataHandler(data, socket) {
if (err) { socket.write(data, function (err) {
logger.log("Caught server socket error: "); if (err) {
logger.log(err.stack); logger.log(
} `error: ${socket.remoteAddress} (remote) throwed: ${err.name}\n${err.stack}`,
} );
function socketDataHandler (data, socket) {
socket.write(data, function(err) {
if (err) {
logger.log(`error: ${socket.remoteAddress} (remote) throwed: ${err.name}\n${err.stack}`);
} }
}); });
} }
this.server.on("connection", (socket) => { this.server.on("connection", (socket) => {
logger.log(`${socket.remoteAddress}${socket.remotePort} is connected`); logger.log(`${socket.remoteAddress}${socket.remotePort} is connected`);
socket.mainconnect = null; socket.mainconnect = null;
if (global.config.server.useWebSocketAPI) { if (global.config.server.useWebSocketAPI) {
socket.wsReverse = net.createConnection(wsPort, "127.0.0.1"); socket.wsReverse = net.createConnection(wsPort, "127.0.0.1");
socket.wsReverse.on("error", socketErrHanler); socket.wsReverse.on("error", socketErrHanler);
socket.wsReverse.on("data", (data) => socketDataHandler(data, socket)); socket.wsReverse.on("data", (data) => socketDataHandler(data, socket));
} }
if (global.config.server.useFrontend) { if (global.config.server.useFrontend) {
socket.httpReverse = net.createConnection(httpPort, "127.0.0.1"); socket.httpReverse = net.createConnection(httpPort, "127.0.0.1");
socket.httpReverse.on("error", socketErrHanler); socket.httpReverse.on("error", socketErrHanler);
socket.httpReverse.on("data", (data) => socketDataHandler(data, socket)); socket.httpReverse.on("data", (data) =>
} socketDataHandler(data, socket),
);
}
socket.on("error", (err) => { socket.on("error", (err) => {
logger.log( logger.log(`socket.on(${socket.remoteAddress}) error:`);
`socket.on(${socket.remoteAddress}) error:` logger.log(err.stack);
); try {
logger.log(err.stack); socket.end();
try { socket.end(); } catch (_) {} } catch (_) {}
// socket.end(); // socket.end();
}); });
socket.on('data', async (data) => { socket.on("data", async (data) => {
const parserResult = await parser(data); const parserResult = await parser(data);
// if (global.config.server.secureMode && data.toString().includes("http/1.1")) { // if (global.config.server.secureMode && data.toString().includes("http/1.1")) {
// logger.log("Encrypted WS!"); // logger.log("Encrypted WS!");
// parserResult.result.isWebSocket = true; // parserResult.result.isWebSocket = true;
// } // }
// const parserDecryptedResult = await parser(global.openSSH.decrypt(data)); // const parserDecryptedResult = await parser(global.openSSH.decrypt(data));
const peerAddress = `${socket.remoteAddress}:${socket.remotePort}`; const peerAddress = `${socket.remoteAddress}:${socket.remotePort}`;
//logger.log("Parser result is", parserResult); //logger.log("Parser result is", parserResult);
if (!socket.mainconnect) { if (!socket.mainconnect) {
// if (parserResult.result.isWebSocket || parserDecryptedResult.result.isWebSocket) { // if (parserResult.result.isWebSocket || parserDecryptedResult.result.isWebSocket) {
if (parserResult.result.isWebSocket) { if (parserResult.result.isWebSocket) {
socket.mainconnect = "ws"; socket.mainconnect = "ws";
if (global.config.server.useFrontend) if (global.config.server.useFrontend) socket.httpReverse.end();
socket.httpReverse.end(); if (global.config.server.useWebSocketAPI) {
if (global.config.server.useWebSocketAPI) { return socket.wsReverse.write(data, socketErrHanler);
return socket.wsReverse.write(data, socketErrHanler); }
} return;
return; } else if (parserResult.result.isHTTP) {
} socket.mainconnect = "http";
else if (parserResult.result.isHTTP) {
socket.mainconnect = "http";
socket.wsReverse.end(); socket.wsReverse.end();
if (global.config.server.useFrontend) { if (global.config.server.useFrontend) {
return socket.httpReverse.write(data, socketErrHanler); return socket.httpReverse.write(data, socketErrHanler);
} }
return; return;
} } else {
else { if (global.config.server.useFrontend) socket.httpReverse.end();
if (global.config.server.useFrontend) if (global.config.server.useWebSocketAPI) socket.wsReverse.end();
socket.httpReverse.end(); socket.mainconnect = "tcp";
if (global.config.server.useWebSocketAPI) return await this.api.exec(peerAddress, data, () => {});
socket.wsReverse.end(); }
socket.mainconnect = "tcp"; } else {
return await this.api.exec(peerAddress, data, () => {}); switch (socket.mainconnect) {
} case "ws":
} if (global.config.server.useWebSocketAPI) {
else { if (!socket.wsReverse.destroyed) {
switch (socket.mainconnect) { return socket.wsReverse.write(data, socketErrHanler);
case "ws": } else {
if (global.config.server.useWebSocketAPI) { socket.wsReverse = net.createConnection(wsPort, "127.0.0.1");
return socket.wsReverse.write(data, socketErrHanler); socket.wsReverse.on("error", socketErrHanler);
} socket.wsReverse.on("data", (data) =>
case "http": socketDataHandler(data, socket),
if (global.config.server.useFrontend) { );
return socket.httpReverse.write(data, socketErrHanler); return socket.wsReverse.write(data, socketErrHanler);
} }
case "tcp": }
return await this.api.exec(peerAddress, data); case "http":
default: if (global.config.server.useFrontend) {
return; if (!socket.httpReverse.destroyed) {
} return socket.httpReverse.write(data, socketErrHanler);
} } else {
}); socket.httpReverse = net.createConnection(
}); httpPort,
"127.0.0.1",
);
socket.httpReverse.on("error", socketErrHanler);
socket.httpReverse.on("data", (data) =>
socketDataHandler(data, socket),
);
return socket.httpReverse.write(data, socketErrHanler);
}
}
case "tcp":
return await this.api.exec(peerAddress, data, () => {});
default:
return;
}
}
});
});
this.server.on('error', (err) => { this.server.on("error", (err) => {
logger.log("Error of server"); logger.log("Error of server");
logger.log(err.stack); logger.log(err.stack);
}); });
this.server.listen(this.port, this.address, (err) => { this.server.listen(this.port, this.address, (err) => {
if (err) throw err; if (err) throw err;
logger.log(`TCP server for ai-adventure labs connected on ${this.address}:${this.port}`); logger.log(
}); `TCP server for ai-adventure labs connected on ${this.address}:${this.port}`,
} );
});
}
} }
const defaultConfigData = { const defaultConfigData = {
server: { server: {
address: "0.0.0.0", address: "0.0.0.0",
port: 8841, port: 8841,
useWebSocketAPI: true, useWebSocketAPI: true,
useFrontend: true, useFrontend: true,
staticInfo: { staticInfo: {
wsPort: 57891, wsPort: 57891,
httpPort: 49901 httpPort: 49901,
} },
}, },
database: { database: {
dialect: "sqlite", dialect: "sqlite",
path: "./data" path: "./data",
}, },
ai: { ai: {
apiType: "kobold" apiType: "kobold",
},
rootuser: {
"login": "admin",
"password": "admin",
"activated": true
} }
}; };
@ -235,4 +258,4 @@ if (global.config.server.secureMode) {
} }
else else
server.run(global.config.server.address, global.config.server.port); server.run(global.config.server.address, global.config.server.port);
*/ */