Skip to content

Commit

Permalink
Update from upstream (#271)
Browse files Browse the repository at this point in the history
* Fix

* Fix

* Fix logout

* Fix logout

* Fix

* WIP
  • Loading branch information
louislam authored Dec 10, 2023
1 parent 587d2dc commit 07c52cc
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 4 deletions.
64 changes: 64 additions & 0 deletions backend/dockge-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,39 @@ 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) => {
Expand Down Expand Up @@ -578,4 +611,35 @@ 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}`;
}

}
14 changes: 14 additions & 0 deletions backend/socket-handlers/main-socket-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@ 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.",
Expand Down Expand Up @@ -280,6 +282,18 @@ 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> {
Expand Down
5 changes: 5 additions & 0 deletions backend/util-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export interface LooseObject {
[key: string]: any
}

export interface BaseRes {
ok: boolean;
msg?: string;
}

let randomBytes : (numBytes: number) => Uint8Array;
initRandomBytes();

Expand Down
54 changes: 50 additions & 4 deletions extra/reset-password.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ 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 ==");

Expand All @@ -12,11 +14,10 @@ const rl = readline.createInterface({
output: process.stdout
});

export const main = async () => {
const server = new DockgeServer();
const server = new DockgeServer();

export const main = async () => {
// Check if

console.log("Connecting the database");
try {
await Database.init(server);
Expand Down Expand Up @@ -47,12 +48,16 @@ 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) {
Expand All @@ -79,6 +84,47 @@ 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();
}
4 changes: 4 additions & 0 deletions frontend/src/mixins/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,10 @@ export default defineComponent({
}
}
});

socket.on("refresh", () => {
location.reload();
});
},

/**
Expand Down

0 comments on commit 07c52cc

Please sign in to comment.