mirror of
https://github.com/louislam/dockge.git
synced 2025-08-12 14:07:02 +02:00
Compare commits
6 Commits
s
...
build-wind
Author | SHA1 | Date | |
---|---|---|---|
4400ba5dd6 | |||
2b428e139c | |||
587d2dcaca | |||
5f1f3593fd | |||
e570374a48 | |||
316c566c76 |
@ -194,39 +194,6 @@ export class DockgeServer {
|
||||
// Create Socket.io
|
||||
this.io = new socketIO.Server(this.httpServer, {
|
||||
cors,
|
||||
allowRequest: (req, callback) => {
|
||||
let isOriginValid = true;
|
||||
const bypass = isDev;
|
||||
|
||||
if (!bypass) {
|
||||
let host = req.headers.host;
|
||||
|
||||
// If this is set, it means the request is from the browser
|
||||
let origin = req.headers.origin;
|
||||
|
||||
// If this is from the browser, check if the origin is allowed
|
||||
if (origin) {
|
||||
try {
|
||||
let originURL = new URL(origin);
|
||||
|
||||
if (host !== originURL.host) {
|
||||
isOriginValid = false;
|
||||
log.error("auth", `Origin (${origin}) does not match host (${host}), IP: ${req.socket.remoteAddress}`);
|
||||
}
|
||||
} catch (e) {
|
||||
// Invalid origin url, probably not from browser
|
||||
isOriginValid = false;
|
||||
log.error("auth", `Invalid origin url (${origin}), IP: ${req.socket.remoteAddress}`);
|
||||
}
|
||||
} else {
|
||||
log.info("auth", `Origin is not set, IP: ${req.socket.remoteAddress}`);
|
||||
}
|
||||
} else {
|
||||
log.debug("auth", "Origin check is bypassed");
|
||||
}
|
||||
|
||||
callback(null, isOriginValid);
|
||||
}
|
||||
});
|
||||
|
||||
this.io.on("connection", async (socket: Socket) => {
|
||||
@ -611,35 +578,4 @@ export class DockgeServer {
|
||||
finalFunction() {
|
||||
log.info("server", "Graceful shutdown successful!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Force connected sockets of a user to refresh and disconnect.
|
||||
* Used for resetting password.
|
||||
* @param {string} userID
|
||||
* @param {string?} currentSocketID
|
||||
*/
|
||||
disconnectAllSocketClients(userID: number, currentSocketID? : string) {
|
||||
for (const rawSocket of this.io.sockets.sockets.values()) {
|
||||
let socket = rawSocket as DockgeSocket;
|
||||
if (socket.userID === userID && socket.id !== currentSocketID) {
|
||||
try {
|
||||
socket.emit("refresh");
|
||||
socket.disconnect();
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isSSL() {
|
||||
return this.config.sslKey && this.config.sslCert;
|
||||
}
|
||||
|
||||
getLocalWebSocketURL() {
|
||||
const protocol = this.isSSL() ? "wss" : "ws";
|
||||
const host = this.config.hostname || "localhost";
|
||||
return `${protocol}://${host}:${this.config.port}`;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -211,8 +211,6 @@ export class MainSocketHandler extends SocketHandler {
|
||||
let user = await doubleCheckPassword(socket, password.currentPassword);
|
||||
await user.resetPassword(password.newPassword);
|
||||
|
||||
server.disconnectAllSocketClients(user.id, socket.id);
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
msg: "Password has been updated successfully.",
|
||||
@ -282,18 +280,6 @@ export class MainSocketHandler extends SocketHandler {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Disconnect all other socket clients of the user
|
||||
socket.on("disconnectOtherSocketClients", async () => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
server.disconnectAllSocketClients(socket.userID, socket.id);
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
log.warn("disconnectOtherSocketClients", e.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async login(username : string, password : string) : Promise<User | null> {
|
||||
|
@ -21,11 +21,6 @@ export interface LooseObject {
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface BaseRes {
|
||||
ok: boolean;
|
||||
msg?: string;
|
||||
}
|
||||
|
||||
let randomBytes : (numBytes: number) => Uint8Array;
|
||||
initRandomBytes();
|
||||
|
||||
|
92
extra/build-windows.ts
Normal file
92
extra/build-windows.ts
Normal file
@ -0,0 +1,92 @@
|
||||
import fsAsync from "fs/promises";
|
||||
import unzipper from "unzipper";
|
||||
import stream from "node:stream";
|
||||
import { fileExists } from "../backend/util-server";
|
||||
|
||||
const version = process.env.VERSION;
|
||||
|
||||
if (!version) {
|
||||
console.error("VERSION env not set");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const output = `./private/build/dockgen-${version}-win-x64.zip`;
|
||||
|
||||
if (await fileExists(output)) {
|
||||
console.error(`${output} already exists`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`Building ${output}`);
|
||||
|
||||
const nodeVersion = "18.17.1";
|
||||
const buildPath = "./private/build/windows";
|
||||
const nodePath = `${buildPath}/node`;
|
||||
const nodeTempPath = `${buildPath}/node-v${nodeVersion}-win-x64`;
|
||||
const corePath = `${buildPath}/core`;
|
||||
|
||||
// Clear
|
||||
await fsAsync.rm(`${buildPath}/dockge-${version}`, {
|
||||
recursive: true,
|
||||
force: true
|
||||
});
|
||||
|
||||
await fsAsync.rm(corePath, {
|
||||
recursive: true,
|
||||
force: true
|
||||
});
|
||||
|
||||
// mkdir
|
||||
await fsAsync.mkdir(buildPath, {
|
||||
recursive: true
|
||||
});
|
||||
|
||||
// Download Node.js if not exists
|
||||
// Download,pipe to unzipper and extract to nodePath
|
||||
if (!await fileExists(nodePath)) {
|
||||
console.log(`Downloading Node.js ${nodeVersion}`);
|
||||
|
||||
try {
|
||||
await download(`https://nodejs.org/dist/v${nodeVersion}/node-v${nodeVersion}-win-x64.zip`);
|
||||
// Rename folder
|
||||
await fsAsync.rename(nodeTempPath, nodePath);
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
console.error(e.message);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
console.log(`Node.js ${nodeVersion} already exists, skipping download`);
|
||||
}
|
||||
|
||||
// Download Dockge from GitHub
|
||||
console.log(`Downloading Dockge ${version} from GitHub`);
|
||||
|
||||
try {
|
||||
await download(`https://github.com/louislam/dockge/archive/refs/tags/${version}.zip`);
|
||||
// Rename folder
|
||||
await fsAsync.rename(`${buildPath}/dockge-${version}`, corePath);
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
console.error(e.message);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function download(url : string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch(url).then((res) => {
|
||||
if (res.body) {
|
||||
// @ts-ignore
|
||||
stream.Readable.fromWeb(res.body)
|
||||
.pipe(unzipper.Extract({
|
||||
path: buildPath,
|
||||
}))
|
||||
.on("close", resolve);
|
||||
} else {
|
||||
reject(new Error(`Unable to download ${url}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
@ -4,8 +4,6 @@ import readline from "readline";
|
||||
import { User } from "../backend/models/user";
|
||||
import { DockgeServer } from "../backend/dockge-server";
|
||||
import { log } from "../backend/log";
|
||||
import { io } from "socket.io-client";
|
||||
import { BaseRes } from "../backend/util-common";
|
||||
|
||||
console.log("== Dockge Reset Password Tool ==");
|
||||
|
||||
@ -14,10 +12,11 @@ const rl = readline.createInterface({
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
const server = new DockgeServer();
|
||||
|
||||
export const main = async () => {
|
||||
const server = new DockgeServer();
|
||||
|
||||
// Check if
|
||||
|
||||
console.log("Connecting the database");
|
||||
try {
|
||||
await Database.init(server);
|
||||
@ -48,16 +47,12 @@ export const main = async () => {
|
||||
// Reset all sessions by reset jwt secret
|
||||
await server.initJWTSecret();
|
||||
|
||||
console.log("Password reset successfully.");
|
||||
|
||||
// Disconnect all other socket clients of the user
|
||||
await disconnectAllSocketClients(user.username, password);
|
||||
|
||||
break;
|
||||
} else {
|
||||
console.log("Passwords do not match, please try again.");
|
||||
}
|
||||
}
|
||||
console.log("Password reset successfully.");
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
@ -84,47 +79,6 @@ function question(question : string) : Promise<string> {
|
||||
});
|
||||
}
|
||||
|
||||
function disconnectAllSocketClients(username : string, password : string) : Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
const url = server.getLocalWebSocketURL();
|
||||
|
||||
console.log("Connecting to " + url + " to disconnect all other socket clients");
|
||||
|
||||
// Disconnect all socket connections
|
||||
const socket = io(url, {
|
||||
transports: [ "websocket" ],
|
||||
reconnection: false,
|
||||
timeout: 5000,
|
||||
});
|
||||
socket.on("connect", () => {
|
||||
socket.emit("login", {
|
||||
username,
|
||||
password,
|
||||
}, (res : BaseRes) => {
|
||||
if (res.ok) {
|
||||
console.log("Logged in.");
|
||||
socket.emit("disconnectOtherSocketClients");
|
||||
} else {
|
||||
console.warn("Login failed.");
|
||||
console.warn("Please restart the server to disconnect all sessions.");
|
||||
}
|
||||
socket.close();
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("connect_error", function () {
|
||||
// The localWebSocketURL is not guaranteed to be working for some complicated Uptime Kuma setup
|
||||
// Ask the user to restart the server manually
|
||||
console.warn("Failed to connect to " + url);
|
||||
console.warn("Please restart the server to disconnect all sessions manually.");
|
||||
resolve();
|
||||
});
|
||||
socket.on("disconnect", () => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (!process.env.TEST_BACKEND) {
|
||||
main();
|
||||
}
|
||||
|
@ -202,10 +202,6 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("refresh", () => {
|
||||
location.reload();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -299,12 +299,12 @@ export default {
|
||||
computed: {
|
||||
|
||||
urls() {
|
||||
if (!this.jsonConfig["x-dockge"] || !this.jsonConfig["x-dockge"].urls || !Array.isArray(this.jsonConfig["x-dockge"].urls)) {
|
||||
if (!this.envsubstJSONConfig["x-dockge"] || !this.envsubstJSONConfig["x-dockge"].urls || !Array.isArray(this.envsubstJSONConfig["x-dockge"].urls)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let urls = [];
|
||||
for (const url of this.jsonConfig["x-dockge"].urls) {
|
||||
for (const url of this.envsubstJSONConfig["x-dockge"].urls) {
|
||||
let display;
|
||||
try {
|
||||
let obj = new URL(url);
|
||||
|
23
package.json
23
package.json
@ -10,13 +10,15 @@
|
||||
"lint": "eslint \"**/*.{ts,vue}\"",
|
||||
"check-ts": "tsc --noEmit",
|
||||
"start": "tsx ./backend/index.ts",
|
||||
"dev": "concurrently -k -r \"wait-on tcp:5000 && pnpm run dev:backend \" \"pnpm run dev:frontend\"",
|
||||
"dev:backend": "cross-env NODE_ENV=development tsx watch --inspect ./backend/index.ts",
|
||||
"dev:frontend": "cross-env NODE_ENV=development vite --host --config ./frontend/vite.config.ts",
|
||||
"release-final": "tsx ./extra/test-docker.ts && tsx extra/update-version.ts && pnpm run build:frontend && npm run build:docker",
|
||||
"release-final": "tsx ./extra/test-docker.ts && tsx extra/update-version.ts && pnpm run build:frontend && pnpm run build:docker",
|
||||
"build:frontend": "vite build --config ./frontend/vite.config.ts",
|
||||
"build:docker-base": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/dockge:base -f ./docker/Base.Dockerfile . --push",
|
||||
"build:docker": "node ./extra/env2arg.js docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/dockge:latest -t louislam/dockge:1 -t louislam/dockge:$VERSION --target release -f ./docker/Dockerfile . --push",
|
||||
"build:docker-nightly": "pnpm run build:frontend && docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/dockge:nightly --target nightly -f ./docker/Dockerfile . --push",
|
||||
"build:windows": "tsx ./extra/build-windows.ts",
|
||||
"build:healthcheck": "docker buildx build -f docker/BuildHealthCheck.Dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/dockge:build-healthcheck . --push",
|
||||
"start-docker": "docker run --rm -p 5001:5001 --name dockge louislam/dockge:latest",
|
||||
"mark-as-nightly": "tsx ./extra/mark-as-nightly.ts",
|
||||
@ -24,7 +26,7 @@
|
||||
"reset-password": "tsx ./extra/reset-password.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@homebridge/node-pty-prebuilt-multiarch": "~0.11.11",
|
||||
"@homebridge/node-pty-prebuilt-multiarch": "~0.11.12",
|
||||
"@inventage/envsubst": "^0.16.0",
|
||||
"@louislam/sqlite3": "~15.1.6",
|
||||
"bcryptjs": "~2.4.3",
|
||||
@ -42,7 +44,8 @@
|
||||
"jwt-decode": "~3.1.2",
|
||||
"knex": "~2.5.1",
|
||||
"limiter-es6-compat": "~2.1.2",
|
||||
"mysql2": "~3.6.3",
|
||||
"mysql2": "~3.6.5",
|
||||
"node-windows": "1.0.0-beta.8",
|
||||
"promisify-child-process": "~4.1.2",
|
||||
"redbean-node": "~0.3.3",
|
||||
"socket.io": "~4.7.2",
|
||||
@ -55,21 +58,23 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@actions/github": "^6.0.0",
|
||||
"@fontsource/jetbrains-mono": "^5.0.17",
|
||||
"@fontsource/jetbrains-mono": "^5.0.18",
|
||||
"@fortawesome/fontawesome-svg-core": "6.4.2",
|
||||
"@fortawesome/free-regular-svg-icons": "6.4.2",
|
||||
"@fortawesome/free-solid-svg-icons": "6.4.2",
|
||||
"@fortawesome/vue-fontawesome": "3.0.3",
|
||||
"@types/bcryptjs": "^2.4.6",
|
||||
"@types/bootstrap": "~5.2.9",
|
||||
"@types/bootstrap": "~5.2.10",
|
||||
"@types/command-exists": "~1.2.3",
|
||||
"@types/express": "~4.17.21",
|
||||
"@types/jsonwebtoken": "~9.0.5",
|
||||
"@types/unzipper": "^0.10.9",
|
||||
"@typescript-eslint/eslint-plugin": "~6.8.0",
|
||||
"@typescript-eslint/parser": "~6.8.0",
|
||||
"@vitejs/plugin-vue": "~4.5.0",
|
||||
"@vitejs/plugin-vue": "~4.5.2",
|
||||
"bootstrap": "5.3.2",
|
||||
"bootstrap-vue-next": "~0.14.10",
|
||||
"concurrently": "^8.2.2",
|
||||
"cross-env": "~7.0.3",
|
||||
"eslint": "~8.50.0",
|
||||
"eslint-plugin-jsdoc": "~46.8.2",
|
||||
@ -78,15 +83,17 @@
|
||||
"sass": "~1.68.0",
|
||||
"typescript": "~5.2.2",
|
||||
"unplugin-vue-components": "~0.25.2",
|
||||
"vite": "~5.0.0",
|
||||
"unzipper": "^0.10.14",
|
||||
"vite": "~5.0.7",
|
||||
"vite-plugin-compression": "~0.5.1",
|
||||
"vue": "~3.3.8",
|
||||
"vue": "~3.3.11",
|
||||
"vue-eslint-parser": "~9.3.2",
|
||||
"vue-i18n": "~9.5.0",
|
||||
"vue-prism-editor": "2.0.0-alpha.2",
|
||||
"vue-qrcode": "~2.2.0",
|
||||
"vue-router": "~4.2.5",
|
||||
"vue-toastification": "2.0.0-rc.5",
|
||||
"wait-on": "^7.2.0",
|
||||
"xterm": "5.4.0-beta.37",
|
||||
"xterm-addon-web-links": "~0.9.0"
|
||||
}
|
||||
|
1011
pnpm-lock.yaml
generated
1011
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user