This commit is contained in:
Louis Lam
2023-11-10 21:52:38 +08:00
parent a12c6dc033
commit 9b9234434e
16 changed files with 241 additions and 73 deletions

View File

@@ -134,7 +134,7 @@ export class Database {
R.freeze(true);
if (autoloadModels) {
await R.autoloadModels("./server/model");
R.autoloadModels("./backend/models", "ts");
}
if (dbConfig.type === "sqlite") {

View File

@@ -28,6 +28,7 @@ import { TerminalSocketHandler } from "./socket-handlers/terminal-socket-handler
import { Stack } from "./stack";
import { Cron } from "croner";
import gracefulShutdown from "http-graceful-shutdown";
import User from "./models/user";
export class DockgeServer {
app : Express;
@@ -194,7 +195,7 @@ export class DockgeServer {
cors,
});
this.io.on("connection", (socket: Socket) => {
this.io.on("connection", async (socket: Socket) => {
log.info("server", "Socket connected!");
this.sendInfo(socket, true);
@@ -208,6 +209,20 @@ export class DockgeServer {
for (const socketHandler of this.socketHandlerList) {
socketHandler.create(socket as DockgeSocket, this);
}
// ***************************
// Better do anything after added all socket handlers here
// ***************************
log.debug("auth", "check auto login");
if (await Settings.get("disableAuth")) {
log.info("auth", "Disabled Auth: auto login to admin");
this.afterLogin(socket as DockgeSocket, await R.findOne("user"));
socket.emit("autoLogin");
} else {
log.debug("auth", "need auth");
}
});
this.io.on("disconnect", () => {
@@ -216,8 +231,17 @@ export class DockgeServer {
}
prepareServer() {
async afterLogin(socket : DockgeSocket, user : User) {
socket.userID = user.id;
socket.join(user.id.toString());
this.sendInfo(socket);
try {
this.sendStackList();
} catch (e) {
log.error("server", e);
}
}
/**

View File

@@ -20,7 +20,7 @@ export class User extends BeanModel {
/**
* Reset this users password
* @param {string} newPassword Users new password
* @param {string} newPassword
* @returns {Promise<void>}
*/
async resetPassword(newPassword : string) {
@@ -42,3 +42,5 @@ export class User extends BeanModel {
}
}
export default User;

View File

@@ -183,6 +183,26 @@ export class DockerSocketHandler extends SocketHandler {
callbackError(e, callback);
}
});
// Services status
socket.on("serviceStatusList", async (stackName : unknown, callback) => {
try {
checkLogin(socket);
if (typeof(stackName) !== "string") {
throw new ValidationError("Stack name must be a string");
}
const stack = Stack.getStack(server, stackName);
const serviceStatusList = Object.fromEntries(await stack.getServiceStatusList());
callback({
ok: true,
serviceStatusList,
});
} catch (e) {
callbackError(e, callback);
}
});
}
saveStack(socket : DockgeSocket, server : DockgeServer, name : unknown, composeYAML : unknown, isAdd : unknown) : Stack {

View File

@@ -72,7 +72,7 @@ export class MainSocketHandler extends SocketHandler {
}
log.debug("auth", "afterLogin");
await this.afterLogin(server, socket, user);
await server.afterLogin(socket, user);
log.debug("auth", "afterLogin ok");
log.info("auth", `Successfully logged in user ${decoded.username}. IP=${clientIP}`);
@@ -129,7 +129,7 @@ export class MainSocketHandler extends SocketHandler {
if (user) {
if (user.twofa_status === 0) {
this.afterLogin(server, socket, user);
server.afterLogin(socket, user);
log.info("auth", `Successfully logged in user ${data.username}. IP=${clientIP}`);
@@ -152,7 +152,7 @@ export class MainSocketHandler extends SocketHandler {
const verify = notp.totp.verify(data.token, user.twofa_secret, twoFAVerifyOptions);
if (user.twofa_last_token !== data.token && verify) {
this.afterLogin(server, socket, user);
server.afterLogin(socket, user);
await R.exec("UPDATE `user` SET twofa_last_token = ? WHERE id = ? ", [
data.token,
@@ -189,6 +189,35 @@ export class MainSocketHandler extends SocketHandler {
});
// Change Password
socket.on("changePassword", async (password, callback) => {
try {
checkLogin(socket);
if (! password.newPassword) {
throw new Error("Invalid new password");
}
if (passwordStrength(password.newPassword).value === "Too weak") {
throw new Error("Password is too weak. It should contain alphabetic and numeric characters. It must be at least 6 characters in length.");
}
let user = await doubleCheckPassword(socket, password.currentPassword);
await user.resetPassword(password.newPassword);
callback({
ok: true,
msg: "Password has been updated successfully.",
});
} catch (e) {
callback({
ok: false,
msg: e.message,
});
}
});
socket.on("getSettings", async (callback) => {
try {
checkLogin(socket);
@@ -221,6 +250,8 @@ export class MainSocketHandler extends SocketHandler {
await doubleCheckPassword(socket, currentPassword);
}
console.log(data);
await Settings.setSettings("general", data);
callback({
@@ -239,19 +270,6 @@ export class MainSocketHandler extends SocketHandler {
});
}
async afterLogin(server: DockgeServer, socket : DockgeSocket, user : User) {
socket.userID = user.id;
socket.join(user.id.toString());
server.sendInfo(socket);
try {
server.sendStackList(socket);
} catch (e) {
log.error("server", e);
}
}
async login(username : string, password : string) {
if (typeof username !== "string" || typeof password !== "string") {
return null;

View File

@@ -333,4 +333,26 @@ export class Stack {
terminal.join(socket);
terminal.start();
}
async getServiceStatusList() {
let statusList = new Map<string, number>();
let res = childProcess.execSync("docker compose ps --format json", {
cwd: this.path,
});
let lines = res.toString().split("\n");
console.log(lines);
for (let line of lines) {
try {
let obj = JSON.parse(line);
statusList.set(obj.Service, obj.State);
} catch (e) {
}
}
return statusList;
}
}