From d889e5be5b98f10c8823fe4ec665f10c031f47ac Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 17:56:20 +0100 Subject: [PATCH 001/190] Update README.template.md --- .github/templates/README.template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/templates/README.template.md b/.github/templates/README.template.md index e364b7b..c650b32 100644 --- a/.github/templates/README.template.md +++ b/.github/templates/README.template.md @@ -2,7 +2,7 @@ WoL Redirect is a Docker Container with graphical interface, which allows users to wake up their services. Integrates with all of the WoL Containers. - +s _Well, except for meteorite_ ## Installation From 280bacc837cfd7b4bf03b061610667a1a2aeb998 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 6 Dec 2025 16:56:32 +0000 Subject: [PATCH 002/190] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9cacc26..ec94874 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ WoL Redirect is a Docker Container with graphical interface, which allows users to wake up their services. Integrates with all of the WoL Containers. - +s _Well, except for meteorite_ ## Installation From 7a29fe396ea3196115a861b7aec9887f69aead39 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 17:57:11 +0100 Subject: [PATCH 003/190] Update docker-compose.yaml --- docker-compose.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index f4aaac1..93cadb5 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,4 +1,3 @@ ---- services: wol: container_name: wol-client From 96aff4ca4e96c8a4408411809b727ae3b6315600 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 6 Dec 2025 16:57:22 +0000 Subject: [PATCH 004/190] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index ec94874..e449322 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ _Well, except for meteorite_ Get the latest `docker-compose.yaml` file: ```yaml ---- services: wol: container_name: wol-client From 3c878c9e09c8acb405a3e57c18c15f8b9be9bded Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 18:08:49 +0100 Subject: [PATCH 005/190] fix --- src/utils/fs.js | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/utils/fs.js b/src/utils/fs.js index 85e90f8..07d11e9 100644 --- a/src/utils/fs.js +++ b/src/utils/fs.js @@ -1,16 +1,12 @@ const fs = require("fs") -const path = require("path") function exists(p) { - fs.stat(p, function (err, stat) { - if (err == null) { - return true - } else if (err.code === "ENOENT") { - return false - } else { - return false - } - }) + try { + fs.statSync(p) + return true + } catch (err) { + return false + } } module.exports = { exists } From eaf2f5a9fadcab1a3be01e6d0fdd5ff73d29924f Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 18:15:46 +0100 Subject: [PATCH 006/190] fix --- src/app.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/app.js b/src/app.js index d430db4..8c61722 100644 --- a/src/app.js +++ b/src/app.js @@ -1,22 +1,24 @@ const express = require("express") -const logger = require("./utils/logger") +const log = require("./utils/logger") const env = require("./env") const app = express() -logger.Init() +log.Init() env.Load() -if (logger.logger.level != env.ENV.logLevel) { - logger.Init(env.ENV.logLevel) +log.Log() + +if (log.logger.level != env.ENV.logLevel) { + log.Init(env.ENV.logLevel) } app.set("view engine", "ejs") app.set("trust proxy", true) app.use((req, res, next) => { - logger.info(`${req.method} ${req.path} ${req.query}`) + log.logger.info(`${req.method} ${req.path} ${req.query}`) }) const auth = require("./auth") @@ -27,5 +29,5 @@ app.use("/", auth) app.get("/data", wol) app.listen(env.ENV.port, () => { - logger.logger.info(`Server running on Port ${env.ENV.port}`) + log.logger.info(`Server running on Port ${env.ENV.port}`) }) From 9231526819658348ee7dc56bc18f72dc9378cb55 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 18:21:01 +0100 Subject: [PATCH 007/190] Update docker-compose.yaml --- docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index f4aaac1..7127f38 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,4 +1,4 @@ ---- +---s services: wol: container_name: wol-client From b717109197a2d856bff46c603e369a562b95a948 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 6 Dec 2025 17:21:10 +0000 Subject: [PATCH 008/190] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9cacc26..449b843 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ _Well, except for meteorite_ Get the latest `docker-compose.yaml` file: ```yaml ---- +---s services: wol: container_name: wol-client From b98481aa080dcb0cf4620514120df16098fee665 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 18:39:35 +0100 Subject: [PATCH 009/190] test --- src/app.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/app.js b/src/app.js index a7712fb..63f8a98 100644 --- a/src/app.js +++ b/src/app.js @@ -19,6 +19,7 @@ app.set("trust proxy", true) app.use((req, res, next) => { log.logger.info(`${req.method} ${req.path} ${req.query}`) + next() }) const auth = require("./auth") @@ -26,7 +27,13 @@ const wol = require("./wol") app.use("/", auth) -app.get("/data", wol) +app.get("/data", async (req, res, next) => { + try { + await startProcessing(req, res) + } catch (err) { + next(err) + } +}) app.use((err, req, res, next) => { log.logger.error(err.message) From 531268daff5923c08affab55328ca84100da8162 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 18:40:20 +0100 Subject: [PATCH 010/190] fix --- src/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app.js b/src/app.js index 63f8a98..6ac4fd2 100644 --- a/src/app.js +++ b/src/app.js @@ -29,7 +29,7 @@ app.use("/", auth) app.get("/data", async (req, res, next) => { try { - await startProcessing(req, res) + await wol(req, res) } catch (err) { next(err) } From 83624ed7e13239ead875f37a788aab4b11b7f937 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 18:53:17 +0100 Subject: [PATCH 011/190] fix missing rsrc url --- src/auth.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auth.js b/src/auth.js index 5020dd1..a15be55 100644 --- a/src/auth.js +++ b/src/auth.js @@ -14,7 +14,7 @@ const redirectURL = new URL(ENV.redirectURL) async function fetchUserInfo(accessToken) { try { - const res = await fetch(ENV.userInfoURL, { + const res = await fetch(ENV.resourceURL, { headers: { Authorization: `Bearer ${accessToken}`, Accept: "application/json", From 128ebd57676fd06d15d3af643a628f55a48c7a50 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 19:04:53 +0100 Subject: [PATCH 012/190] debugging --- src/wol.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wol.js b/src/wol.js index 6f29651..c759e86 100644 --- a/src/wol.js +++ b/src/wol.js @@ -204,6 +204,10 @@ async function startProcessing(req, res) { } if (!err && wakeDocker && woldEnabled) { + logger.debug( + `Sending WoL-D to ${ENV.woldURL}: ${JSON.stringify({ query })}` + ) + const dockerRes = await post(ENV.woldURL, { query }) if (dockerRes?.output && ENV.exposeLogs) { From 4de5d2d7fc1d3f2f39bc71fb57cdd71ada803c15 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 19:20:16 +0100 Subject: [PATCH 013/190] debugging --- src/wol.js | 105 ++++++++++++++++++++++++++++------------------------- 1 file changed, 55 insertions(+), 50 deletions(-) diff --git a/src/wol.js b/src/wol.js index c759e86..2cfe78f 100644 --- a/src/wol.js +++ b/src/wol.js @@ -154,73 +154,78 @@ async function trySendWakeupPackets(hosts, wolUrl) { } async function startProcessing(req, res) { - if (!req.isAuthenticated()) { - return res.json({ error: true, log: "Unauthorized" }) - } + try { + if (!req.isAuthenticated()) { + return res.json({ error: true, log: "Unauthorized" }) + } - const originalUrl = req.cookies.serviceUrl - if (!originalUrl) { - return res.json({ error: true, log: "Missing serviceUrl cookie" }) - } + const originalUrl = req.cookies.serviceUrl + if (!originalUrl) { + return res.json({ error: true, log: "Missing serviceUrl cookie" }) + } - const serviceURL = new URL(originalUrl) - const resolved = getDataByHostname(serviceURL.hostname) + const serviceURL = new URL(originalUrl) + const resolved = getDataByHostname(serviceURL.hostname) - if (!resolved) { - return res.json({ error: true, log: "No route for hostname" }) - } + if (!resolved) { + return res.json({ error: true, log: "No route for hostname" }) + } - const { hosts, routeAttributes } = resolved + const { hosts, routeAttributes } = resolved - const context = { - HOST: serviceURL.host, - HOSTNAME: serviceURL.hostname, - PORT: serviceURL.port || "", - PROTOCOL: serviceURL.protocol, - URL: originalUrl, - PATH: serviceURL.pathname, - } + const context = { + HOST: serviceURL.host, + HOSTNAME: serviceURL.hostname, + PORT: serviceURL.port || "", + PROTOCOL: serviceURL.protocol, + URL: originalUrl, + PATH: serviceURL.pathname, + } - const query = buildQuery(ENV.queryPattern, context) + const query = buildQuery(ENV.queryPattern, context) - let output = "" - let err = false + let output = "" + let err = false - const wakeDocker = Boolean(routeAttributes.wakeDocker) + const wakeDocker = Boolean(routeAttributes.wakeDocker) - const wolEnabled = typeof ENV.wolURL === "string" && ENV.wolURL.trim() !== "" + const wolEnabled = + typeof ENV.wolURL === "string" && ENV.wolURL.trim() !== "" - const woldEnabled = - typeof ENV.woldURL === "string" && ENV.woldURL.trim() !== "" + const woldEnabled = + typeof ENV.woldURL === "string" && ENV.woldURL.trim() !== "" - const wolResult = - wolEnabled && hosts.length > 0 - ? await trySendWakeupPackets(hosts, ENV.wolURL) - : null + const wolResult = + wolEnabled && hosts.length > 0 + ? await trySendWakeupPackets(hosts, ENV.wolURL) + : null - if (wolResult) { - err = wolResult.err - if (ENV.exposeLogs) output += wolResult.output - } + if (wolResult) { + err = wolResult.err + if (ENV.exposeLogs) output += wolResult.output + } - if (!err && wakeDocker && woldEnabled) { - logger.debug( - `Sending WoL-D to ${ENV.woldURL}: ${JSON.stringify({ query })}` - ) + if (!err && wakeDocker && woldEnabled) { + logger.debug( + `Sending WoL-D to ${ENV.woldURL}: ${JSON.stringify({ query })}` + ) - const dockerRes = await post(ENV.woldURL, { query }) + const dockerRes = await post(ENV.woldURL, { query }) - if (dockerRes?.output && ENV.exposeLogs) { - output += dockerRes.output + if (dockerRes?.output && ENV.exposeLogs) { + output += dockerRes.output + } } - } - return res.json({ - url: originalUrl, - log: output, - error: err, - host: serviceURL.hostname, - }) + return res.json({ + url: originalUrl, + log: output, + error: err, + host: serviceURL.hostname, + }) + } catch (err) { + logger.error(err) + } } module.exports = startProcessing From 52dbecf3742df7a50a53077bb6f902abf30e746e Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 19:35:24 +0100 Subject: [PATCH 014/190] test --- src/app.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/app.js b/src/app.js index 6ac4fd2..ac810da 100644 --- a/src/app.js +++ b/src/app.js @@ -27,13 +27,7 @@ const wol = require("./wol") app.use("/", auth) -app.get("/data", async (req, res, next) => { - try { - await wol(req, res) - } catch (err) { - next(err) - } -}) +app.get("/data", async (req, res) => wol(req, res)) app.use((err, req, res, next) => { log.logger.error(err.message) From 9b951c08a6cec177a15519a738169fb4cb417ce9 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 19:51:48 +0100 Subject: [PATCH 015/190] debugging --- src/app.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/app.js b/src/app.js index ac810da..bfb07aa 100644 --- a/src/app.js +++ b/src/app.js @@ -19,7 +19,6 @@ app.set("trust proxy", true) app.use((req, res, next) => { log.logger.info(`${req.method} ${req.path} ${req.query}`) - next() }) const auth = require("./auth") @@ -29,12 +28,6 @@ app.use("/", auth) app.get("/data", async (req, res) => wol(req, res)) -app.use((err, req, res, next) => { - log.logger.error(err.message) - - res.status(500).send("Internal server error") -}) - app.listen(env.ENV.port, () => { log.logger.info(`Server running on Port ${env.ENV.port}`) }) From b0d602a65d49bf223c4dae138cd33cc9245635ae Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 19:57:01 +0100 Subject: [PATCH 016/190] test --- src/app.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app.js b/src/app.js index bfb07aa..593b8d4 100644 --- a/src/app.js +++ b/src/app.js @@ -26,7 +26,9 @@ const wol = require("./wol") app.use("/", auth) -app.get("/data", async (req, res) => wol(req, res)) +app.get("/data", async (req, res) => { + wol(req, res) +}) app.listen(env.ENV.port, () => { log.logger.info(`Server running on Port ${env.ENV.port}`) From f41f34705d036b5b14dc0479e4cf484ddd66435e Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 20:02:31 +0100 Subject: [PATCH 017/190] debugging --- src/app.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/app.js b/src/app.js index 593b8d4..e9ff9ba 100644 --- a/src/app.js +++ b/src/app.js @@ -19,6 +19,7 @@ app.set("trust proxy", true) app.use((req, res, next) => { log.logger.info(`${req.method} ${req.path} ${req.query}`) + next() }) const auth = require("./auth") @@ -27,7 +28,12 @@ const wol = require("./wol") app.use("/", auth) app.get("/data", async (req, res) => { - wol(req, res) + try { + await wol(req, res) + } catch (err) { + log.logger.error("Unhandled error in /data:", err) + res.status(500).send("Internal server error") + } }) app.listen(env.ENV.port, () => { From 382b00a71d672ef3381a70776132f66479e1ec9c Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 20:10:36 +0100 Subject: [PATCH 018/190] debugging --- src/app.js | 7 +------ src/wol.js | 4 ++++ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/app.js b/src/app.js index e9ff9ba..5f56d8a 100644 --- a/src/app.js +++ b/src/app.js @@ -28,12 +28,7 @@ const wol = require("./wol") app.use("/", auth) app.get("/data", async (req, res) => { - try { - await wol(req, res) - } catch (err) { - log.logger.error("Unhandled error in /data:", err) - res.status(500).send("Internal server error") - } + await wol(req, res) }) app.listen(env.ENV.port, () => { diff --git a/src/wol.js b/src/wol.js index 2cfe78f..b3e4951 100644 --- a/src/wol.js +++ b/src/wol.js @@ -212,11 +212,15 @@ async function startProcessing(req, res) { const dockerRes = await post(ENV.woldURL, { query }) + logger.error("After wold") + if (dockerRes?.output && ENV.exposeLogs) { output += dockerRes.output } } + logger.debug("Before res.json()") + return res.json({ url: originalUrl, log: output, From c233dfd79f920dc029e39ed8381c0f849d0ccf56 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 20:25:26 +0100 Subject: [PATCH 019/190] test --- src/wol.js | 109 ++++++++++++++++++++++++----------------------------- 1 file changed, 50 insertions(+), 59 deletions(-) diff --git a/src/wol.js b/src/wol.js index b3e4951..c759e86 100644 --- a/src/wol.js +++ b/src/wol.js @@ -154,82 +154,73 @@ async function trySendWakeupPackets(hosts, wolUrl) { } async function startProcessing(req, res) { - try { - if (!req.isAuthenticated()) { - return res.json({ error: true, log: "Unauthorized" }) - } + if (!req.isAuthenticated()) { + return res.json({ error: true, log: "Unauthorized" }) + } - const originalUrl = req.cookies.serviceUrl - if (!originalUrl) { - return res.json({ error: true, log: "Missing serviceUrl cookie" }) - } + const originalUrl = req.cookies.serviceUrl + if (!originalUrl) { + return res.json({ error: true, log: "Missing serviceUrl cookie" }) + } - const serviceURL = new URL(originalUrl) - const resolved = getDataByHostname(serviceURL.hostname) + const serviceURL = new URL(originalUrl) + const resolved = getDataByHostname(serviceURL.hostname) - if (!resolved) { - return res.json({ error: true, log: "No route for hostname" }) - } - - const { hosts, routeAttributes } = resolved + if (!resolved) { + return res.json({ error: true, log: "No route for hostname" }) + } - const context = { - HOST: serviceURL.host, - HOSTNAME: serviceURL.hostname, - PORT: serviceURL.port || "", - PROTOCOL: serviceURL.protocol, - URL: originalUrl, - PATH: serviceURL.pathname, - } + const { hosts, routeAttributes } = resolved - const query = buildQuery(ENV.queryPattern, context) + const context = { + HOST: serviceURL.host, + HOSTNAME: serviceURL.hostname, + PORT: serviceURL.port || "", + PROTOCOL: serviceURL.protocol, + URL: originalUrl, + PATH: serviceURL.pathname, + } - let output = "" - let err = false + const query = buildQuery(ENV.queryPattern, context) - const wakeDocker = Boolean(routeAttributes.wakeDocker) + let output = "" + let err = false - const wolEnabled = - typeof ENV.wolURL === "string" && ENV.wolURL.trim() !== "" + const wakeDocker = Boolean(routeAttributes.wakeDocker) - const woldEnabled = - typeof ENV.woldURL === "string" && ENV.woldURL.trim() !== "" + const wolEnabled = typeof ENV.wolURL === "string" && ENV.wolURL.trim() !== "" - const wolResult = - wolEnabled && hosts.length > 0 - ? await trySendWakeupPackets(hosts, ENV.wolURL) - : null + const woldEnabled = + typeof ENV.woldURL === "string" && ENV.woldURL.trim() !== "" - if (wolResult) { - err = wolResult.err - if (ENV.exposeLogs) output += wolResult.output - } + const wolResult = + wolEnabled && hosts.length > 0 + ? await trySendWakeupPackets(hosts, ENV.wolURL) + : null - if (!err && wakeDocker && woldEnabled) { - logger.debug( - `Sending WoL-D to ${ENV.woldURL}: ${JSON.stringify({ query })}` - ) + if (wolResult) { + err = wolResult.err + if (ENV.exposeLogs) output += wolResult.output + } - const dockerRes = await post(ENV.woldURL, { query }) + if (!err && wakeDocker && woldEnabled) { + logger.debug( + `Sending WoL-D to ${ENV.woldURL}: ${JSON.stringify({ query })}` + ) - logger.error("After wold") + const dockerRes = await post(ENV.woldURL, { query }) - if (dockerRes?.output && ENV.exposeLogs) { - output += dockerRes.output - } + if (dockerRes?.output && ENV.exposeLogs) { + output += dockerRes.output } - - logger.debug("Before res.json()") - - return res.json({ - url: originalUrl, - log: output, - error: err, - host: serviceURL.hostname, - }) - } catch (err) { - logger.error(err) } + + return res.json({ + url: originalUrl, + log: output, + error: err, + host: serviceURL.hostname, + }) } module.exports = startProcessing From 1decbab820f3772e3142a3315536ad16be9b8231 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 20:38:44 +0100 Subject: [PATCH 020/190] test --- src/app.js | 7 ++++++- src/wol.js | 8 +++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/app.js b/src/app.js index 5f56d8a..1318716 100644 --- a/src/app.js +++ b/src/app.js @@ -28,7 +28,12 @@ const wol = require("./wol") app.use("/", auth) app.get("/data", async (req, res) => { - await wol(req, res) + try { + await wol(req, res) + } catch (err) { + log.logger.error(`Unhandled error in /data: ${err.stack}`) + res.status(500).json({ error: true, log: "Internal server error" }) + } }) app.listen(env.ENV.port, () => { diff --git a/src/wol.js b/src/wol.js index c759e86..bec3ec0 100644 --- a/src/wol.js +++ b/src/wol.js @@ -163,7 +163,13 @@ async function startProcessing(req, res) { return res.json({ error: true, log: "Missing serviceUrl cookie" }) } - const serviceURL = new URL(originalUrl) + let serviceURL + try { + serviceURL = new URL(originalUrl) + } catch (err) { + return res.status(400).json({ error: true, log: "Invalid serviceUrl" }) + } + const resolved = getDataByHostname(serviceURL.hostname) if (!resolved) { From 209e941ae41c172c471cd4f123e9bba9ca14550b Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 20:46:11 +0100 Subject: [PATCH 021/190] test --- src/wol.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/wol.js b/src/wol.js index bec3ec0..af7f126 100644 --- a/src/wol.js +++ b/src/wol.js @@ -222,10 +222,7 @@ async function startProcessing(req, res) { } return res.json({ - url: originalUrl, - log: output, - error: err, - host: serviceURL.hostname, + test: "HELLO", }) } From cd01bb9dd424f93ace1b246da7cf78052b2cbb4d Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 20:53:38 +0100 Subject: [PATCH 022/190] test --- src/wol.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wol.js b/src/wol.js index af7f126..98f7150 100644 --- a/src/wol.js +++ b/src/wol.js @@ -192,6 +192,10 @@ async function startProcessing(req, res) { let output = "" let err = false + return res.json({ + test: "HELLO", + }) + const wakeDocker = Boolean(routeAttributes.wakeDocker) const wolEnabled = typeof ENV.wolURL === "string" && ENV.wolURL.trim() !== "" From 92c1bcdf8fdcc49c4a72f6133af577b5a4a29eff Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 20:57:50 +0100 Subject: [PATCH 023/190] test --- src/wol.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wol.js b/src/wol.js index 98f7150..02d3528 100644 --- a/src/wol.js +++ b/src/wol.js @@ -192,10 +192,6 @@ async function startProcessing(req, res) { let output = "" let err = false - return res.json({ - test: "HELLO", - }) - const wakeDocker = Boolean(routeAttributes.wakeDocker) const wolEnabled = typeof ENV.wolURL === "string" && ENV.wolURL.trim() !== "" @@ -213,6 +209,10 @@ async function startProcessing(req, res) { if (ENV.exposeLogs) output += wolResult.output } + return res.json({ + test: "HELLO", + }) + if (!err && wakeDocker && woldEnabled) { logger.debug( `Sending WoL-D to ${ENV.woldURL}: ${JSON.stringify({ query })}` From 415f69cfe17d5709536b0d8891cdf2e3fcef28a9 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 21:04:28 +0100 Subject: [PATCH 024/190] test --- src/wol.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/wol.js b/src/wol.js index 02d3528..e0343e0 100644 --- a/src/wol.js +++ b/src/wol.js @@ -204,15 +204,17 @@ async function startProcessing(req, res) { ? await trySendWakeupPackets(hosts, ENV.wolURL) : null - if (wolResult) { - err = wolResult.err - if (ENV.exposeLogs) output += wolResult.output - } + logger.debug(wolResult) return res.json({ test: "HELLO", }) + if (wolResult) { + err = wolResult.err + if (ENV.exposeLogs) output += wolResult.output + } + if (!err && wakeDocker && woldEnabled) { logger.debug( `Sending WoL-D to ${ENV.woldURL}: ${JSON.stringify({ query })}` From e8b810c38366c6eb12328cf2a816c93312998543 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 21:08:51 +0100 Subject: [PATCH 025/190] test --- src/wol.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wol.js b/src/wol.js index e0343e0..d1e3359 100644 --- a/src/wol.js +++ b/src/wol.js @@ -204,7 +204,7 @@ async function startProcessing(req, res) { ? await trySendWakeupPackets(hosts, ENV.wolURL) : null - logger.debug(wolResult) + logger.debug(JSON.stringify(wolResult)) return res.json({ test: "HELLO", From a2ed1fc7fb4bc512de7b3abdbcb3b3d758b330fe Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 21:11:11 +0100 Subject: [PATCH 026/190] test --- src/wol.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/wol.js b/src/wol.js index d1e3359..97700d1 100644 --- a/src/wol.js +++ b/src/wol.js @@ -199,10 +199,11 @@ async function startProcessing(req, res) { const woldEnabled = typeof ENV.woldURL === "string" && ENV.woldURL.trim() !== "" - const wolResult = - wolEnabled && hosts.length > 0 - ? await trySendWakeupPackets(hosts, ENV.wolURL) - : null + let wolResult = null + + if (wolEnabled && hosts.length > 0) { + wolResult = await trySendWakeupPackets(hosts, ENV.wolURL) + } logger.debug(JSON.stringify(wolResult)) From 38760b3c27386ff19faa849f82dbc4e4528add49 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 21:20:17 +0100 Subject: [PATCH 027/190] test --- src/wol.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/wol.js b/src/wol.js index 97700d1..b414076 100644 --- a/src/wol.js +++ b/src/wol.js @@ -201,16 +201,14 @@ async function startProcessing(req, res) { let wolResult = null - if (wolEnabled && hosts.length > 0) { - wolResult = await trySendWakeupPackets(hosts, ENV.wolURL) - } - - logger.debug(JSON.stringify(wolResult)) - return res.json({ test: "HELLO", }) + if (wolEnabled && hosts.length > 0) { + wolResult = await trySendWakeupPackets(hosts, ENV.wolURL) + } + if (wolResult) { err = wolResult.err if (ENV.exposeLogs) output += wolResult.output From 6b4d0ec28077df686b1818c6db18a22d28bce5c2 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 21:24:14 +0100 Subject: [PATCH 028/190] test --- src/wol.js | 160 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 95 insertions(+), 65 deletions(-) diff --git a/src/wol.js b/src/wol.js index b414076..93fc7be 100644 --- a/src/wol.js +++ b/src/wol.js @@ -154,81 +154,111 @@ async function trySendWakeupPackets(hosts, wolUrl) { } async function startProcessing(req, res) { - if (!req.isAuthenticated()) { - return res.json({ error: true, log: "Unauthorized" }) - } - - const originalUrl = req.cookies.serviceUrl - if (!originalUrl) { - return res.json({ error: true, log: "Missing serviceUrl cookie" }) - } - - let serviceURL try { - serviceURL = new URL(originalUrl) - } catch (err) { - return res.status(400).json({ error: true, log: "Invalid serviceUrl" }) - } - - const resolved = getDataByHostname(serviceURL.hostname) - - if (!resolved) { - return res.json({ error: true, log: "No route for hostname" }) - } - - const { hosts, routeAttributes } = resolved - - const context = { - HOST: serviceURL.host, - HOSTNAME: serviceURL.hostname, - PORT: serviceURL.port || "", - PROTOCOL: serviceURL.protocol, - URL: originalUrl, - PATH: serviceURL.pathname, - } - - const query = buildQuery(ENV.queryPattern, context) - - let output = "" - let err = false - - const wakeDocker = Boolean(routeAttributes.wakeDocker) - - const wolEnabled = typeof ENV.wolURL === "string" && ENV.wolURL.trim() !== "" - - const woldEnabled = - typeof ENV.woldURL === "string" && ENV.woldURL.trim() !== "" + // -------------------- + // Authentication check + // -------------------- + if (!req.isAuthenticated()) { + return res.json({ error: true, log: "Unauthorized" }) + } - let wolResult = null + // -------------------- + // Read and validate cookie + // -------------------- + const originalUrl = req.cookies.serviceUrl + if (!originalUrl) { + return res.json({ error: true, log: "Missing serviceUrl cookie" }) + } - return res.json({ - test: "HELLO", - }) + let serviceURL + try { + serviceURL = new URL(originalUrl) + } catch (err) { + return res.status(400).json({ error: true, log: "Invalid serviceUrl" }) + } - if (wolEnabled && hosts.length > 0) { - wolResult = await trySendWakeupPackets(hosts, ENV.wolURL) - } + // -------------------- + // Resolve route and hosts + // -------------------- + const resolved = getDataByHostname(serviceURL.hostname) + if (!resolved) { + return res.json({ error: true, log: "No route for hostname" }) + } - if (wolResult) { - err = wolResult.err - if (ENV.exposeLogs) output += wolResult.output - } + const { hosts, routeAttributes } = resolved - if (!err && wakeDocker && woldEnabled) { - logger.debug( - `Sending WoL-D to ${ENV.woldURL}: ${JSON.stringify({ query })}` - ) + const context = { + HOST: serviceURL.host, + HOSTNAME: serviceURL.hostname, + PORT: serviceURL.port || "", + PROTOCOL: serviceURL.protocol, + URL: originalUrl, + PATH: serviceURL.pathname, + } - const dockerRes = await post(ENV.woldURL, { query }) + const query = buildQuery(ENV.queryPattern, context) + + let output = "" + let err = false + + const wakeDocker = Boolean(routeAttributes.wakeDocker) + const wolEnabled = + typeof ENV.wolURL === "string" && ENV.wolURL.trim() !== "" + const woldEnabled = + typeof ENV.woldURL === "string" && ENV.woldURL.trim() !== "" + + // -------------------- + // Safe WoL call + // -------------------- + let wolResult = null + try { + if (wolEnabled && hosts.length > 0) { + wolResult = await trySendWakeupPackets(hosts, ENV.wolURL) + if (wolResult) { + err = wolResult.err + if (ENV.exposeLogs) output += wolResult.output + } + } + } catch (wolErr) { + logger.error("Error in WoL processing:", wolErr) + err = true + } - if (dockerRes?.output && ENV.exposeLogs) { - output += dockerRes.output + // -------------------- + // Safe Docker wakeup + // -------------------- + try { + if (!err && wakeDocker && woldEnabled) { + logger.debug( + `Sending WoL-D to ${ENV.woldURL}: ${JSON.stringify({ query })}` + ) + const dockerRes = await post(ENV.woldURL, { query }) + if (dockerRes?.output && ENV.exposeLogs) output += dockerRes.output + } + } catch (dockerErr) { + logger.error("Error in Docker WoL processing:", dockerErr) + err = true } - } - return res.json({ - test: "HELLO", - }) + // -------------------- + // Respond to client safely + // -------------------- + return res.json({ + url: originalUrl, + log: output, + error: err, + host: serviceURL.hostname, + }) + } catch (fatalErr) { + // -------------------- + // Catch any unexpected error to prevent CF 520 + // -------------------- + logger.error("Fatal error in /data endpoint:", fatalErr) + return res.status(500).json({ + error: true, + log: "Internal server error", + }) + } } module.exports = startProcessing From 31b057f2fb30bb6c6009bc162e5884fca45a6bb4 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 21:51:17 +0100 Subject: [PATCH 029/190] add ws --- package-lock.json | 24 +++++- package.json | 3 +- src/app.js | 9 +-- src/wol.js | 200 ++++++++++++++++++++++++---------------------- views/home.ejs | 56 ++++++++++--- 5 files changed, 174 insertions(+), 118 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0fa3253..cbd9bdb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,8 @@ "express": "^4.21.1", "express-session": "^1.18.1", "passport": "^0.7.0", - "passport-oauth2": "^1.8.0" + "passport-oauth2": "^1.8.0", + "ws": "^8.18.3" } }, "node_modules/accepts": { @@ -1137,6 +1138,27 @@ "engines": { "node": ">= 0.8" } + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } } } } diff --git a/package.json b/package.json index dc9eff2..0253f48 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "express": "^4.21.1", "express-session": "^1.18.1", "passport": "^0.7.0", - "passport-oauth2": "^1.8.0" + "passport-oauth2": "^1.8.0", + "ws": "^8.18.3" } } diff --git a/src/app.js b/src/app.js index 1318716..91cd222 100644 --- a/src/app.js +++ b/src/app.js @@ -27,14 +27,7 @@ const wol = require("./wol") app.use("/", auth) -app.get("/data", async (req, res) => { - try { - await wol(req, res) - } catch (err) { - log.logger.error(`Unhandled error in /data: ${err.stack}`) - res.status(500).json({ error: true, log: "Internal server error" }) - } -}) +app.use("/", wol) app.listen(env.ENV.port, () => { log.logger.info(`Server running on Port ${env.ENV.port}`) diff --git a/src/wol.js b/src/wol.js index 93fc7be..79caa8b 100644 --- a/src/wol.js +++ b/src/wol.js @@ -1,7 +1,18 @@ +const ws = require("ws") +const http = require("http") +const { v4: uuidv4 } = require("uuid") +const express = require("express") + const { logger } = require("./utils/logger") const { ENV } = require("./env") const fs = require("fs") +const router = express.Router() +const server = http.createServer(router) +const wss = new ws.Server({ server }) + +const clients = {} + const CONFIG = JSON.parse(fs.readFileSync(ENV.configPath, "utf8")) function buildQuery(pattern, context) { @@ -154,111 +165,110 @@ async function trySendWakeupPackets(hosts, wolUrl) { } async function startProcessing(req, res) { + if (!req.isAuthenticated()) { + return res.json({ error: true, message: "Unauthorized" }) + } + + const originalUrl = req.cookies.serviceUrl + if (!originalUrl) { + return res.json({ error: true, message: "Missing serviceUrl cookie" }) + } + + let serviceURL try { - // -------------------- - // Authentication check - // -------------------- - if (!req.isAuthenticated()) { - return res.json({ error: true, log: "Unauthorized" }) - } + serviceURL = new URL(originalUrl) + } catch (err) { + return res.status(400).json({ error: true, message: "Invalid serviceUrl" }) + } - // -------------------- - // Read and validate cookie - // -------------------- - const originalUrl = req.cookies.serviceUrl - if (!originalUrl) { - return res.json({ error: true, log: "Missing serviceUrl cookie" }) - } + const resolved = getDataByHostname(serviceURL.hostname) - let serviceURL - try { - serviceURL = new URL(originalUrl) - } catch (err) { - return res.status(400).json({ error: true, log: "Invalid serviceUrl" }) - } + if (!resolved) { + return res.json({ error: true, message: "No route for hostname" }) + } - // -------------------- - // Resolve route and hosts - // -------------------- - const resolved = getDataByHostname(serviceURL.hostname) - if (!resolved) { - return res.json({ error: true, log: "No route for hostname" }) - } + const requestId = uuidv4() - const { hosts, routeAttributes } = resolved + res.json({ error: false, message: "Start request received", requestId }) - const context = { - HOST: serviceURL.host, - HOSTNAME: serviceURL.hostname, - PORT: serviceURL.port || "", - PROTOCOL: serviceURL.protocol, - URL: originalUrl, - PATH: serviceURL.pathname, - } + const { hosts, routeAttributes } = resolved - const query = buildQuery(ENV.queryPattern, context) - - let output = "" - let err = false - - const wakeDocker = Boolean(routeAttributes.wakeDocker) - const wolEnabled = - typeof ENV.wolURL === "string" && ENV.wolURL.trim() !== "" - const woldEnabled = - typeof ENV.woldURL === "string" && ENV.woldURL.trim() !== "" - - // -------------------- - // Safe WoL call - // -------------------- - let wolResult = null - try { - if (wolEnabled && hosts.length > 0) { - wolResult = await trySendWakeupPackets(hosts, ENV.wolURL) - if (wolResult) { - err = wolResult.err - if (ENV.exposeLogs) output += wolResult.output - } - } - } catch (wolErr) { - logger.error("Error in WoL processing:", wolErr) - err = true - } + const context = { + HOST: serviceURL.host, + HOSTNAME: serviceURL.hostname, + PORT: serviceURL.port || "", + PROTOCOL: serviceURL.protocol, + URL: originalUrl, + PATH: serviceURL.pathname, + } - // -------------------- - // Safe Docker wakeup - // -------------------- - try { - if (!err && wakeDocker && woldEnabled) { - logger.debug( - `Sending WoL-D to ${ENV.woldURL}: ${JSON.stringify({ query })}` - ) - const dockerRes = await post(ENV.woldURL, { query }) - if (dockerRes?.output && ENV.exposeLogs) output += dockerRes.output - } - } catch (dockerErr) { - logger.error("Error in Docker WoL processing:", dockerErr) - err = true + const query = buildQuery(ENV.queryPattern, context) + + let output = "" + let err = false + + const wakeDocker = Boolean(routeAttributes.wakeDocker) + + const wolEnabled = typeof ENV.wolURL === "string" && ENV.wolURL.trim() !== "" + + const woldEnabled = + typeof ENV.woldURL === "string" && ENV.woldURL.trim() !== "" + + let wolResult = null + + if (wolEnabled && hosts.length > 0) { + wolResult = await trySendWakeupPackets(hosts, ENV.wolURL) + } + + if (wolResult) { + err = wolResult.err + if (ENV.exposeLogs) output += wolResult.output + } + + if (!err && wakeDocker && woldEnabled) { + logger.debug( + `Sending WoL-D to ${ENV.woldURL}: ${JSON.stringify({ query })}` + ) + + const dockerRes = await post(ENV.woldURL, { query }) + + if (dockerRes?.output && ENV.exposeLogs) { + output += dockerRes.output } + } - // -------------------- - // Respond to client safely - // -------------------- - return res.json({ - url: originalUrl, - log: output, - error: err, - host: serviceURL.hostname, - }) - } catch (fatalErr) { - // -------------------- - // Catch any unexpected error to prevent CF 520 - // -------------------- - logger.error("Fatal error in /data endpoint:", fatalErr) - return res.status(500).json({ - error: true, - log: "Internal server error", - }) + const ws = clients[requestId] + + if (ws && ws.readyState === WebSocket.OPEN) { + ws.send( + JSON.stringify({ + url: originalUrl, + message: output, + error: err, + host: serviceURL.hostname, + requestId, + }) + ) } } -module.exports = startProcessing +wss.on("connection", (ws, req) => { + const url = new URL(req.url) + const requestId = url.searchParams.get("requestId") + + if (!requestId) { + ws.send(JSON.stringify({ error: "Missing requestId" })) + ws.close() + return + } + + clients[requestId] = ws + + ws.on("close", () => { + delete clients[requestId] + }) +}) + +router.get("/start", async (res, req) => await startProcessing(req, res)) + +module.exports = router diff --git a/views/home.ejs b/views/home.ejs index b745fce..2d1ef45 100644 --- a/views/home.ejs +++ b/views/home.ejs @@ -254,7 +254,7 @@ function handleError({ host = "Server", - message = "Unable to reach the server", + message = "Something went wrong", } = {}) { const titleText = document.getElementById("title") const subTitleText = document.getElementById("subtitle") @@ -263,7 +263,7 @@ changeAnimation("spin", "cross-line") changeAnimation("hide", "add-line") - titleText.textContent = "Something went wrong" + titleText.textContent = message subTitleText.textContent = `${host} seems to be unreachable` }, 1000) } @@ -273,26 +273,56 @@ const subTitleText = document.getElementById("subtitle") logEl.textContent = "" - - const baseText = "You will be Redirected shortly" + subTitleText.textContent = "Initializing startup..." try { - console.log("Initializing Startup") - const response = await fetch("/data") + const response = await fetch("/start") if (!response.ok) throw new Error(`HTTP error ${response.status}`) const data = await response.json() - logEl.textContent = data.log || "" + const requestId = data.requestId + if (!requestId) throw new Error("No requestId returned from server") + + logEl.textContent += "Process started. Waiting for device...\n" + + const ws = new WebSocket( + `ws://${window.location.host}?requestId=${requestId}` + ) + + ws.onopen = () => { + logEl.textContent += "WebSocket connected.\n" + } + + ws.onmessage = (event) => { + const msg = JSON.parse(event.data) - if (data.error) { - handleError({ host: data.host }) - } else if (data.url) { - window.location.href = data.url - } else { + if (msg.message) { + logEl.textContent += msg.message + "\n" + } + + if (!msg.error && msg.url) { + logEl.textContent += "Device is online! Redirecting...\n" + ws.close() + window.location.href = msg.url + } + + if (msg.error) { + logEl.textContent += "Error occurred while starting device.\n" + ws.close() + handleError() + } + } + + ws.onerror = (err) => { + logEl.textContent += "WebSocket connection failed.\n" handleError() } + + ws.onclose = () => { + logEl.textContent += "WebSocket closed.\n" + } } catch (err) { - console.error("Error fetching data:", err) + logEl.textContent += "Failed to start process: " + err.message + "\n" handleError() } } From 1baca4a25af62aeb69d2078319fd8a83d351b18e Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 21:53:30 +0100 Subject: [PATCH 030/190] add uuid pkg --- package-lock.json | 14 ++++++++++++++ package.json | 1 + 2 files changed, 15 insertions(+) diff --git a/package-lock.json b/package-lock.json index cbd9bdb..6df4c9e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "express-session": "^1.18.1", "passport": "^0.7.0", "passport-oauth2": "^1.8.0", + "uuid": "^13.0.0", "ws": "^8.18.3" } }, @@ -1130,6 +1131,19 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz", + "integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index 0253f48..44ec3b3 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "express-session": "^1.18.1", "passport": "^0.7.0", "passport-oauth2": "^1.8.0", + "uuid": "^13.0.0", "ws": "^8.18.3" } } From 21bede8c083bb44777a1ab1adf659b4e2de71ccf Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 21:57:50 +0100 Subject: [PATCH 031/190] debug --- views/home.ejs | 1 + 1 file changed, 1 insertion(+) diff --git a/views/home.ejs b/views/home.ejs index 2d1ef45..6712f21 100644 --- a/views/home.ejs +++ b/views/home.ejs @@ -322,6 +322,7 @@ logEl.textContent += "WebSocket closed.\n" } } catch (err) { + console.log(err) logEl.textContent += "Failed to start process: " + err.message + "\n" handleError() } From 5f68bdbd3c9a80ba3216c1a00e5f7d63ce6c8053 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 22:09:49 +0100 Subject: [PATCH 032/190] fix --- src/app.js | 9 +++++++-- src/wol.js | 31 ++++--------------------------- src/wss.js | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 29 deletions(-) create mode 100644 src/wss.js diff --git a/src/app.js b/src/app.js index 91cd222..d571b52 100644 --- a/src/app.js +++ b/src/app.js @@ -1,6 +1,7 @@ const express = require("express") const log = require("./utils/logger") const env = require("./env") +const http = require("http") const app = express() @@ -25,10 +26,14 @@ app.use((req, res, next) => { const auth = require("./auth") const wol = require("./wol") +const wss = require("./wss") + app.use("/", auth) -app.use("/", wol) +const server = http.createServer(app) + +wss.attach(server, app, wol) -app.listen(env.ENV.port, () => { +server.listen(env.ENV.port, () => { log.logger.info(`Server running on Port ${env.ENV.port}`) }) diff --git a/src/wol.js b/src/wol.js index 79caa8b..27fdcd0 100644 --- a/src/wol.js +++ b/src/wol.js @@ -1,17 +1,11 @@ -const ws = require("ws") -const http = require("http") -const { v4: uuidv4 } = require("uuid") const express = require("express") +const wss = require("./wss") const { logger } = require("./utils/logger") const { ENV } = require("./env") const fs = require("fs") const router = express.Router() -const server = http.createServer(router) -const wss = new ws.Server({ server }) - -const clients = {} const CONFIG = JSON.parse(fs.readFileSync(ENV.configPath, "utf8")) @@ -187,7 +181,7 @@ async function startProcessing(req, res) { return res.json({ error: true, message: "No route for hostname" }) } - const requestId = uuidv4() + const requestId = wss.createRequestId() res.json({ error: false, message: "Start request received", requestId }) @@ -237,7 +231,7 @@ async function startProcessing(req, res) { } } - const ws = clients[requestId] + const ws = wss.getClient(requestId) if (ws && ws.readyState === WebSocket.OPEN) { ws.send( @@ -252,23 +246,6 @@ async function startProcessing(req, res) { } } -wss.on("connection", (ws, req) => { - const url = new URL(req.url) - const requestId = url.searchParams.get("requestId") - - if (!requestId) { - ws.send(JSON.stringify({ error: "Missing requestId" })) - ws.close() - return - } - - clients[requestId] = ws - - ws.on("close", () => { - delete clients[requestId] - }) -}) - -router.get("/start", async (res, req) => await startProcessing(req, res)) +router.get("/start", async (req, res) => await startProcessing(req, res)) module.exports = router diff --git a/src/wss.js b/src/wss.js new file mode 100644 index 0000000..4d7af26 --- /dev/null +++ b/src/wss.js @@ -0,0 +1,39 @@ +const WebSocket = require("ws") +const { v4: uuidv4 } = require("uuid") + +const clients = {} + +let wss = null + +function attach(server, app, router) { + wss = new WebSocket.Server({ server }) + + wss.on("connection", (socket, req) => { + const url = new URL(req.url) + const requestId = url.searchParams.get("requestId") + + if (!requestId) { + socket.send(JSON.stringify({ error: true, message: "Missing requestId" })) + socket.close() + return + } + + clients[requestId] = socket + + socket.on("close", () => { + delete clients[requestId] + }) + }) + + app.use("/", router) +} + +function getClient(requestId) { + return clients[requestId] +} + +function createRequestId() { + return uuidv4() +} + +module.exports = { attach, getClient, createRequestId } From b05f6d90c3a757c1759c837caa8b37de532ba8bc Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 22:12:51 +0100 Subject: [PATCH 033/190] fix ws/s --- views/home.ejs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/views/home.ejs b/views/home.ejs index 6712f21..0d32425 100644 --- a/views/home.ejs +++ b/views/home.ejs @@ -285,8 +285,9 @@ logEl.textContent += "Process started. Waiting for device...\n" + const protocol = location.protocol === "https:" ? "wss" : "ws" const ws = new WebSocket( - `ws://${window.location.host}?requestId=${requestId}` + `${protocol}://${location.host}/ws?requestId=${id}` ) ws.onopen = () => { From 81a76bf758701c955c1c43e43753a56818acb497 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 22:15:45 +0100 Subject: [PATCH 034/190] fix typo --- views/home.ejs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/home.ejs b/views/home.ejs index 0d32425..5111b57 100644 --- a/views/home.ejs +++ b/views/home.ejs @@ -287,7 +287,7 @@ const protocol = location.protocol === "https:" ? "wss" : "ws" const ws = new WebSocket( - `${protocol}://${location.host}/ws?requestId=${id}` + `${protocol}://${location.host}/ws?requestId=${requestId}` ) ws.onopen = () => { From 641e83e04b34c8a21bf25ff280b9b12a00a2244f Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 22:21:38 +0100 Subject: [PATCH 035/190] add dummy base --- src/wss.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wss.js b/src/wss.js index 4d7af26..591a5c9 100644 --- a/src/wss.js +++ b/src/wss.js @@ -9,7 +9,7 @@ function attach(server, app, router) { wss = new WebSocket.Server({ server }) wss.on("connection", (socket, req) => { - const url = new URL(req.url) + const url = new URL(req.url, "http://localhost") const requestId = url.searchParams.get("requestId") if (!requestId) { From 3a93e9a33959c77a33296e75f2c05278e999588b Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 22:31:11 +0100 Subject: [PATCH 036/190] add pong to keep ws socket alive --- src/wol.js | 28 +++++++++++++++++++++------- src/wss.js | 19 +++++++++++++++++++ 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/wol.js b/src/wol.js index 27fdcd0..e290f1a 100644 --- a/src/wol.js +++ b/src/wol.js @@ -198,7 +198,6 @@ async function startProcessing(req, res) { const query = buildQuery(ENV.queryPattern, context) - let output = "" let err = false const wakeDocker = Boolean(routeAttributes.wakeDocker) @@ -216,7 +215,17 @@ async function startProcessing(req, res) { if (wolResult) { err = wolResult.err - if (ENV.exposeLogs) output += wolResult.output + } + + const ws = wss.getClient(requestId) + + if (ws && ws.readyState === WebSocket.OPEN) { + ws.send( + JSON.stringify({ + error: err, + message: wolResult.output, + }) + ) } if (!err && wakeDocker && woldEnabled) { @@ -226,18 +235,23 @@ async function startProcessing(req, res) { const dockerRes = await post(ENV.woldURL, { query }) - if (dockerRes?.output && ENV.exposeLogs) { - output += dockerRes.output + if (dockerRes?.output) { + if (ws && ws.readyState === WebSocket.OPEN) { + ws.send( + JSON.stringify({ + error: err, + message: dockerRes.output, + }) + ) + } } } - const ws = wss.getClient(requestId) - if (ws && ws.readyState === WebSocket.OPEN) { ws.send( JSON.stringify({ url: originalUrl, - message: output, + message: "", error: err, host: serviceURL.hostname, requestId, diff --git a/src/wss.js b/src/wss.js index 591a5c9..ea77259 100644 --- a/src/wss.js +++ b/src/wss.js @@ -23,6 +23,25 @@ function attach(server, app, router) { socket.on("close", () => { delete clients[requestId] }) + + socket.isAlive = true + + socket.on("pong", () => { + socket.isAlive = true + }) + + const interval = setInterval(() => { + if (socket.isAlive === false) { + socket.terminate() + return + } + socket.isAlive = false + socket.ping() + }, 15000) + + socket.on("close", () => { + clearInterval(interval) + }) }) app.use("/", router) From 540ed965ff8ecb2c3096cf1407f549071d01d7a2 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 22:44:00 +0100 Subject: [PATCH 037/190] small updates --- src/wol.js | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++--- src/wss.js | 5 +---- 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/src/wol.js b/src/wol.js index e290f1a..572a449 100644 --- a/src/wol.js +++ b/src/wol.js @@ -158,6 +158,29 @@ async function trySendWakeupPackets(hosts, wolUrl) { return { output, err } } +async function waitForHostUp( + url, + { interval = 3000, timeout = 60000, okOnly = true } = {} +) { + const start = Date.now() + + while (Date.now() - start < timeout) { + try { + const res = await fetch(url, { method: "GET" }) + + if (okOnly) { + if (res.ok) return true + } else { + return true + } + } catch (_) {} + + await new Promise((r) => setTimeout(r, interval)) + } + + return false +} + async function startProcessing(req, res) { if (!req.isAuthenticated()) { return res.json({ error: true, message: "Unauthorized" }) @@ -219,7 +242,11 @@ async function startProcessing(req, res) { const ws = wss.getClient(requestId) - if (ws && ws.readyState === WebSocket.OPEN) { + if (!ws) { + return + } + + if (ws.readyState === WebSocket.OPEN) { ws.send( JSON.stringify({ error: err, @@ -228,7 +255,14 @@ async function startProcessing(req, res) { ) } - if (!err && wakeDocker && woldEnabled) { + if (err) { + if (ws.readyState === WebSocket.OPEN) { + ws.close() + } + return + } + + if (wakeDocker && woldEnabled) { logger.debug( `Sending WoL-D to ${ENV.woldURL}: ${JSON.stringify({ query })}` ) @@ -247,7 +281,29 @@ async function startProcessing(req, res) { } } - if (ws && ws.readyState === WebSocket.OPEN) { + const isReady = await waitForHostUp(serviceURL) + + if (!isReady) { + err = true + + if (ws.readyState === WebSocket.OPEN) { + ws.send( + JSON.stringify({ + error: err, + message: "Timeout waiting for Service", + }) + ) + } + } + + if (err) { + if (ws.readyState === WebSocket.OPEN) { + ws.close() + } + return + } + + if (ws.readyState === WebSocket.OPEN) { ws.send( JSON.stringify({ url: originalUrl, diff --git a/src/wss.js b/src/wss.js index ea77259..fa3f6bf 100644 --- a/src/wss.js +++ b/src/wss.js @@ -20,10 +20,6 @@ function attach(server, app, router) { clients[requestId] = socket - socket.on("close", () => { - delete clients[requestId] - }) - socket.isAlive = true socket.on("pong", () => { @@ -41,6 +37,7 @@ function attach(server, app, router) { socket.on("close", () => { clearInterval(interval) + delete clients[requestId] }) }) From 3a2e7c6d0f949bed62a5afd47d6b9363ddf50ddd Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 22:50:38 +0100 Subject: [PATCH 038/190] check if redirect to stop loops --- src/app.js | 2 ++ src/wol.js | 22 +++++++++++----------- views/home.ejs | 4 ++-- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/app.js b/src/app.js index d571b52..1896e97 100644 --- a/src/app.js +++ b/src/app.js @@ -19,6 +19,8 @@ app.set("view engine", "ejs") app.set("trust proxy", true) app.use((req, res, next) => { + res.setHeader("X-Redirect-Service", "1") + log.logger.info(`${req.method} ${req.path} ${req.query}`) next() }) diff --git a/src/wol.js b/src/wol.js index 572a449..62266ae 100644 --- a/src/wol.js +++ b/src/wol.js @@ -158,22 +158,22 @@ async function trySendWakeupPackets(hosts, wolUrl) { return { output, err } } -async function waitForHostUp( - url, - { interval = 3000, timeout = 60000, okOnly = true } = {} -) { +async function isRealDevice(res) { + return !res.headers.get("X-Redirect-Service") +} + +async function waitForHostUp(url, options = {}) { + const { interval = 3000, timeout = 60000 } = options const start = Date.now() while (Date.now() - start < timeout) { try { - const res = await fetch(url, { method: "GET" }) + const res = await fetch(url) - if (okOnly) { - if (res.ok) return true - } else { + if (res.ok && (await isRealDevice(res))) { return true } - } catch (_) {} + } catch {} await new Promise((r) => setTimeout(r, interval)) } @@ -270,7 +270,7 @@ async function startProcessing(req, res) { const dockerRes = await post(ENV.woldURL, { query }) if (dockerRes?.output) { - if (ws && ws.readyState === WebSocket.OPEN) { + if (ws.readyState === WebSocket.OPEN) { ws.send( JSON.stringify({ error: err, @@ -290,7 +290,7 @@ async function startProcessing(req, res) { ws.send( JSON.stringify({ error: err, - message: "Timeout waiting for Service", + message: "Timeout waiting for service", }) ) } diff --git a/views/home.ejs b/views/home.ejs index 5111b57..e9d4b98 100644 --- a/views/home.ejs +++ b/views/home.ejs @@ -302,13 +302,13 @@ } if (!msg.error && msg.url) { - logEl.textContent += "Device is online! Redirecting...\n" + logEl.textContent += "Service is online! Redirecting...\n" ws.close() window.location.href = msg.url } if (msg.error) { - logEl.textContent += "Error occurred while starting device.\n" + logEl.textContent += "Error occurred while starting service.\n" ws.close() handleError() } From 96e9f1ecd2c823d1b51b0f1d50cd02f5dbb970b4 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 6 Dec 2025 23:09:16 +0100 Subject: [PATCH 039/190] stop loop --- src/app.js | 4 ++++ src/wol.js | 13 +++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/app.js b/src/app.js index 1896e97..52ad05d 100644 --- a/src/app.js +++ b/src/app.js @@ -21,6 +21,10 @@ app.set("trust proxy", true) app.use((req, res, next) => { res.setHeader("X-Redirect-Service", "1") + if (req.headers["x-redirect-service"]) { + return res.status(200).end() + } + log.logger.info(`${req.method} ${req.path} ${req.query}`) next() }) diff --git a/src/wol.js b/src/wol.js index 62266ae..8d40804 100644 --- a/src/wol.js +++ b/src/wol.js @@ -158,19 +158,20 @@ async function trySendWakeupPackets(hosts, wolUrl) { return { output, err } } -async function isRealDevice(res) { - return !res.headers.get("X-Redirect-Service") -} - async function waitForHostUp(url, options = {}) { const { interval = 3000, timeout = 60000 } = options const start = Date.now() while (Date.now() - start < timeout) { try { - const res = await fetch(url) + const res = await fetch(url, { + method: "GET", + headers: { + "X-Redirect-Service": 1, + }, + }) - if (res.ok && (await isRealDevice(res))) { + if (res.ok && !res.headers.get("X-Redirect-Service")) { return true } } catch {} From 9884f2b0c17e14869e91041c7b88d105b3ff7a33 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 10:31:21 +0100 Subject: [PATCH 040/190] service instead of device --- views/home.ejs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/home.ejs b/views/home.ejs index e9d4b98..be77165 100644 --- a/views/home.ejs +++ b/views/home.ejs @@ -283,7 +283,7 @@ const requestId = data.requestId if (!requestId) throw new Error("No requestId returned from server") - logEl.textContent += "Process started. Waiting for device...\n" + logEl.textContent += "Process started. Waiting for service...\n" const protocol = location.protocol === "https:" ? "wss" : "ws" const ws = new WebSocket( From f1a729a0b3dd8ac6415372ef0a9b4c682ed24e91 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 10:37:15 +0100 Subject: [PATCH 041/190] debug waitForHostUp --- src/wol.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/wol.js b/src/wol.js index 8d40804..2e23323 100644 --- a/src/wol.js +++ b/src/wol.js @@ -171,6 +171,9 @@ async function waitForHostUp(url, options = {}) { }, }) + const data = res.json() + logger.debug(data) + if (res.ok && !res.headers.get("X-Redirect-Service")) { return true } From d6dfbf5adc5afa63bd0de2aaf60878c7168d52d6 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 10:43:44 +0100 Subject: [PATCH 042/190] fix debug --- src/app.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app.js b/src/app.js index 52ad05d..10f31ae 100644 --- a/src/app.js +++ b/src/app.js @@ -25,7 +25,9 @@ app.use((req, res, next) => { return res.status(200).end() } - log.logger.info(`${req.method} ${req.path} ${req.query}`) + url = new URL(req.url) + + log.logger.info(`${req.method} ${url.pathname} ${url.search}`) next() }) From ee8a370fd5819eeb101e5eeb5349ded71c88f956 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 10:44:33 +0100 Subject: [PATCH 043/190] debug --- src/wol.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/wol.js b/src/wol.js index 2e23323..6ca6c72 100644 --- a/src/wol.js +++ b/src/wol.js @@ -171,8 +171,9 @@ async function waitForHostUp(url, options = {}) { }, }) - const data = res.json() - logger.debug(data) + const data = res.headers + + console.log(header) if (res.ok && !res.headers.get("X-Redirect-Service")) { return true From 835744567a2fba1d58ff045ba0fbd4438344594d Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 10:46:51 +0100 Subject: [PATCH 044/190] debug post fetch error --- src/wol.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wol.js b/src/wol.js index 6ca6c72..7b529b0 100644 --- a/src/wol.js +++ b/src/wol.js @@ -30,7 +30,9 @@ async function post(url, data) { return await response.json() } catch (err) { - logger.error(`POST error: ${err.message}`) + logger.error( + `POST error: ${err.message}; cause: ${JSON.stringify(err.cause)}` + ) return null } } From f7530e41b1677d206d532749b9869cda66a8ce65 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 10:50:12 +0100 Subject: [PATCH 045/190] fix urlparse --- src/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app.js b/src/app.js index 10f31ae..9e976e6 100644 --- a/src/app.js +++ b/src/app.js @@ -25,7 +25,7 @@ app.use((req, res, next) => { return res.status(200).end() } - url = new URL(req.url) + url = URL.parse(req.url, `${req.protocol}://${req.hostname}`) log.logger.info(`${req.method} ${url.pathname} ${url.search}`) next() From 12916a3f6557152ea6f5c457b7298c759ff7664f Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 11:03:06 +0100 Subject: [PATCH 046/190] debug fix --- src/wol.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wol.js b/src/wol.js index 7b529b0..7c02ba7 100644 --- a/src/wol.js +++ b/src/wol.js @@ -175,7 +175,7 @@ async function waitForHostUp(url, options = {}) { const data = res.headers - console.log(header) + logger.debug(data) if (res.ok && !res.headers.get("X-Redirect-Service")) { return true From 81783c093ba49641723512b3c906cfc310776ec2 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 11:07:44 +0100 Subject: [PATCH 047/190] testing done. --- src/wol.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/wol.js b/src/wol.js index 7c02ba7..1e7394e 100644 --- a/src/wol.js +++ b/src/wol.js @@ -173,10 +173,6 @@ async function waitForHostUp(url, options = {}) { }, }) - const data = res.headers - - logger.debug(data) - if (res.ok && !res.headers.get("X-Redirect-Service")) { return true } From 546982fa34bef54bfe53e94e283493c26dda6fb6 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 11:12:25 +0100 Subject: [PATCH 048/190] cleanup --- src/wol.js | 74 +++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/src/wol.js b/src/wol.js index 1e7394e..7817987 100644 --- a/src/wol.js +++ b/src/wol.js @@ -137,7 +137,9 @@ async function trySendWakeupPackets(hosts, wolUrl) { } } - logger.debug(`Sending WoL to ${targetUrl}: ${JSON.stringify(payload)}`) + logger.debug( + `Sending WoL packets to ${targetUrl}: ${JSON.stringify(payload)}` + ) const response = await post(targetUrl, payload) if (!response?.message) { @@ -249,25 +251,18 @@ async function startProcessing(req, res) { return } - if (ws.readyState === WebSocket.OPEN) { - ws.send( - JSON.stringify({ - error: err, - message: wolResult.output, - }) - ) - } + sendToClient(ws, { + error: err, + message: wolResult.output, + }) - if (err) { - if (ws.readyState === WebSocket.OPEN) { - ws.close() - } - return - } + errorClient(ws, err) if (wakeDocker && woldEnabled) { logger.debug( - `Sending WoL-D to ${ENV.woldURL}: ${JSON.stringify({ query })}` + `Sending WoL-Dockerized packets to ${ENV.woldURL}: ${JSON.stringify({ + query, + })}` ) const dockerRes = await post(ENV.woldURL, { query }) @@ -289,34 +284,39 @@ async function startProcessing(req, res) { if (!isReady) { err = true - if (ws.readyState === WebSocket.OPEN) { - ws.send( - JSON.stringify({ - error: err, - message: "Timeout waiting for service", - }) - ) - } + sendToClient(ws, { + error: err, + message: "Timeout waiting for service", + }) } + errorClient(ws, err) + + sendToClient(ws, { + url: originalUrl, + message: "", + error: err, + host: serviceURL.hostname, + requestId, + }) +} + +function sendToClient(ws, data) { + if (ws.readyState === WebSocket.OPEN) { + ws.send(JSON.stringify(data)) + return true + } + return false +} + +function errorClient(ws, err) { if (err) { if (ws.readyState === WebSocket.OPEN) { ws.close() } - return - } - - if (ws.readyState === WebSocket.OPEN) { - ws.send( - JSON.stringify({ - url: originalUrl, - message: "", - error: err, - host: serviceURL.hostname, - requestId, - }) - ) + return true } + return false } router.get("/start", async (req, res) => await startProcessing(req, res)) From bf2b3773cb89ed5efe75cebd551d62c6853614a4 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 11:19:36 +0100 Subject: [PATCH 049/190] add override for query pattern --- src/env.js | 6 ++--- src/wol.js | 66 ++++++++++++++++++++++++++---------------------------- 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/src/env.js b/src/env.js index 24e1384..77c476e 100644 --- a/src/env.js +++ b/src/env.js @@ -8,7 +8,7 @@ const ENV = { logLevel: "info", exposeLogs: false, - queryPattern: "", + woldQueryPattern: "", wolURL: null, woldURL: null, virtualPort: "", @@ -39,11 +39,11 @@ function Load() { ENV.port = process.env.PORT || ENV.port ENV.logLevel = process.env.LOG_LEVEL || ENV.logLevel - ENV.queryPattern = process.env.QUERY_PATTERN + ENV.woldQueryPattern = process.env.WOLD_QUERY_PATTERN ENV.exposeLogs = process.env.EXPOSE_LOGS || ENV.exposeLogs - if (ENV.queryPattern == "") { + if (ENV.woldQueryPattern == "") { logger.fatal(`Query pattern is empty`) } diff --git a/src/wol.js b/src/wol.js index 7817987..74aa56b 100644 --- a/src/wol.js +++ b/src/wol.js @@ -215,67 +215,65 @@ async function startProcessing(req, res) { const { hosts, routeAttributes } = resolved - const context = { - HOST: serviceURL.host, - HOSTNAME: serviceURL.hostname, - PORT: serviceURL.port || "", - PROTOCOL: serviceURL.protocol, - URL: originalUrl, - PATH: serviceURL.pathname, - } - - const query = buildQuery(ENV.queryPattern, context) - let err = false - const wakeDocker = Boolean(routeAttributes.wakeDocker) - const wolEnabled = typeof ENV.wolURL === "string" && ENV.wolURL.trim() !== "" - const woldEnabled = - typeof ENV.woldURL === "string" && ENV.woldURL.trim() !== "" - let wolResult = null if (wolEnabled && hosts.length > 0) { wolResult = await trySendWakeupPackets(hosts, ENV.wolURL) } - if (wolResult) { - err = wolResult.err - } - const ws = wss.getClient(requestId) if (!ws) { return } - sendToClient(ws, { - error: err, - message: wolResult.output, - }) + if (wolResult) { + err = wolResult.err + + sendToClient(ws, { + error: err, + message: wolResult.output, + }) + } errorClient(ws, err) + const wakeDocker = Boolean(routeAttributes.wakeDocker) + + const woldEnabled = + typeof ENV.woldURL === "string" && ENV.woldURL.trim() !== "" + if (wakeDocker && woldEnabled) { + const context = { + HOST: serviceURL.host, + HOSTNAME: serviceURL.hostname, + PORT: serviceURL.port || "", + PROTOCOL: serviceURL.protocol, + URL: originalUrl, + PATH: serviceURL.pathname, + } + + const queryPattern = routeAttributes.queryPattern || ENV.woldQueryPattern + + const query = buildQuery(queryPattern, context) + logger.debug( `Sending WoL-Dockerized packets to ${ENV.woldURL}: ${JSON.stringify({ - query, + query: query, })}` ) - const dockerRes = await post(ENV.woldURL, { query }) + const dockerRes = await post(ENV.woldURL, { query: query }) if (dockerRes?.output) { - if (ws.readyState === WebSocket.OPEN) { - ws.send( - JSON.stringify({ - error: err, - message: dockerRes.output, - }) - ) - } + sendToClient(ws, { + error: err, + message: dockerRes.output, + }) } } From ab0aabe8209b63dbdf2c157baf2082b62bfbecbb Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 17:03:35 +0100 Subject: [PATCH 050/190] update due to wol-client --- src/wol.js | 126 ++++++++++++++++++++++++++++++++++++------------- src/wss.js | 18 +++---- views/home.ejs | 6 +-- 3 files changed, 105 insertions(+), 45 deletions(-) diff --git a/src/wol.js b/src/wol.js index 74aa56b..93618ee 100644 --- a/src/wol.js +++ b/src/wol.js @@ -1,5 +1,6 @@ const express = require("express") const wss = require("./wss") +const WebSocket = require("ws") const { logger } = require("./utils/logger") const { ENV } = require("./env") @@ -101,30 +102,29 @@ function getDataByHostname(hostname) { } } -async function trySendWakeupPackets(hosts, wolUrl) { - if (!hosts?.length) return null - if (typeof wolUrl !== "string" || wolUrl.trim() === "") return null +async function trySendWakeupPackets(client, hosts, wolUrl) { + if (!hosts?.length) return { err: true } + if (!client) return { err: true } + if (!wolUrl) return { err: true } - let output = "" let err = false + const baseURL = new URL(wolUrl) + const protocol = baseURL.protocol === "https:" ? "wss" : "ws" + const virtualPort = ENV.virtualPort && `${ENV.virtualPort}`.trim() !== "" ? ENV.virtualPort : null for (const host of hosts) { - const ip = host.ip - let targetUrl = wolUrl let payload if (host.isVirtual) { - if (!virtualPort) { - continue - } + if (!virtualPort) continue - targetUrl = `http://${ip}:${virtualPort}` + targetUrl = `http://${host.ip}:${virtualPort}` payload = { id: host.id, startupTime: host.startupTime, @@ -142,26 +142,90 @@ async function trySendWakeupPackets(hosts, wolUrl) { ) const response = await post(targetUrl, payload) - if (!response?.message) { + if (!response?.client_id) { err = true + + sendToClient(client, { + success: false, + error: true, + message: `WoL request failed`, + }) + + errorClient(client, err) + break } - const msg = response.message + const hostClientId = response.client_id - if (msg.output && !host.isVirtual) { - output += msg.output - } + const wsURL = `${protocol}://${baseURL.host}/ws?client_id=${hostClientId}` + const ws = new WebSocket(wsURL) + + let finished = false + + ws.on("message", (msg) => { + let data + try { + data = JSON.parse(msg) + } catch { + return + } + + if (data.error === true) { + err = true + } + + sendToClient(client, { + success: false, + error: err, + message: data.message, + }) + + errorClient(client, err) + + if (data.success === true) { + finished = true + ws.close() + } else if (err) { + ws.close() + } + }) + + ws.on("close", () => { + if (!finished && !err) { + err = true + + sendToClient(client, { + error: true, + message: `WoL WebSocket closed unexpectedly`, + }) + + errorClient(client, err) + } + }) - if (msg.success === false) { + ws.on("error", () => { err = true - break - } + + logger.error("Error during WebSocket connection: ", err.message) + + sendToClient(client, { + success: false, + error: true, + message: `WoL WebSocket error for host`, + }) + }) + + await new Promise((resolve) => { + ws.on("close", resolve) + ws.on("error", resolve) + }) + + if (err) break } - return { output, err } + return { err } } - async function waitForHostUp(url, options = {}) { const { interval = 3000, timeout = 60000 } = options const start = Date.now() @@ -209,9 +273,11 @@ async function startProcessing(req, res) { return res.json({ error: true, message: "No route for hostname" }) } - const requestId = wss.createRequestId() + const clientID = wss.createClientID() - res.json({ error: false, message: "Start request received", requestId }) + res.json({ + client_id: clientID, + }) const { hosts, routeAttributes } = resolved @@ -221,23 +287,18 @@ async function startProcessing(req, res) { let wolResult = null - if (wolEnabled && hosts.length > 0) { - wolResult = await trySendWakeupPackets(hosts, ENV.wolURL) - } - - const ws = wss.getClient(requestId) + const ws = wss.getClient(clientID) if (!ws) { return } + if (wolEnabled && hosts.length > 0) { + wolResult = await trySendWakeupPackets(ws, hosts, ENV.wolURL) + } + if (wolResult) { err = wolResult.err - - sendToClient(ws, { - error: err, - message: wolResult.output, - }) } errorClient(ws, err) @@ -295,7 +356,6 @@ async function startProcessing(req, res) { message: "", error: err, host: serviceURL.hostname, - requestId, }) } diff --git a/src/wss.js b/src/wss.js index fa3f6bf..80dcb68 100644 --- a/src/wss.js +++ b/src/wss.js @@ -10,15 +10,15 @@ function attach(server, app, router) { wss.on("connection", (socket, req) => { const url = new URL(req.url, "http://localhost") - const requestId = url.searchParams.get("requestId") + const clientID = url.searchParams.get("client_id") - if (!requestId) { - socket.send(JSON.stringify({ error: true, message: "Missing requestId" })) + if (!clientID) { + socket.send(JSON.stringify({ error: true, message: "Missing client_id" })) socket.close() return } - clients[requestId] = socket + clients[clientID] = socket socket.isAlive = true @@ -37,19 +37,19 @@ function attach(server, app, router) { socket.on("close", () => { clearInterval(interval) - delete clients[requestId] + delete clients[clientID] }) }) app.use("/", router) } -function getClient(requestId) { - return clients[requestId] +function getClient(clientID) { + return clients[clientID] } -function createRequestId() { +function createClientID() { return uuidv4() } -module.exports = { attach, getClient, createRequestId } +module.exports = { attach, getClient, createClientID } diff --git a/views/home.ejs b/views/home.ejs index be77165..24c51b4 100644 --- a/views/home.ejs +++ b/views/home.ejs @@ -280,14 +280,14 @@ if (!response.ok) throw new Error(`HTTP error ${response.status}`) const data = await response.json() - const requestId = data.requestId - if (!requestId) throw new Error("No requestId returned from server") + const clientID = data.client_id + if (!clientID) throw new Error("No requestId returned from server") logEl.textContent += "Process started. Waiting for service...\n" const protocol = location.protocol === "https:" ? "wss" : "ws" const ws = new WebSocket( - `${protocol}://${location.host}/ws?requestId=${requestId}` + `${protocol}://${location.host}/ws?client_id=${clientID}` ) ws.onopen = () => { From 403c96a419ecc4cebcf292b91005452b36500658 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 17:15:44 +0100 Subject: [PATCH 051/190] cleanup --- src/utils/request.js | 39 +++++++++++++++++++++++++ src/wol.js | 68 +++++++++++++++++++++----------------------- 2 files changed, 71 insertions(+), 36 deletions(-) create mode 100644 src/utils/request.js diff --git a/src/utils/request.js b/src/utils/request.js new file mode 100644 index 0000000..694e845 --- /dev/null +++ b/src/utils/request.js @@ -0,0 +1,39 @@ +async function post(url, data) { + try { + const response = await fetch(url, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(data), + }) + + if (!response.ok) { + throw new Error(`${url} returned HTTP ${response.status}`) + } + + return response + } catch (err) { + logger.error( + `POST error: ${err.message}; cause: ${JSON.stringify(err.cause)}` + ) + return null + } +} + +async function get(url, options) { + try { + const response = await fetch(url, options) + + if (!response.ok) { + throw new Error(`${url} returned HTTP ${response.status}`) + } + + return response + } catch (err) { + logger.error( + `GET error: ${err.message}; cause: ${JSON.stringify(err.cause)}` + ) + return null + } +} + +module.exports = { post, get } diff --git a/src/wol.js b/src/wol.js index 93618ee..7d6319b 100644 --- a/src/wol.js +++ b/src/wol.js @@ -1,8 +1,10 @@ const express = require("express") const wss = require("./wss") + const WebSocket = require("ws") const { logger } = require("./utils/logger") +const request = require("./utils/request") const { ENV } = require("./env") const fs = require("fs") @@ -17,27 +19,6 @@ function buildQuery(pattern, context) { ) } -async function post(url, data) { - try { - const response = await fetch(url, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(data), - }) - - if (!response.ok) { - throw new Error(`POST to ${url} returned HTTP ${response.status}`) - } - - return await response.json() - } catch (err) { - logger.error( - `POST error: ${err.message}; cause: ${JSON.stringify(err.cause)}` - ) - return null - } -} - function resolveRecord(hostname) { const { records } = CONFIG @@ -141,8 +122,19 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { `Sending WoL packets to ${targetUrl}: ${JSON.stringify(payload)}` ) - const response = await post(targetUrl, payload) - if (!response?.client_id) { + const response = await request.post(targetUrl, payload) + + let data = null + + if (response) { + try { + data = await response.json() + } catch { + data = null + } + } + + if (!data?.client_id) { err = true sendToClient(client, { @@ -226,23 +218,25 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { return { err } } + async function waitForHostUp(url, options = {}) { const { interval = 3000, timeout = 60000 } = options const start = Date.now() while (Date.now() - start < timeout) { - try { - const res = await fetch(url, { - method: "GET", - headers: { - "X-Redirect-Service": 1, - }, - }) + const res = await request.get(url, { + headers: { + "X-Redirect-Service": 1, + }, + }) - if (res.ok && !res.headers.get("X-Redirect-Service")) { - return true - } - } catch {} + if (res == null) { + continue + } + + if (res.ok && !res.headers.get("X-Redirect-Service")) { + return true + } await new Promise((r) => setTimeout(r, interval)) } @@ -328,9 +322,11 @@ async function startProcessing(req, res) { })}` ) - const dockerRes = await post(ENV.woldURL, { query: query }) + const dockerRes = await request.post(ENV.woldURL, { query: query }) + + const data = await request.json() - if (dockerRes?.output) { + if (data?.output) { sendToClient(ws, { error: err, message: dockerRes.output, From 6b3a708dfe5ab2e36c99f52bb066b5561a2c43f8 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 17:19:45 +0100 Subject: [PATCH 052/190] fix package --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 44ec3b3..7d1248d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wol-redirect", - "version": "1.0.0", + "version": "none", "description": "A Redirect and WoL Service", "main": "app.js", "scripts": { From aaf7eff5e629d8b0ba389994bc852abb6fcd568c Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 17:24:46 +0100 Subject: [PATCH 053/190] debug --- src/wol.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wol.js b/src/wol.js index 7d6319b..f33cd64 100644 --- a/src/wol.js +++ b/src/wol.js @@ -90,7 +90,9 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { let err = false - const baseURL = new URL(wolUrl) + logger.debug("Starting wakeup call") + const baseURL = URL.parse(wolUrl) + logger.debug("base: ", baseURL.toString()) const protocol = baseURL.protocol === "https:" ? "wss" : "ws" const virtualPort = From f2e4a816dcb8dcccdc5b923b11c73d26c1ecc65a Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 17:31:50 +0100 Subject: [PATCH 054/190] wait for client --- src/wol.js | 4 +--- src/wss.js | 24 +++++++++++++++++++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/wol.js b/src/wol.js index f33cd64..5e5589a 100644 --- a/src/wol.js +++ b/src/wol.js @@ -90,9 +90,7 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { let err = false - logger.debug("Starting wakeup call") const baseURL = URL.parse(wolUrl) - logger.debug("base: ", baseURL.toString()) const protocol = baseURL.protocol === "https:" ? "wss" : "ws" const virtualPort = @@ -283,7 +281,7 @@ async function startProcessing(req, res) { let wolResult = null - const ws = wss.getClient(clientID) + const ws = await wss.waitForClient(clientID) if (!ws) { return diff --git a/src/wss.js b/src/wss.js index 80dcb68..0e47647 100644 --- a/src/wss.js +++ b/src/wss.js @@ -1,6 +1,7 @@ const WebSocket = require("ws") const { v4: uuidv4 } = require("uuid") +const waiters = new Map() const clients = {} let wss = null @@ -20,6 +21,11 @@ function attach(server, app, router) { clients[clientID] = socket + if (waiters.has(clientID)) { + waiters.get(clientID)(socket) + waiters.delete(clientID) + } + socket.isAlive = true socket.on("pong", () => { @@ -44,6 +50,22 @@ function attach(server, app, router) { app.use("/", router) } +function waitForClient(clientID, timeout = 5000) { + return new Promise((resolve, reject) => { + const existing = clients[clientID] + if (existing) return resolve(existing) + + waiters.set(clientID, resolve) + + setTimeout(() => { + if (waiters.has(clientID)) { + waiters.delete(clientID) + reject(new Error("WebSocket connection timeout")) + } + }, timeout) + }) +} + function getClient(clientID) { return clients[clientID] } @@ -52,4 +74,4 @@ function createClientID() { return uuidv4() } -module.exports = { attach, getClient, createClientID } +module.exports = { attach, getClient, waitForClient, createClientID } From 23963ea0e0b89ebb706779b2ea9f000cffbf976a Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 17:41:01 +0100 Subject: [PATCH 055/190] add logger to request --- src/utils/request.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/utils/request.js b/src/utils/request.js index 694e845..245a1b5 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -1,3 +1,5 @@ +const logger = require("./logger") + async function post(url, data) { try { const response = await fetch(url, { From 4845d8cd6d3ea44170eca771d336914e793ab82c Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 17:51:46 +0100 Subject: [PATCH 056/190] fix import --- src/utils/request.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/request.js b/src/utils/request.js index 245a1b5..67acfdc 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -1,4 +1,4 @@ -const logger = require("./logger") +const logger = require("./logger").logger async function post(url, data) { try { From 1deacd16d9d6e6d080d55db022616aca618b51c4 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 18:00:22 +0100 Subject: [PATCH 057/190] fix --- src/utils/request.js | 4 ++++ src/wol.js | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/utils/request.js b/src/utils/request.js index 67acfdc..2b1b891 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -14,6 +14,10 @@ async function post(url, data) { return response } catch (err) { + if (!err.cause) { + err.cause = "" + } + logger.error( `POST error: ${err.message}; cause: ${JSON.stringify(err.cause)}` ) diff --git a/src/wol.js b/src/wol.js index 5e5589a..c02a663 100644 --- a/src/wol.js +++ b/src/wol.js @@ -148,7 +148,7 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { break } - const hostClientId = response.client_id + const hostClientId = data.client_id const wsURL = `${protocol}://${baseURL.host}/ws?client_id=${hostClientId}` const ws = new WebSocket(wsURL) From d370c99791ca585e15e5edd3de27abdf98912459 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 18:12:02 +0100 Subject: [PATCH 058/190] fix requestjson --- src/wol.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wol.js b/src/wol.js index c02a663..913ee08 100644 --- a/src/wol.js +++ b/src/wol.js @@ -324,7 +324,7 @@ async function startProcessing(req, res) { const dockerRes = await request.post(ENV.woldURL, { query: query }) - const data = await request.json() + const data = await dockerRes.json() if (data?.output) { sendToClient(ws, { From ffc6541577dd72ccd6de68e79c34e9c9d116f119 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 18:15:52 +0100 Subject: [PATCH 059/190] switch back to dark --- views/home.ejs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/home.ejs b/views/home.ejs index 24c51b4..bd086ac 100644 --- a/views/home.ejs +++ b/views/home.ejs @@ -330,7 +330,7 @@ } const prefersDark = window.matchMedia( - "(prefers-color-scheme: light)" + "(prefers-color-scheme: dark)" ).matches document.body.setAttribute("data-theme", prefersDark ? "dark" : "light") From 2ed59b6524e7a35f17b686b5640fb52fe17a34fb Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 18:24:41 +0100 Subject: [PATCH 060/190] debug --- src/wol.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wol.js b/src/wol.js index 913ee08..723e1e5 100644 --- a/src/wol.js +++ b/src/wol.js @@ -134,6 +134,8 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { } } + logger.debug("got: ", data) + if (!data?.client_id) { err = true From b16631f8a9f988bea3c5a03bb7d3932db429de4c Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 18:25:12 +0100 Subject: [PATCH 061/190] more debugging --- src/wol.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wol.js b/src/wol.js index 723e1e5..0fa6533 100644 --- a/src/wol.js +++ b/src/wol.js @@ -153,6 +153,7 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { const hostClientId = data.client_id const wsURL = `${protocol}://${baseURL.host}/ws?client_id=${hostClientId}` + logger.debug("url: ", wsURL) const ws = new WebSocket(wsURL) let finished = false From 42efb64c6155ac1d7bc6cc92e816a80b377c4c35 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 18:47:07 +0100 Subject: [PATCH 062/190] fix debugs --- src/wol.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wol.js b/src/wol.js index 0fa6533..a9975d5 100644 --- a/src/wol.js +++ b/src/wol.js @@ -134,7 +134,7 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { } } - logger.debug("got: ", data) + logger.debug("got: " + JSON.stringify(data)) if (!data?.client_id) { err = true @@ -153,7 +153,7 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { const hostClientId = data.client_id const wsURL = `${protocol}://${baseURL.host}/ws?client_id=${hostClientId}` - logger.debug("url: ", wsURL) + logger.debug("url: " + wsURL) const ws = new WebSocket(wsURL) let finished = false From 4748d73cd71028d729cf2e61139d45b1dc433dac Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 18:58:55 +0100 Subject: [PATCH 063/190] remove unused logs --- src/wol.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/wol.js b/src/wol.js index a9975d5..913ee08 100644 --- a/src/wol.js +++ b/src/wol.js @@ -134,8 +134,6 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { } } - logger.debug("got: " + JSON.stringify(data)) - if (!data?.client_id) { err = true @@ -153,7 +151,6 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { const hostClientId = data.client_id const wsURL = `${protocol}://${baseURL.host}/ws?client_id=${hostClientId}` - logger.debug("url: " + wsURL) const ws = new WebSocket(wsURL) let finished = false From 1f27af36bc3355f3a07f1ed5cc39b5fb4b784602 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 19:01:59 +0100 Subject: [PATCH 064/190] readd log --- src/wol.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/wol.js b/src/wol.js index 913ee08..543689a 100644 --- a/src/wol.js +++ b/src/wol.js @@ -7,6 +7,7 @@ const { logger } = require("./utils/logger") const request = require("./utils/request") const { ENV } = require("./env") const fs = require("fs") +const { url } = require("inspector") const router = express.Router() @@ -134,6 +135,8 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { } } + logger.debug("Received " + data + " from " + url) + if (!data?.client_id) { err = true From 02dd7ae80160f8b50f757312d39d932a7ee27bd4 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 19:24:09 +0100 Subject: [PATCH 065/190] make ws blocking --- src/wol.js | 124 ++++++++++++++++++----------------------------------- 1 file changed, 41 insertions(+), 83 deletions(-) diff --git a/src/wol.js b/src/wol.js index 543689a..e9c516e 100644 --- a/src/wol.js +++ b/src/wol.js @@ -85,19 +85,13 @@ function getDataByHostname(hostname) { } async function trySendWakeupPackets(client, hosts, wolUrl) { - if (!hosts?.length) return { err: true } - if (!client) return { err: true } - if (!wolUrl) return { err: true } + if (!hosts?.length || !client || !wolUrl) return { err: true } - let err = false - - const baseURL = URL.parse(wolUrl) + const baseURL = new URL(wolUrl) const protocol = baseURL.protocol === "https:" ? "wss" : "ws" + const virtualPort = ENV.virtualPort?.trim() || null - const virtualPort = - ENV.virtualPort && `${ENV.virtualPort}`.trim() !== "" - ? ENV.virtualPort - : null + let err = false for (const host of hosts) { let targetUrl = wolUrl @@ -105,18 +99,10 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { if (host.isVirtual) { if (!virtualPort) continue - targetUrl = `http://${host.ip}:${virtualPort}` - payload = { - id: host.id, - startupTime: host.startupTime, - } + payload = { id: host.id, startupTime: host.startupTime } } else { - payload = { - ip: host.ip, - mac: host.mac, - startupTime: host.startupTime, - } + payload = { ip: host.ip, mac: host.mac, startupTime: host.startupTime } } logger.debug( @@ -126,7 +112,6 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { const response = await request.post(targetUrl, payload) let data = null - if (response) { try { data = await response.json() @@ -135,88 +120,61 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { } } - logger.debug("Received " + data + " from " + url) - if (!data?.client_id) { - err = true - sendToClient(client, { success: false, error: true, - message: `WoL request failed`, + message: `WoL request failed for host ${host.ip}`, }) - - errorClient(client, err) - - break + return { err: true } } - const hostClientId = data.client_id - - const wsURL = `${protocol}://${baseURL.host}/ws?client_id=${hostClientId}` + const wsURL = `${protocol}://${baseURL.host}/ws?client_id=${data.client_id}` const ws = new WebSocket(wsURL) - let finished = false - - ws.on("message", (msg) => { - let data - try { - data = JSON.parse(msg) - } catch { - return - } - - if (data.error === true) { - err = true - } - - sendToClient(client, { - success: false, - error: err, - message: data.message, - }) - - errorClient(client, err) + const hostResult = await new Promise((resolve) => { + let finished = false - if (data.success === true) { - finished = true - ws.close() - } else if (err) { - ws.close() - } - }) + ws.on("message", (msg) => { + if (finished) return - ws.on("close", () => { - if (!finished && !err) { - err = true + let parsed + try { + parsed = JSON.parse(msg) + } catch { + return + } sendToClient(client, { - error: true, - message: `WoL WebSocket closed unexpectedly`, + error: parsed.error || false, + message: parsed.message || "", + host: host.ip, }) - errorClient(client, err) - } - }) - - ws.on("error", () => { - err = true - - logger.error("Error during WebSocket connection: ", err.message) + if (parsed.success) { + finished = true + ws.close() + resolve({ success: true }) + } else if (parsed.error) { + finished = true + ws.close() + resolve({ success: false }) + } + }) - sendToClient(client, { - success: false, - error: true, - message: `WoL WebSocket error for host`, + ws.on("close", () => { + if (!finished) resolve({ success: false }) }) - }) - await new Promise((resolve) => { - ws.on("close", resolve) - ws.on("error", resolve) + ws.on("error", () => { + if (!finished) resolve({ success: false }) + }) }) - if (err) break + if (!hostResult.success) { + err = true + break // Stop processing further hosts + } } return { err } From 988f6caa150d7de86dd97c1cddd078c1eca97a58 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 19:32:43 +0100 Subject: [PATCH 066/190] test new promise --- src/wol.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/wol.js b/src/wol.js index e9c516e..8e19ca0 100644 --- a/src/wol.js +++ b/src/wol.js @@ -110,14 +110,11 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { ) const response = await request.post(targetUrl, payload) - let data = null if (response) { try { data = await response.json() - } catch { - data = null - } + } catch {} } if (!data?.client_id) { @@ -132,6 +129,11 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { const wsURL = `${protocol}://${baseURL.host}/ws?client_id=${data.client_id}` const ws = new WebSocket(wsURL) + await new Promise((resolve, reject) => { + ws.once("open", resolve) + ws.once("error", () => resolve()) + }) + const hostResult = await new Promise((resolve) => { let finished = false @@ -173,7 +175,7 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { if (!hostResult.success) { err = true - break // Stop processing further hosts + break } } From 48f6290b28f93246880e8f4f3b89aa2bee4d51b6 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 19:33:55 +0100 Subject: [PATCH 067/190] more debugging --- src/wol.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wol.js b/src/wol.js index 8e19ca0..0127dfd 100644 --- a/src/wol.js +++ b/src/wol.js @@ -173,6 +173,8 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { }) }) + logger.debug("Finished promise: " + hostResult) + if (!hostResult.success) { err = true break From bde49b3785edf542b41210da570e40812453cad5 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 19:47:51 +0100 Subject: [PATCH 068/190] more debugging --- src/wol.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/wol.js b/src/wol.js index 0127dfd..54e902e 100644 --- a/src/wol.js +++ b/src/wol.js @@ -7,7 +7,6 @@ const { logger } = require("./utils/logger") const request = require("./utils/request") const { ENV } = require("./env") const fs = require("fs") -const { url } = require("inspector") const router = express.Router() @@ -148,33 +147,37 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { } sendToClient(client, { + success: false, error: parsed.error || false, message: parsed.message || "", - host: host.ip, }) + logger.debug("Received " + JSON.stringify(parsed)) + if (parsed.success) { finished = true + ws.close() resolve({ success: true }) } else if (parsed.error) { finished = true + ws.close() resolve({ success: false }) } }) ws.on("close", () => { + logger.debug("Closing...") if (!finished) resolve({ success: false }) }) ws.on("error", () => { + logger.debug("Error during ws!") if (!finished) resolve({ success: false }) }) }) - logger.debug("Finished promise: " + hostResult) - if (!hostResult.success) { err = true break From e9ab8baaff1e1ffce866997b9500d0f3848e6c81 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 20:25:33 +0100 Subject: [PATCH 069/190] remove unneeded debugs --- src/wol.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/wol.js b/src/wol.js index 54e902e..c371aa1 100644 --- a/src/wol.js +++ b/src/wol.js @@ -152,8 +152,6 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { message: parsed.message || "", }) - logger.debug("Received " + JSON.stringify(parsed)) - if (parsed.success) { finished = true @@ -168,12 +166,10 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { }) ws.on("close", () => { - logger.debug("Closing...") if (!finished) resolve({ success: false }) }) ws.on("error", () => { - logger.debug("Error during ws!") if (!finished) resolve({ success: false }) }) }) From 57167c26e8f0d8d0019689d85d9327c0096bee82 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 7 Dec 2025 20:29:18 +0100 Subject: [PATCH 070/190] remove host var --- src/wol.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wol.js b/src/wol.js index c371aa1..e653811 100644 --- a/src/wol.js +++ b/src/wol.js @@ -120,7 +120,7 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { sendToClient(client, { success: false, error: true, - message: `WoL request failed for host ${host.ip}`, + message: `WoL request failed for host`, }) return { err: true } } From 9fafb0a78ecd813d03029a5732acccd4dee48ba6 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Mon, 8 Dec 2025 21:20:15 +0100 Subject: [PATCH 071/190] update due to wol-dockerized update --- src/wol.js | 134 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 100 insertions(+), 34 deletions(-) diff --git a/src/wol.js b/src/wol.js index e653811..24fa8c0 100644 --- a/src/wol.js +++ b/src/wol.js @@ -64,7 +64,6 @@ function buildHostEntry(key) { mac: host.mac, id: host.id, startupTime: host.startupTime, - isVirtual: Boolean(host.isVirtual), } } @@ -83,7 +82,7 @@ function getDataByHostname(hostname) { } } -async function trySendWakeupPackets(client, hosts, wolUrl) { +async function trySendWoLPackets(client, hosts, wolUrl) { if (!hosts?.length || !client || !wolUrl) return { err: true } const baseURL = new URL(wolUrl) @@ -96,7 +95,7 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { let targetUrl = wolUrl let payload - if (host.isVirtual) { + if (host.id) { if (!virtualPort) continue targetUrl = `http://${host.ip}:${virtualPort}` payload = { id: host.id, startupTime: host.startupTime } @@ -183,6 +182,84 @@ async function trySendWakeupPackets(client, hosts, wolUrl) { return { err } } +async function trySendWoLDPackets(client, context, targetUrl, queryPattern) { + const query = buildQuery(queryPattern, context) + + logger.debug( + `Sending WoLD packets to ${targetUrl}: ${JSON.stringify({ + query: query, + })}` + ) + + const response = await request.post(targetUrl, payload) + let data = null + if (response) { + try { + data = await response.json() + } catch {} + } + + if (!data?.client_id) { + sendToClient(client, { + success: false, + error: true, + message: `WoLD request failed for host`, + }) + return { err: true } + } + + const wsURL = `${protocol}://${baseURL.host}/ws?client_id=${data.client_id}` + const ws = new WebSocket(wsURL) + + await new Promise((resolve, reject) => { + ws.once("open", resolve) + ws.once("error", () => resolve()) + }) + + const woldResult = await new Promise((resolve) => { + let finished = false + + ws.on("message", (msg) => { + if (finished) return + + let parsed + try { + parsed = JSON.parse(msg) + } catch { + return + } + + sendToClient(client, { + success: false, + error: parsed.error || false, + message: parsed.message || "", + }) + + if (parsed.success) { + finished = true + + ws.close() + resolve({ success: true }) + } else if (parsed.error) { + finished = true + + ws.close() + resolve({ success: false }) + } + }) + + ws.on("close", () => { + if (!finished) resolve({ success: false }) + }) + + ws.on("error", () => { + if (!finished) resolve({ success: false }) + }) + }) + + return { err: woldResult.success } +} + async function waitForHostUp(url, options = {}) { const { interval = 3000, timeout = 60000 } = options const start = Date.now() @@ -252,7 +329,7 @@ async function startProcessing(req, res) { } if (wolEnabled && hosts.length > 0) { - wolResult = await trySendWakeupPackets(ws, hosts, ENV.wolURL) + wolResult = await trySendWoLPackets(ws, hosts, ENV.wolURL) } if (wolResult) { @@ -261,41 +338,30 @@ async function startProcessing(req, res) { errorClient(ws, err) - const wakeDocker = Boolean(routeAttributes.wakeDocker) + const woldUrl = routeAttributes?.wold?.url || ENV.woldURL - const woldEnabled = - typeof ENV.woldURL === "string" && ENV.woldURL.trim() !== "" + let woldResult = null - if (wakeDocker && woldEnabled) { - const context = { - HOST: serviceURL.host, - HOSTNAME: serviceURL.hostname, - PORT: serviceURL.port || "", - PROTOCOL: serviceURL.protocol, - URL: originalUrl, - PATH: serviceURL.pathname, - } - - const queryPattern = routeAttributes.queryPattern || ENV.woldQueryPattern - - const query = buildQuery(queryPattern, context) + if (wakeDocker && woldUrl.trim() !== "") { + const queryPattern = + routeAttributes?.wold?.queryPattern || ENV.woldQueryPattern - logger.debug( - `Sending WoL-Dockerized packets to ${ENV.woldURL}: ${JSON.stringify({ - query: query, - })}` + woldResult = await trySendWoLDPackets( + ws, + { + HOST: serviceURL.host, + HOSTNAME: serviceURL.hostname, + PORT: serviceURL.port || "", + PROTOCOL: serviceURL.protocol, + PATH: serviceURL.pathname, + }, + woldUrl, + queryPattern ) + } - const dockerRes = await request.post(ENV.woldURL, { query: query }) - - const data = await dockerRes.json() - - if (data?.output) { - sendToClient(ws, { - error: err, - message: dockerRes.output, - }) - } + if (woldResult) { + err = woldResult.err } const isReady = await waitForHostUp(serviceURL) From 28f8ace2d16969c49ffb824baabc6574f2f501e2 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Tue, 9 Dec 2025 17:50:36 +0100 Subject: [PATCH 072/190] change config for docker --- src/wol.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/wol.js b/src/wol.js index 24fa8c0..936bb13 100644 --- a/src/wol.js +++ b/src/wol.js @@ -338,13 +338,16 @@ async function startProcessing(req, res) { errorClient(ws, err) - const woldUrl = routeAttributes?.wold?.url || ENV.woldURL - let woldResult = null - if (wakeDocker && woldUrl.trim() !== "") { - const queryPattern = - routeAttributes?.wold?.queryPattern || ENV.woldQueryPattern + const wold = routeAttributes?.wold + const woldEnabled = + wold === true || (typeof wold === "object" && wold !== null) + + const woldUrl = (routeAttributes?.wold?.url || ENV.woldURL).trim() + + if (woldEnabled && woldUrl !== "") { + const queryPattern = (wold?.queryPattern || ENV.woldQueryPattern).trim() woldResult = await trySendWoLDPackets( ws, From dd136709c0478132691f1463cb5156285dc054e0 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Tue, 9 Dec 2025 18:52:13 +0100 Subject: [PATCH 073/190] remove wold and instead merge config into host entry via `docker` field --- src/env.js | 24 ++---- src/wol.js | 247 +++++++++++++++++++++++++---------------------------- 2 files changed, 122 insertions(+), 149 deletions(-) diff --git a/src/env.js b/src/env.js index 77c476e..2c7fab1 100644 --- a/src/env.js +++ b/src/env.js @@ -9,9 +9,10 @@ const ENV = { exposeLogs: false, woldQueryPattern: "", - wolURL: null, - woldURL: null, - virtualPort: "", + wolURL: "", + + woldPort: "7777", + virtualPort: "9000", sessionKey: "", cookieKey: "", @@ -39,27 +40,18 @@ function Load() { ENV.port = process.env.PORT || ENV.port ENV.logLevel = process.env.LOG_LEVEL || ENV.logLevel - ENV.woldQueryPattern = process.env.WOLD_QUERY_PATTERN + ENV.woldQueryPattern = process.env.WOLD_QUERY_PATTERN || "" ENV.exposeLogs = process.env.EXPOSE_LOGS || ENV.exposeLogs - if (ENV.woldQueryPattern == "") { - logger.fatal(`Query pattern is empty`) - } - ENV.wolURL = process.env.WOL_URL || "" - ENV.woldURL = process.env.WOLD_URL || "" - ENV.virtualPort = process.env.VIRTUAL_PORT || "" + + ENV.woldPort = process.env.WOLD_PORT || ENV.woldPort + ENV.virtualPort = process.env.VIRTUAL_PORT || ENV.virtualPort if (!ENV.wolURL) { logger.warn("No WoL URL set") } - if (!ENV.woldURL) { - logger.warn("No WoL docker URL set") - } - if (!ENV.virtualPort) { - logger.warn("No virtual port set") - } ENV.sessionKey = process.env.SESSION_KEY || "" ENV.cookieKey = process.env.COOKIE_KEY || "" diff --git a/src/wol.js b/src/wol.js index 936bb13..dde5b31 100644 --- a/src/wol.js +++ b/src/wol.js @@ -12,6 +12,12 @@ const router = express.Router() const CONFIG = JSON.parse(fs.readFileSync(ENV.configPath, "utf8")) +const HostType = { + PHYSICAL: "physical", + VIRTUAL: "virtual", + DOCKER: "docker", +} + function buildQuery(pattern, context) { return Object.entries(context).reduce( (str, [k, v]) => str.replaceAll(`{${k}}`, v), @@ -63,6 +69,7 @@ function buildHostEntry(key) { ip: host.ip, mac: host.mac, id: host.id, + wold: host.wold, startupTime: host.startupTime, } } @@ -82,40 +89,121 @@ function getDataByHostname(hostname) { } } -async function trySendWoLPackets(client, hosts, wolUrl) { - if (!hosts?.length || !client || !wolUrl) return { err: true } +function getHostType(host) { + let type = HostType.PHYSICAL + + if (host?.id !== null && typeof host?.id === "string") { + type = HostType.VIRTUAL + } else if ( + host?.docker !== null && + (host?.docker == true || typeof host?.docker === "object") + ) { + type = HostType.DOCKER + } else if (host?.mac && host?.ip) { + type = HostType.PHYSICAL + } + + return type +} + +function getDataFromHost(host) { + const type = getHostType(host) + + switch (type) { + case HostType.PHYSICAL: + const wolUrl = host.url || ENV.wolURL + const wolURL = URL.parse(woldUrl) + + if (!wolURL) { + return null + } + + return { + url: wolUrl, + payload: { + addr: host.addr, + ip: host.ip, + mac: host.mac, + startupTime: host.startupTime, + }, + } + case HostType.VIRTUAL: + const virtualUrl = host.url || `http://${host.ip}:${ENV.virtualPort}/wake` + + const virtualURL = URL.parse(woldUrl) + + if (!virtualURL) { + return null + } + + return { + url: virtualUrl, + payload: { + id: host.id, + startupTime: host.startupTime, + }, + } + case HostType.DOCKER: + const woldUrl = host.url || `http://${host.ip}:${ENV.woldPort}/wake` + + const woldURL = URL.parse(woldUrl) + + if (!woldURL) { + return null + } + + const queryPattern = host.docker.queryPattern || ENV.woldQueryPattern + const context = { + HOST: woldURL.host, + HOSTNAME: woldURL.hostname, + PORT: woldURL.port || "", + PROTOCOL: woldURL.protocol, + PATH: woldURL.pathname, + } + + const query = buildQuery(queryPattern, context) + + return { + url: woldUrl, + payload: { + query: query, + }, + } + } - const baseURL = new URL(wolUrl) - const protocol = baseURL.protocol === "https:" ? "wss" : "ws" - const virtualPort = ENV.virtualPort?.trim() || null + return null +} + +async function trySendWoLPackets(client, hosts) { + if (!hosts?.length || !client) return { err: true } let err = false for (const host of hosts) { - let targetUrl = wolUrl - let payload - - if (host.id) { - if (!virtualPort) continue - targetUrl = `http://${host.ip}:${virtualPort}` - payload = { id: host.id, startupTime: host.startupTime } - } else { - payload = { ip: host.ip, mac: host.mac, startupTime: host.startupTime } + const data = getDataFromHost(host) + + if (data === null) { + logger.error("Could not parse host: ", host) + err = true + break } + const targetUrl = data.url + const payload = data.payload + logger.debug( - `Sending WoL packets to ${targetUrl}: ${JSON.stringify(payload)}` + `Sending WoL request to ${targetUrl}: ${JSON.stringify(payload)}` ) const response = await request.post(targetUrl, payload) - let data = null + let responseData = null if (response) { try { - data = await response.json() + responseData = await response.json() } catch {} } - if (!data?.client_id) { + if (!responseData?.client_id) { sendToClient(client, { success: false, error: true, @@ -124,7 +212,7 @@ async function trySendWoLPackets(client, hosts, wolUrl) { return { err: true } } - const wsURL = `${protocol}://${baseURL.host}/ws?client_id=${data.client_id}` + const wsURL = `${protocol}://${baseURL.host}/ws?client_id=${responseData.client_id}` const ws = new WebSocket(wsURL) await new Promise((resolve, reject) => { @@ -182,84 +270,6 @@ async function trySendWoLPackets(client, hosts, wolUrl) { return { err } } -async function trySendWoLDPackets(client, context, targetUrl, queryPattern) { - const query = buildQuery(queryPattern, context) - - logger.debug( - `Sending WoLD packets to ${targetUrl}: ${JSON.stringify({ - query: query, - })}` - ) - - const response = await request.post(targetUrl, payload) - let data = null - if (response) { - try { - data = await response.json() - } catch {} - } - - if (!data?.client_id) { - sendToClient(client, { - success: false, - error: true, - message: `WoLD request failed for host`, - }) - return { err: true } - } - - const wsURL = `${protocol}://${baseURL.host}/ws?client_id=${data.client_id}` - const ws = new WebSocket(wsURL) - - await new Promise((resolve, reject) => { - ws.once("open", resolve) - ws.once("error", () => resolve()) - }) - - const woldResult = await new Promise((resolve) => { - let finished = false - - ws.on("message", (msg) => { - if (finished) return - - let parsed - try { - parsed = JSON.parse(msg) - } catch { - return - } - - sendToClient(client, { - success: false, - error: parsed.error || false, - message: parsed.message || "", - }) - - if (parsed.success) { - finished = true - - ws.close() - resolve({ success: true }) - } else if (parsed.error) { - finished = true - - ws.close() - resolve({ success: false }) - } - }) - - ws.on("close", () => { - if (!finished) resolve({ success: false }) - }) - - ws.on("error", () => { - if (!finished) resolve({ success: false }) - }) - }) - - return { err: woldResult.success } -} - async function waitForHostUp(url, options = {}) { const { interval = 3000, timeout = 60000 } = options const start = Date.now() @@ -318,8 +328,6 @@ async function startProcessing(req, res) { let err = false - const wolEnabled = typeof ENV.wolURL === "string" && ENV.wolURL.trim() !== "" - let wolResult = null const ws = await wss.waitForClient(clientID) @@ -328,44 +336,17 @@ async function startProcessing(req, res) { return } - if (wolEnabled && hosts.length > 0) { - wolResult = await trySendWoLPackets(ws, hosts, ENV.wolURL) - } - - if (wolResult) { - err = wolResult.err + if (hosts.length > 0) { + err = true + errorClient(ws, err) + return } - errorClient(ws, err) + wolResult = await trySendWoLPackets(ws, hosts, ENV.wolURL) - let woldResult = null + err = wolResult.err - const wold = routeAttributes?.wold - const woldEnabled = - wold === true || (typeof wold === "object" && wold !== null) - - const woldUrl = (routeAttributes?.wold?.url || ENV.woldURL).trim() - - if (woldEnabled && woldUrl !== "") { - const queryPattern = (wold?.queryPattern || ENV.woldQueryPattern).trim() - - woldResult = await trySendWoLDPackets( - ws, - { - HOST: serviceURL.host, - HOSTNAME: serviceURL.hostname, - PORT: serviceURL.port || "", - PROTOCOL: serviceURL.protocol, - PATH: serviceURL.pathname, - }, - woldUrl, - queryPattern - ) - } - - if (woldResult) { - err = woldResult.err - } + errorClient(ws, err) const isReady = await waitForHostUp(serviceURL) From dc06b203fd23e3c268b019cde4f593e2d869a7aa Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Tue, 9 Dec 2025 19:20:56 +0100 Subject: [PATCH 074/190] update logs --- views/home.ejs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/home.ejs b/views/home.ejs index bd086ac..a5f8655 100644 --- a/views/home.ejs +++ b/views/home.ejs @@ -281,7 +281,7 @@ const data = await response.json() const clientID = data.client_id - if (!clientID) throw new Error("No requestId returned from server") + if (!clientID) throw new Error("No client_id returned from server") logEl.textContent += "Process started. Waiting for service...\n" From ab5c01a2cd7c7eb0cf74f435597fdd9e77048cf8 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Tue, 9 Dec 2025 19:22:17 +0100 Subject: [PATCH 075/190] fix if-statement --- src/wol.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wol.js b/src/wol.js index dde5b31..fee320c 100644 --- a/src/wol.js +++ b/src/wol.js @@ -336,7 +336,7 @@ async function startProcessing(req, res) { return } - if (hosts.length > 0) { + if (hosts.length <= 0) { err = true errorClient(ws, err) return From 0aa2f468218305f9b88c346089c36dc6fa030a61 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Tue, 9 Dec 2025 19:24:53 +0100 Subject: [PATCH 076/190] only expose logs if expose logs is set to true --- src/env.js | 2 +- src/wol.js | 26 +++++++++++++++++++------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/env.js b/src/env.js index 2c7fab1..4043689 100644 --- a/src/env.js +++ b/src/env.js @@ -6,7 +6,7 @@ const ENV = { configPath: "config/mapping.json", port: "6789", logLevel: "info", - exposeLogs: false, + exposeLogs: true, woldQueryPattern: "", wolURL: "", diff --git a/src/wol.js b/src/wol.js index fee320c..e82719d 100644 --- a/src/wol.js +++ b/src/wol.js @@ -207,7 +207,7 @@ async function trySendWoLPackets(client, hosts) { sendToClient(client, { success: false, error: true, - message: `WoL request failed for host`, + message: ENV.exposeLogs ? `wakeup request failed for host` : "", }) return { err: true } } @@ -236,7 +236,7 @@ async function trySendWoLPackets(client, hosts) { sendToClient(client, { success: false, error: parsed.error || false, - message: parsed.message || "", + message: ENV.exposeLogs ? parsed.message || "" : "", }) if (parsed.success) { @@ -297,25 +297,37 @@ async function waitForHostUp(url, options = {}) { async function startProcessing(req, res) { if (!req.isAuthenticated()) { - return res.json({ error: true, message: "Unauthorized" }) + return res.json({ + error: true, + message: ENV.exposeLogs ? "Unauthorized" : "", + }) } const originalUrl = req.cookies.serviceUrl if (!originalUrl) { - return res.json({ error: true, message: "Missing serviceUrl cookie" }) + return res.json({ + error: true, + message: ENV.exposeLogs ? "Missing serviceUrl cookie" : "", + }) } let serviceURL try { serviceURL = new URL(originalUrl) } catch (err) { - return res.status(400).json({ error: true, message: "Invalid serviceUrl" }) + return res.status(400).json({ + error: true, + message: ENV.exposeLogs ? "Invalid serviceUrl" : "", + }) } const resolved = getDataByHostname(serviceURL.hostname) if (!resolved) { - return res.json({ error: true, message: "No route for hostname" }) + return res.json({ + error: true, + message: ENV.exposeLogs ? "No route for hostname" : "", + }) } const clientID = wss.createClientID() @@ -355,7 +367,7 @@ async function startProcessing(req, res) { sendToClient(ws, { error: err, - message: "Timeout waiting for service", + message: ENV.exposeLogs ? "Timeout waiting for service" : "", }) } From 1c8a39dc154c213fce4f06a1e0cab15f40000168 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Tue, 9 Dec 2025 19:26:42 +0100 Subject: [PATCH 077/190] fix typos --- src/wol.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wol.js b/src/wol.js index e82719d..137cb05 100644 --- a/src/wol.js +++ b/src/wol.js @@ -112,7 +112,7 @@ function getDataFromHost(host) { switch (type) { case HostType.PHYSICAL: const wolUrl = host.url || ENV.wolURL - const wolURL = URL.parse(woldUrl) + const wolURL = URL.parse(wolUrl) if (!wolURL) { return null @@ -130,7 +130,7 @@ function getDataFromHost(host) { case HostType.VIRTUAL: const virtualUrl = host.url || `http://${host.ip}:${ENV.virtualPort}/wake` - const virtualURL = URL.parse(woldUrl) + const virtualURL = URL.parse(virtualUrl) if (!virtualURL) { return null From 1e5edfc3e0a71929d3719d0c54cfe183afaf40d4 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Tue, 9 Dec 2025 19:33:47 +0100 Subject: [PATCH 078/190] create wsurl based on targeturl --- src/wol.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/wol.js b/src/wol.js index 137cb05..4060cf5 100644 --- a/src/wol.js +++ b/src/wol.js @@ -189,6 +189,14 @@ async function trySendWoLPackets(client, hosts) { } const targetUrl = data.url + const targetURL = URL.parse(targetUrl) + + if (!targetURL) { + logger.error("Could not parse target url: ", host) + err = true + break + } + const payload = data.payload logger.debug( @@ -212,7 +220,8 @@ async function trySendWoLPackets(client, hosts) { return { err: true } } - const wsURL = `${protocol}://${baseURL.host}/ws?client_id=${responseData.client_id}` + const wsProtocol = targetURL.protocol === "https:" ? "wss" : "ws" + const wsURL = `${wsProtocol}://${targetURL.host}/ws?client_id=${responseData.client_id}` const ws = new WebSocket(wsURL) await new Promise((resolve, reject) => { From 4cbf57997aa81de4e0d1bcf4343a6194d4bc07d4 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Tue, 9 Dec 2025 19:41:10 +0100 Subject: [PATCH 079/190] fix payload for virtual hosts --- src/wol.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wol.js b/src/wol.js index 4060cf5..8718af2 100644 --- a/src/wol.js +++ b/src/wol.js @@ -140,6 +140,7 @@ function getDataFromHost(host) { url: virtualUrl, payload: { id: host.id, + ip: host.ip, startupTime: host.startupTime, }, } From d6b17fec47ff17bc439df3882e7df35994cf170b Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Wed, 10 Dec 2025 19:02:36 +0100 Subject: [PATCH 080/190] use virtIP instead of ip for pinging purposes --- src/wol.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wol.js b/src/wol.js index 8718af2..6c12406 100644 --- a/src/wol.js +++ b/src/wol.js @@ -140,7 +140,7 @@ function getDataFromHost(host) { url: virtualUrl, payload: { id: host.id, - ip: host.ip, + virtIP: host.ip, startupTime: host.startupTime, }, } From 17b8c2b87442fa6fc2c2a0cc64776c2c1dcb6a60 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Wed, 10 Dec 2025 19:06:14 +0100 Subject: [PATCH 081/190] update vePort --- src/env.js | 4 ++-- src/wol.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/env.js b/src/env.js index 4043689..6812722 100644 --- a/src/env.js +++ b/src/env.js @@ -12,7 +12,7 @@ const ENV = { wolURL: "", woldPort: "7777", - virtualPort: "9000", + vePort: "9999", sessionKey: "", cookieKey: "", @@ -47,7 +47,7 @@ function Load() { ENV.wolURL = process.env.WOL_URL || "" ENV.woldPort = process.env.WOLD_PORT || ENV.woldPort - ENV.virtualPort = process.env.VIRTUAL_PORT || ENV.virtualPort + ENV.vePort = process.env.VIRTUAL_PORT || ENV.vePort if (!ENV.wolURL) { logger.warn("No WoL URL set") diff --git a/src/wol.js b/src/wol.js index 6c12406..58ab1f2 100644 --- a/src/wol.js +++ b/src/wol.js @@ -128,7 +128,7 @@ function getDataFromHost(host) { }, } case HostType.VIRTUAL: - const virtualUrl = host.url || `http://${host.ip}:${ENV.virtualPort}/wake` + const virtualUrl = host.url || `http://${host.ip}:${ENV.vePort}/wake` const virtualURL = URL.parse(virtualUrl) From b47abfee9de211883eb976cf24adf02b32ecd46e Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Wed, 10 Dec 2025 19:07:51 +0100 Subject: [PATCH 082/190] fix payload of ve --- src/wol.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wol.js b/src/wol.js index 58ab1f2..6488cdb 100644 --- a/src/wol.js +++ b/src/wol.js @@ -140,7 +140,7 @@ function getDataFromHost(host) { url: virtualUrl, payload: { id: host.id, - virtIP: host.ip, + ip: host.virtIP, startupTime: host.startupTime, }, } From 0e2237556c91bb599dcd6f6ae94d73330d95e4e3 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Wed, 10 Dec 2025 19:39:48 +0100 Subject: [PATCH 083/190] return whole host object --- src/wol.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/wol.js b/src/wol.js index 6488cdb..ad91594 100644 --- a/src/wol.js +++ b/src/wol.js @@ -65,13 +65,7 @@ function buildHostEntry(key) { host = CONFIG.hosts.any } - return { - ip: host.ip, - mac: host.mac, - id: host.id, - wold: host.wold, - startupTime: host.startupTime, - } + return host } function getDataByHostname(hostname) { From 305a236c2d58462c09819ba04b580a8e44574c4a Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Wed, 10 Dec 2025 19:55:34 +0100 Subject: [PATCH 084/190] uppercase in logs --- src/wol.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wol.js b/src/wol.js index ad91594..0eebca8 100644 --- a/src/wol.js +++ b/src/wol.js @@ -210,7 +210,7 @@ async function trySendWoLPackets(client, hosts) { sendToClient(client, { success: false, error: true, - message: ENV.exposeLogs ? `wakeup request failed for host` : "", + message: ENV.exposeLogs ? `Wakeup request failed for host` : "", }) return { err: true } } From 5b8ec0695e278312b56b5f36e085fc15f8445fe9 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Wed, 10 Dec 2025 21:41:43 +0100 Subject: [PATCH 085/190] fix --- src/wol.js | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/wol.js b/src/wol.js index 0eebca8..134880b 100644 --- a/src/wol.js +++ b/src/wol.js @@ -100,7 +100,7 @@ function getHostType(host) { return type } -function getDataFromHost(host) { +function getDataFromHost(host, serviceUrl) { const type = getHostType(host) switch (type) { @@ -147,13 +147,19 @@ function getDataFromHost(host) { return null } + const serviceURL = URL.parse(serviceUrl) + + if (!serviceURL) { + return null + } + const queryPattern = host.docker.queryPattern || ENV.woldQueryPattern const context = { - HOST: woldURL.host, - HOSTNAME: woldURL.hostname, - PORT: woldURL.port || "", - PROTOCOL: woldURL.protocol, - PATH: woldURL.pathname, + HOST: serviceURL.host, + HOSTNAME: serviceURL.hostname, + PORT: serviceURL.port || "", + PROTOCOL: serviceURL.protocol, + PATH: serviceURL.pathname, } const query = buildQuery(queryPattern, context) @@ -169,13 +175,13 @@ function getDataFromHost(host) { return null } -async function trySendWoLPackets(client, hosts) { +async function trySendWoLPackets(client, hosts, serviceUrl) { if (!hosts?.length || !client) return { err: true } let err = false for (const host of hosts) { - const data = getDataFromHost(host) + const data = getDataFromHost(host, serviceUrl) if (data === null) { logger.error("Could not parse host: ", host) From 98d387089639a260ee642640efce7a4e66748f50 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Wed, 10 Dec 2025 21:45:28 +0100 Subject: [PATCH 086/190] fix --- src/wol.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wol.js b/src/wol.js index 134880b..cd8dcf7 100644 --- a/src/wol.js +++ b/src/wol.js @@ -364,7 +364,7 @@ async function startProcessing(req, res) { return } - wolResult = await trySendWoLPackets(ws, hosts, ENV.wolURL) + wolResult = await trySendWoLPackets(ws, hosts, originalUrl) err = wolResult.err From 9f8f028afdd457d087e838aa290f95e57dcb5ac5 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Fri, 12 Dec 2025 15:07:14 +0100 Subject: [PATCH 087/190] move frontend js into module --- public/js/wol.js | 73 +++++++++++++++++++++++++++++++ views/home.ejs | 109 +++++++++++++++++------------------------------ 2 files changed, 113 insertions(+), 69 deletions(-) create mode 100644 public/js/wol.js diff --git a/public/js/wol.js b/public/js/wol.js new file mode 100644 index 0000000..f47d8af --- /dev/null +++ b/public/js/wol.js @@ -0,0 +1,73 @@ +export async function startWoLProcess({ + endpoint = "/start", + onwsopen = () => { + outputHandler("WebSocket connected.") + }, + onwserror = (err) => { + outputHandler("WebSocket connection failed.") + errorHandler(err) + }, + onwsclose = () => { + outputHandler("WebSocket closed.") + }, + onerror = (ws, msg) => { + outputHandler("Failed to start service.") + ws.close() + errorHandler(msg.message) + }, + onmessage = (ws, msg) => { + outputHandler(msg.message) + }, + onsuccess = (ws, msg) => { + outputHandler("Service is online! Redirecting...") + ws.close() + window.location.href = msg.url + }, + errorHandler = (msg) => { + console.error(msg) + }, + outputHandler = (msg) => { + console.log(msg) + }, +}) { + try { + const response = await fetch(endpoint) + if (!response.ok) throw new Error(`HTTP error ${response.status}`) + + const data = await response.json() + const clientID = data.client_id + if (!clientID) throw new Error("No client_id returned from server") + + logEl.textContent += "Process started. Waiting for service...\n" + + const protocol = location.protocol === "https:" ? "wss" : "ws" + const ws = new WebSocket( + `${protocol}://${location.host}/ws?client_id=${clientID}` + ) + + ws.onopen = onwsopen + + ws.onmessage = (event) => { + const msg = JSON.parse(event.data) + + if (msg.message) { + onmessage(ws, msg) + } + + if (!msg.error && msg.url) { + onsuccess(ws, msg) + } + + if (msg.error) { + onerror(ws, msg) + } + } + + ws.onerror = onwserror + + ws.onclose = onwsclose + } catch (err) { + outputHandler(`Failed to start process: ${err.message}`) + errorHandler(err.message) + } +} diff --git a/views/home.ejs b/views/home.ejs index a5f8655..cb0ebbd 100644 --- a/views/home.ejs +++ b/views/home.ejs @@ -239,14 +239,21 @@

Starting Service

-

You will be Redirected shortly

+

Initializing startup...

-

+

- From 83b07f7f87211ea644176c5e5d837caa16a84cf3 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Fri, 12 Dec 2025 15:12:05 +0100 Subject: [PATCH 088/190] add public folder --- src/app.js | 1 + src/auth.js | 1 + 2 files changed, 2 insertions(+) diff --git a/src/app.js b/src/app.js index 9e976e6..f358300 100644 --- a/src/app.js +++ b/src/app.js @@ -17,6 +17,7 @@ if (log.logger.level != env.ENV.logLevel) { app.set("view engine", "ejs") app.set("trust proxy", true) +app.use(express.static("../public")) app.use((req, res, next) => { res.setHeader("X-Redirect-Service", "1") diff --git a/src/auth.js b/src/auth.js index a15be55..2fd5d37 100644 --- a/src/auth.js +++ b/src/auth.js @@ -116,6 +116,7 @@ router.get("/", (req, res) => { return res.render("home", { username: req.user.username, + redirect: redirectURL.toString(), }) }) From 9aa790be2e12f3b22cdad9d6ad1a1e540419298d Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Fri, 12 Dec 2025 15:38:52 +0100 Subject: [PATCH 089/190] move css into own files --- public/style/default.css | 210 +++++++++++++++++++++++++++++++++++++++ public/style/user.css | 18 ++++ 2 files changed, 228 insertions(+) create mode 100644 public/style/default.css create mode 100644 public/style/user.css diff --git a/public/style/default.css b/public/style/default.css new file mode 100644 index 0000000..e053d84 --- /dev/null +++ b/public/style/default.css @@ -0,0 +1,210 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body[data-theme="dark"] { + --bg-color: #211f1f; + --dot-color: #ffffff; + + --card-color: #1a1919; + + --text-color: #ffffff; + --secondary-color: #bbbbbb; + + --spinner-color: #4b8264; + --spinner-color-transparent: transparent; + --line-color: #8f3d3d; +} + +body[data-theme="light"] { + --bg-color: #ffffff; + --dot-color: #2a2a2a; + + --card-color: #ffffff; + + --text-color: #1a1919; + --secondary-color: #555555; + + --spinner-color: #5aa47b; + --spinner-color-transparent: transparent; + --line-color: #d9534f; +} + +body { + color: var(--text-color); + font-family: "Gill Sans", "Gill Sans MT", Calibri, "Trebuchet MS", sans-serif; + background: var(--bg-color); + + display: flex; + height: 100vh; + align-items: center; + justify-content: center; + flex-direction: row; + + transition: background 0.3s, color 0.3s; + + z-index: 1; +} + +.container { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + + width: 100%; + max-width: 600px; + + padding: 40px 30px; + + gap: 25px; + + background: var(--card-color); + border-radius: 16px; + + box-shadow: 0 0 25px rgba(0, 0, 0, 0.35); + border: 1px solid rgba(255, 255, 255, 0.05); + + backdrop-filter: blur(18px); + -webkit-backdrop-filter: blur(18px); +} + +.top-row { + display: flex; + align-items: center; + min-height: 10vh; +} + +.middle-row { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + gap: 10px; +} + +.bottom-row { + padding-top: 30px; + display: flex; + align-items: center; + gap: 30px; + font-size: 14px; + white-space: pre-wrap; + color: var(--secondary-color); + opacity: 0.8; +} + +.spinner { + height: 120px; + width: 120px; + border: 8px solid; + border-color: var(--spinner-color) var(--spinner-color) var(--spinner-color) + var(--spinner-color-transparent); + border-radius: 50%; +} + +.line { + position: absolute; + height: 80px; + width: 120px; + border: 8px solid; + border-color: var(--line-color) var(--line-color) var(--line-color) + var(--line-color); + border-radius: 50%; +} + +#hide { + opacity: 0; +} + +#spin { + animation: spin 0.8s ease infinite; +} + +#cross-line { + animation: collapse-to-cross 1s ease forwards; +} + +#add-line { + animation: add-line 1s ease forwards; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +@keyframes collapse-to-cross { + 40% { + border-color: var(--line-color) transparent var(--line-color) transparent; + } + 100% { + height: 0px; + border-radius: 6px; + border-color: var(--line-color) transparent var(--line-color) transparent; + transform: rotate(45deg); + } +} + +@keyframes add-line { + 20% { + opacity: 1; + } + 40% { + border-color: var(--line-color) transparent var(--line-color) transparent; + } + 100% { + opacity: 1; + height: 0px; + border-radius: 6px; + border-color: var(--line-color) transparent var(--line-color) transparent; + transform: rotate(-45deg); + } +} + +.bg-pattern { + position: fixed; + inset: 0; + z-index: -1; + + background-image: radial-gradient(var(--dot-color) 1px, transparent 1px); + background-size: 20px 20px; + + opacity: 0.25; + animation: move-dots 18s linear infinite; + + z-index: 0; +} + +.bg-pattern::after { + content: ""; + position: absolute; + inset: 0; + + background-image: radial-gradient(var(--dot-color) 1px, transparent 1px); + background-size: 28px 28px; + opacity: 0.15; + + animation: move-dots-reverse 28s linear infinite; +} + +@keyframes move-dots { + from { + background-position: 0 0; + } + to { + background-position: 200px 200px; + } +} + +@keyframes move-dots-reverse { + from { + background-position: 0 0; + } + to { + background-position: -200px -200px; + } +} diff --git a/public/style/user.css b/public/style/user.css new file mode 100644 index 0000000..f9a7930 --- /dev/null +++ b/public/style/user.css @@ -0,0 +1,18 @@ +.profile { + display: flex; + flex-direction: column; + align-self: center; + text-align: center; + justify-content: center; + + margin: 5px; + padding: 1px; + + border-radius: 360px; + aspect-ratio: 1 / 1; + + height: clamp(20px, 2vh + 2vw, 6vh); + + font-size: clamp(15px, 1vh + 1vw, 5vh - 15px); + font-weight: bold; +} From 272b800639f4c597dd5f6d1bbf18c8f812247b38 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Fri, 12 Dec 2025 15:39:08 +0100 Subject: [PATCH 090/190] add profile picture with ejs and oauth claims --- public/js/user.js | 16 +++ src/auth.js | 10 +- views/home.ejs | 242 ++++------------------------------------------ 3 files changed, 45 insertions(+), 223 deletions(-) create mode 100644 public/js/user.js diff --git a/public/js/user.js b/public/js/user.js new file mode 100644 index 0000000..c8f6a86 --- /dev/null +++ b/public/js/user.js @@ -0,0 +1,16 @@ +export function getProfileColor( + str, + { hues = [10, 40, 60, 90, 120, 150, 180, 200, 220, 250, 280, 310, 340] } +) { + let hash = 0 + for (let i = 0; i < str.length; i++) { + hash = str.charCodeAt(i) + ((hash << 5) - hash) + } + + const hue = hues[Math.abs(hash) % hues.length] + + const saturation = 70 + const lightness = 60 + + return `hsl(${hue}, ${saturation}%, ${lightness}%)` +} diff --git a/src/auth.js b/src/auth.js index 2fd5d37..df39e89 100644 --- a/src/auth.js +++ b/src/auth.js @@ -47,6 +47,8 @@ passport.use( const userInfo = await fetchUserInfo(accessToken) const username = userInfo.username || userInfo.preferred_username + const email = userInfo.email + const locale = userInfo.locale if (!username) { return done(new Error("No username provided by IDP")) @@ -55,6 +57,8 @@ passport.use( return done(null, { accessToken, username, + email, + locale, rawUserInfo: userInfo, }) } catch (err) { @@ -115,7 +119,11 @@ router.get("/", (req, res) => { } return res.render("home", { - username: req.user.username, + user: { + name: req.user.username, + locale: req.user.locale, + email: req.user.email, + }, redirect: redirectURL.toString(), }) }) diff --git a/views/home.ejs b/views/home.ejs index cb0ebbd..39ceaa9 100644 --- a/views/home.ejs +++ b/views/home.ejs @@ -3,230 +3,11 @@ - Redirect Page - + Redirect Page
@@ -246,8 +27,22 @@

+ +
+
+
+ + + @@ -28,13 +34,19 @@ + +
- - - - Redirect Page From ad473abcc9d9413c0b37f1107733a435451ef15e Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 11:15:27 +0100 Subject: [PATCH 155/190] move css --- public/style/default.css | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/public/style/default.css b/public/style/default.css index cf5d30d..ef467c0 100644 --- a/public/style/default.css +++ b/public/style/default.css @@ -1,3 +1,31 @@ +body[data-theme="dark"] { + --bg-color: #211f1f; + --dot-color: #ffffff; + + --card-color: #1a1919; + + --text-color: #ffffff; + --secondary-color: #bbbbbb; + + --spinner-color: #4b8264; + --spinner-color-transparent: transparent; + --line-color: #8f3d3d; +} + +body[data-theme="light"] { + --bg-color: #ffffff; + --dot-color: #2a2a2a; + + --card-color: #ffffff; + + --text-color: #1a1919; + --secondary-color: #555555; + + --spinner-color: #5aa47b; + --spinner-color-transparent: transparent; + --line-color: #d9534f; +} + * { margin: 0; padding: 0; From b5389a6d1c979c26f0d8881d0f36027eac29ad4c Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 11:18:37 +0100 Subject: [PATCH 156/190] fix css --- public/style/default.css | 28 ---------------------------- public/style/theme.css | 28 ++++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/public/style/default.css b/public/style/default.css index ef467c0..cf5d30d 100644 --- a/public/style/default.css +++ b/public/style/default.css @@ -1,31 +1,3 @@ -body[data-theme="dark"] { - --bg-color: #211f1f; - --dot-color: #ffffff; - - --card-color: #1a1919; - - --text-color: #ffffff; - --secondary-color: #bbbbbb; - - --spinner-color: #4b8264; - --spinner-color-transparent: transparent; - --line-color: #8f3d3d; -} - -body[data-theme="light"] { - --bg-color: #ffffff; - --dot-color: #2a2a2a; - - --card-color: #ffffff; - - --text-color: #1a1919; - --secondary-color: #555555; - - --spinner-color: #5aa47b; - --spinner-color-transparent: transparent; - --line-color: #d9534f; -} - * { margin: 0; padding: 0; diff --git a/public/style/theme.css b/public/style/theme.css index d0a091b..7587acb 100644 --- a/public/style/theme.css +++ b/public/style/theme.css @@ -1,3 +1,31 @@ +html[data-theme="dark"] { + --bg-color: #211f1f; + --dot-color: #ffffff; + + --card-color: #1a1919; + + --text-color: #ffffff; + --secondary-color: #bbbbbb; + + --spinner-color: #4b8264; + --spinner-color-transparent: transparent; + --line-color: #8f3d3d; +} + +html[data-theme="light"] { + --bg-color: #ffffff; + --dot-color: #2a2a2a; + + --card-color: #ffffff; + + --text-color: #1a1919; + --secondary-color: #555555; + + --spinner-color: #5aa47b; + --spinner-color-transparent: transparent; + --line-color: #d9534f; +} + .theme-toggle { position: absolute; From a74754a7cdc8ae3af70090793028ed9ae73450cf Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 11:23:09 +0100 Subject: [PATCH 157/190] fix typo --- views/home.ejs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/home.ejs b/views/home.ejs index b5481de..22f3a95 100644 --- a/views/home.ejs +++ b/views/home.ejs @@ -106,7 +106,7 @@ }, onwsopen: () => { handleSubtitle("Starting process...") - handleOutput("WebSocket connected.") + handleOutput("WebSocket connected") }, onsuccess: (ws, msg) => { if (msg.url !== serviceUrl) { From 88fe0ea996fee337b699cf8e42c3a957a8596966 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 11:48:11 +0100 Subject: [PATCH 158/190] add icons for toggle (from fontawesome) --- public/img/moon.svg | 1 + public/img/sun.svg | 1 + public/style/theme.css | 12 ++++++------ views/home.ejs | 4 ++-- 4 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 public/img/moon.svg create mode 100644 public/img/sun.svg diff --git a/public/img/moon.svg b/public/img/moon.svg new file mode 100644 index 0000000..d6c6d77 --- /dev/null +++ b/public/img/moon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/sun.svg b/public/img/sun.svg new file mode 100644 index 0000000..0479496 --- /dev/null +++ b/public/img/sun.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/style/theme.css b/public/style/theme.css index 7587acb..d59e622 100644 --- a/public/style/theme.css +++ b/public/style/theme.css @@ -46,26 +46,26 @@ html[data-theme="light"] { -webkit-backdrop-filter: blur(18px); } -.sun, -.moon { +.theme-toggle #sun, +.theme-toggle #moon { position: absolute; opacity: 0; } -html[data-theme="light"] .moon { +html[data-theme="light"] .theme-toggle #moon { opacity: 1; transform: scale(1); } -html[data-theme="light"] .sun { +html[data-theme="light"] .theme-toggle #sun { transform: scale(0.8); } -html[data-theme="dark"] .sun { +html[data-theme="dark"] .theme-toggle #sun { opacity: 1; transform: scale(1); } -html[data-theme="dark"] .moon { +html[data-theme="dark"] .theme-toggle #moon { transform: scale(0.8); } diff --git a/views/home.ejs b/views/home.ejs index 22f3a95..f105121 100644 --- a/views/home.ejs +++ b/views/home.ejs @@ -35,8 +35,8 @@
From a23a774584e8d7757cf3e72494017fcd9fb087d4 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 12:14:12 +0100 Subject: [PATCH 159/190] hide and show --- public/style/theme.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/style/theme.css b/public/style/theme.css index d59e622..2ba7495 100644 --- a/public/style/theme.css +++ b/public/style/theme.css @@ -49,11 +49,11 @@ html[data-theme="light"] { .theme-toggle #sun, .theme-toggle #moon { position: absolute; - opacity: 0; + display: none; } html[data-theme="light"] .theme-toggle #moon { - opacity: 1; + display: block; transform: scale(1); } @@ -62,7 +62,7 @@ html[data-theme="light"] .theme-toggle #sun { } html[data-theme="dark"] .theme-toggle #sun { - opacity: 1; + display: block; transform: scale(1); } From eeca842f31b8df6af59dc8a139cc1ba62e39d374 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 12:27:55 +0100 Subject: [PATCH 160/190] fix theme --- public/style/theme.css | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/public/style/theme.css b/public/style/theme.css index 2ba7495..41c8294 100644 --- a/public/style/theme.css +++ b/public/style/theme.css @@ -2,6 +2,8 @@ html[data-theme="dark"] { --bg-color: #211f1f; --dot-color: #ffffff; + --icon-color: #ffffff; + --card-color: #1a1919; --text-color: #ffffff; @@ -16,6 +18,8 @@ html[data-theme="light"] { --bg-color: #ffffff; --dot-color: #2a2a2a; + --icon-color: #1a1a1a; + --card-color: #ffffff; --text-color: #1a1919; @@ -34,7 +38,7 @@ html[data-theme="light"] { aspect-ratio: 1 / 1; - height: clamp(50px, 6vmin, 60px); + height: clamp(50px / 1.5, 6vmin / 1.5, 60px / 1.5); background: var(--card-color); border-radius: 16px; @@ -48,24 +52,13 @@ html[data-theme="light"] { .theme-toggle #sun, .theme-toggle #moon { - position: absolute; display: none; } html[data-theme="light"] .theme-toggle #moon { display: block; - transform: scale(1); -} - -html[data-theme="light"] .theme-toggle #sun { - transform: scale(0.8); } html[data-theme="dark"] .theme-toggle #sun { display: block; - transform: scale(1); -} - -html[data-theme="dark"] .theme-toggle #moon { - transform: scale(0.8); } From 991ff81813317ed7569d203d4c90942524b51225 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 12:28:01 +0100 Subject: [PATCH 161/190] add iconcolor --- public/style/theme.css | 1 + 1 file changed, 1 insertion(+) diff --git a/public/style/theme.css b/public/style/theme.css index 41c8294..1f60b4f 100644 --- a/public/style/theme.css +++ b/public/style/theme.css @@ -52,6 +52,7 @@ html[data-theme="light"] { .theme-toggle #sun, .theme-toggle #moon { + color: var(--icon-color); display: none; } From a053df9fd5df7418891bb7a5364c20e51c47aad8 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 12:42:44 +0100 Subject: [PATCH 162/190] removed fontawesome icons due to incorrect colors; will create custom :) --- public/img/moon.svg | 1 - public/img/sun.svg | 1 - 2 files changed, 2 deletions(-) delete mode 100644 public/img/moon.svg delete mode 100644 public/img/sun.svg diff --git a/public/img/moon.svg b/public/img/moon.svg deleted file mode 100644 index d6c6d77..0000000 --- a/public/img/moon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/img/sun.svg b/public/img/sun.svg deleted file mode 100644 index 0479496..0000000 --- a/public/img/sun.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file From 2c3a63b71970bac1cddebffd3cbfc62a3648858b Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 21:32:30 +0100 Subject: [PATCH 163/190] add icons --- public/style/theme.css | 4 ++++ public/style/user.css | 4 ++++ views/home.ejs | 36 ++++++++++++++++++++++++++++++++++-- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/public/style/theme.css b/public/style/theme.css index 1f60b4f..57fbd32 100644 --- a/public/style/theme.css +++ b/public/style/theme.css @@ -33,6 +33,10 @@ html[data-theme="light"] { .theme-toggle { position: absolute; + display: flex; + justify-content: center; + align-items: center; + top: 15px; left: 15px; diff --git a/public/style/user.css b/public/style/user.css index 18c7df1..2915f12 100644 --- a/public/style/user.css +++ b/public/style/user.css @@ -1,6 +1,10 @@ .user { position: absolute; + display: flex; + justify-content: center; + align-items: center; + top: 15px; right: 15px; diff --git a/views/home.ejs b/views/home.ejs index f105121..ff07b97 100644 --- a/views/home.ejs +++ b/views/home.ejs @@ -35,8 +35,40 @@
From 0110653302e03d52e7ac8e961512a0cf092b49b0 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 21:51:56 +0100 Subject: [PATCH 164/190] add possibility to not use auth --- src/auth.js | 106 +++++++++++++++++++++++----------------------------- src/env.js | 72 +++++++++++++++++++++-------------- src/wol.js | 41 ++++++++++++++++++++ 3 files changed, 130 insertions(+), 89 deletions(-) diff --git a/src/auth.js b/src/auth.js index 8f3d65b..ceaaed7 100644 --- a/src/auth.js +++ b/src/auth.js @@ -41,9 +41,7 @@ async function fetchUserInfo(accessToken) { } } -function Init() { - redirectURL = new URL(ENV.redirectURL) - +function registerOauth() { passport.use( new OAuth2Strategy( { @@ -83,65 +81,9 @@ function Init() { passport.serializeUser((user, done) => done(null, user)) passport.deserializeUser((user, done) => done(null, user)) - router.use( - session({ - store: new RedisStore({ client: redisClient }), - secret: ENV.sessionKey, - resave: false, - saveUninitialized: false, - cookie: { - domain: redirectURL.hostname, - secure: true, - sameSite: "lax", - maxAge: 1000 * 60 * 60, - }, - }) - ) - router.use(passport.initialize()) router.use(passport.session()) - router.get("/", async (req, res) => { - if (req.query.session_id) { - res.cookie("session_id", req.query.session_id, { - domain: redirectURL.hostname, - httpOnly: true, - secure: true, - sameSite: "lax", - maxAge: 1000 * 60 * 60, - }) - } - - if (req.hostname !== redirectURL.hostname) { - const originalHost = req.headers["x-forwarded-host"] || req.get("host") - const originalProto = req.headers["x-forwarded-proto"] || req.protocol - const originalUri = req.headers["x-forwarded-uri"] || req.originalUrl - - const originalUrl = `${originalProto}://${originalHost}${originalUri}` - - const sessionID = uuidv4() - - await WriteToCache(`service=${sessionID}`, originalUrl) - - return res.redirect(`${redirectURL.origin}/?session_id=${sessionID}`) - } - - if (!req.isAuthenticated()) { - return res.redirect("/auth") - } - - const serviceUrl = await GetFromCache(`service=${req.query.session_id}`) - - res.render("home", { - user: { - name: req.user.username, - locale: req.user.locale, - email: req.user.email, - }, - serviceUrl: serviceUrl, - }) - }) - router.get("/auth", passport.authenticate("oauth2")) router.get("/auth/callback", passport.authenticate("oauth2"), (req, res) => @@ -157,8 +99,52 @@ function Init() { }) } +function registerFakeAuth() { + router.get("/auth", (req, res) => { + if (!req.session.user) { + req.session.user = { + username: "user", + email: "", + locale: "", + accessToken: null, + } + } + + req.user = req.session.user + + req.isAuthenticated = () => true + }) + + router.get("/logout", (req, res) => { + if (!req.isAuthenticated()) return + + req.session.destroy() + }) +} + export function Router() { - Init() + redirectURL = new URL(ENV.redirectURL) + + router.use( + session({ + store: new RedisStore({ client: redisClient }), + secret: ENV.sessionKey, + resave: false, + saveUninitialized: false, + cookie: { + domain: redirectURL.hostname, + secure: true, + sameSite: "lax", + maxAge: 1000 * 60 * 60, + }, + }) + ) + + if (ENV.useOauth) { + registerOauth() + } else { + registerFakeAuth() + } return router } diff --git a/src/env.js b/src/env.js index 51c0df6..fc8ef57 100644 --- a/src/env.js +++ b/src/env.js @@ -6,7 +6,9 @@ export const ENV = { configPath: "/app/config/mapping.json", port: "6789", logLevel: "info", + exposeLogs: true, + useOauth: true, redisHost: "redis", redisPort: "6379", @@ -51,7 +53,11 @@ export function Load() { ENV.woldQueryPattern = process.env.WOLD_QUERY_PATTERN || "" - ENV.exposeLogs = process.env.EXPOSE_LOGS || ENV.exposeLogs + const exposeLogs = process.env.EXPOSE_LOGS + + if (exposeLogs) { + ENV.exposeLogs = exposeLogs.trim().toLowerCase() == "true" + } ENV.wolURL = process.env.WOL_URL || "" @@ -68,37 +74,45 @@ export function Load() { logger.fatal("No session key provided") } - ENV.authorizationURL = process.env.AUTHORIZATION_URL || "" - ENV.resourceURL = process.env.RESOURCE_URL || "" - ENV.logoutURL = process.env.LOGOUT_URL || "" - ENV.tokenURL = process.env.TOKEN_URL || "" - ENV.redirectURL = process.env.REDIRECT_URL || "" + const useOauth = process.env.USE_OAUTH - if (!ENV.authorizationURL) { - logger.fatal("No authorization URL set") - } - if (!ENV.resourceURL) { - logger.fatal("No resource URL set") - } - if (!ENV.logoutURL) { - logger.fatal("No logout URL set") - } - if (!ENV.tokenURL) { - logger.fatal("No token URL set") - } - if (!ENV.redirectURL) { - logger.fatal("No redirect URL set") + if (useOauth) { + ENV.useOauth = useOauth.trim().toLowerCase() == "true" } - ENV.clientID = process.env.CLIENT_ID || "" - ENV.clientSecret = process.env.CLIENT_SECRET || "" - ENV.scope = process.env.SCOPE || ENV.scope - - if (!ENV.clientID) { - logger.fatal("No client id provided") - } - if (!ENV.clientSecret) { - logger.fatal("No client secret provided") + if (ENV.useOauth) { + ENV.authorizationURL = process.env.AUTHORIZATION_URL || "" + ENV.resourceURL = process.env.RESOURCE_URL || "" + ENV.logoutURL = process.env.LOGOUT_URL || "" + ENV.tokenURL = process.env.TOKEN_URL || "" + ENV.redirectURL = process.env.REDIRECT_URL || "" + + if (!ENV.authorizationURL) { + logger.fatal("No authorization URL set") + } + if (!ENV.resourceURL) { + logger.fatal("No resource URL set") + } + if (!ENV.logoutURL) { + logger.fatal("No logout URL set") + } + if (!ENV.tokenURL) { + logger.fatal("No token URL set") + } + if (!ENV.redirectURL) { + logger.fatal("No redirect URL set") + } + + ENV.clientID = process.env.CLIENT_ID || "" + ENV.clientSecret = process.env.CLIENT_SECRET || "" + ENV.scope = process.env.SCOPE || ENV.scope + + if (!ENV.clientID) { + logger.fatal("No client id provided") + } + if (!ENV.clientSecret) { + logger.fatal("No client secret provided") + } } logger.info("Loaded Environment") diff --git a/src/wol.js b/src/wol.js index 2b4b956..7786048 100644 --- a/src/wol.js +++ b/src/wol.js @@ -440,4 +440,45 @@ export function Router() { return router } +router.get("/", async (req, res) => { + if (req.query.session_id) { + res.cookie("session_id", req.query.session_id, { + domain: redirectURL.hostname, + httpOnly: true, + secure: true, + sameSite: "lax", + maxAge: 1000 * 60 * 60, + }) + } + + if (req.hostname !== redirectURL.hostname) { + const originalHost = req.headers["x-forwarded-host"] || req.get("host") + const originalProto = req.headers["x-forwarded-proto"] || req.protocol + const originalUri = req.headers["x-forwarded-uri"] || req.originalUrl + + const originalUrl = `${originalProto}://${originalHost}${originalUri}` + + const sessionID = uuidv4() + + await WriteToCache(`service=${sessionID}`, originalUrl) + + return res.redirect(`${redirectURL.origin}/?session_id=${sessionID}`) + } + + if (!req.isAuthenticated()) { + return res.redirect("/auth") + } + + const serviceUrl = await GetFromCache(`service=${req.query.session_id}`) + + res.render("home", { + user: { + name: req.user.username, + locale: req.user.locale, + email: req.user.email, + }, + serviceUrl: serviceUrl, + }) +}) + router.get("/start", async (req, res) => await startProcessing(req, res)) From dd6610f03167c76dbca5280eda185a10f58224f2 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 21:56:59 +0100 Subject: [PATCH 165/190] fix noauth --- src/auth.js | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/auth.js b/src/auth.js index ceaaed7..ef3f713 100644 --- a/src/auth.js +++ b/src/auth.js @@ -42,6 +42,8 @@ async function fetchUserInfo(accessToken) { } function registerOauth() { + redirectURL = new URL(ENV.redirectURL) + passport.use( new OAuth2Strategy( { @@ -81,6 +83,21 @@ function registerOauth() { passport.serializeUser((user, done) => done(null, user)) passport.deserializeUser((user, done) => done(null, user)) + router.use( + session({ + store: new RedisStore({ client: redisClient }), + secret: ENV.sessionKey, + resave: false, + saveUninitialized: false, + cookie: { + domain: redirectURL.hostname, + secure: true, + sameSite: "lax", + maxAge: 1000 * 60 * 60, + }, + }) + ) + router.use(passport.initialize()) router.use(passport.session()) @@ -123,23 +140,6 @@ function registerFakeAuth() { } export function Router() { - redirectURL = new URL(ENV.redirectURL) - - router.use( - session({ - store: new RedisStore({ client: redisClient }), - secret: ENV.sessionKey, - resave: false, - saveUninitialized: false, - cookie: { - domain: redirectURL.hostname, - secure: true, - sameSite: "lax", - maxAge: 1000 * 60 * 60, - }, - }) - ) - if (ENV.useOauth) { registerOauth() } else { From 749a8cacdac8e3f849a45358a3e9f49ba2bb8c0b Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 22:17:09 +0100 Subject: [PATCH 166/190] fix? --- src/app.js | 4 +++- src/auth.js | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/wol.js | 32 ++++---------------------------- src/wss.js | 4 +--- 4 files changed, 59 insertions(+), 32 deletions(-) diff --git a/src/app.js b/src/app.js index b5398ac..d712c17 100644 --- a/src/app.js +++ b/src/app.js @@ -44,6 +44,8 @@ await Init() app.use(cookieParser()) app.use("/", auth()) +app.use("/", wol()) + app.use((err, req, res, next) => { log.logger.error(err) res.status(500).send("Encountered an unexpected error") @@ -51,7 +53,7 @@ app.use((err, req, res, next) => { const server = createServer(app) -Attach(server, app, wol()) +Attach(server) server.listen(env.ENV.port, () => { log.logger.info(`Server running on Port ${env.ENV.port}`) diff --git a/src/auth.js b/src/auth.js index ef3f713..5bb51a1 100644 --- a/src/auth.js +++ b/src/auth.js @@ -41,6 +41,20 @@ async function fetchUserInfo(accessToken) { } } +async function handleServiceUrl(req, res) { + const originalHost = req.headers["x-forwarded-host"] || req.get("host") + const originalProto = req.headers["x-forwarded-proto"] || req.protocol + const originalUri = req.headers["x-forwarded-uri"] || req.originalUrl + + const originalUrl = `${originalProto}://${originalHost}${originalUri}` + + const sessionID = uuidv4() + + await WriteToCache(`service=${sessionID}`, originalUrl) + + return res.redirect(`${redirectURL.origin}/?session_id=${sessionID}`) +} + function registerOauth() { redirectURL = new URL(ENV.redirectURL) @@ -101,6 +115,28 @@ function registerOauth() { router.use(passport.initialize()) router.use(passport.session()) + router.get("/", async (req, res, next) => { + if (req.query.session_id) { + res.cookie("session_id", req.query.session_id, { + domain: redirectURL.hostname, + httpOnly: true, + secure: true, + sameSite: "lax", + maxAge: 1000 * 60 * 60, + }) + } + + if (req.hostname !== redirectURL.hostname) { + await handleServiceUrl(req, res) + } + + if (!req.isAuthenticated()) { + return res.redirect("/auth") + } + + next() + }) + router.get("/auth", passport.authenticate("oauth2")) router.get("/auth/callback", passport.authenticate("oauth2"), (req, res) => @@ -117,6 +153,21 @@ function registerOauth() { } function registerFakeAuth() { + router.get("/", async (req, res, next) => { + if (req.query.session_id) { + res.cookie("session_id", req.query.session_id, { + httpOnly: true, + secure: true, + sameSite: "lax", + maxAge: 1000 * 60 * 60, + }) + } + + await handleServiceUrl(req, res) + + next() + }) + router.get("/auth", (req, res) => { if (!req.session.user) { req.session.user = { diff --git a/src/wol.js b/src/wol.js index 7786048..cda4cbe 100644 --- a/src/wol.js +++ b/src/wol.js @@ -440,38 +440,14 @@ export function Router() { return router } -router.get("/", async (req, res) => { - if (req.query.session_id) { - res.cookie("session_id", req.query.session_id, { - domain: redirectURL.hostname, - httpOnly: true, - secure: true, - sameSite: "lax", - maxAge: 1000 * 60 * 60, - }) - } - - if (req.hostname !== redirectURL.hostname) { - const originalHost = req.headers["x-forwarded-host"] || req.get("host") - const originalProto = req.headers["x-forwarded-proto"] || req.protocol - const originalUri = req.headers["x-forwarded-uri"] || req.originalUrl - - const originalUrl = `${originalProto}://${originalHost}${originalUri}` - - const sessionID = uuidv4() - - await WriteToCache(`service=${sessionID}`, originalUrl) - - return res.redirect(`${redirectURL.origin}/?session_id=${sessionID}`) - } - - if (!req.isAuthenticated()) { - return res.redirect("/auth") +router.get("/", async (req, res, next) => { + if (!req.session) { + return res.status(500).send("Bad Request: Missing session_id") } const serviceUrl = await GetFromCache(`service=${req.query.session_id}`) - res.render("home", { + return res.render("home", { user: { name: req.user.username, locale: req.user.locale, diff --git a/src/wss.js b/src/wss.js index d8f6e9e..2330c1e 100644 --- a/src/wss.js +++ b/src/wss.js @@ -6,7 +6,7 @@ const clients = {} let wss = null -export function Attach(server, app, router) { +export function Attach(server) { wss = new WebSocketServer({ server }) wss.on("connection", (socket, req) => { @@ -46,8 +46,6 @@ export function Attach(server, app, router) { delete clients[clientID] }) }) - - app.use("/", router) } export function WaitForClient(clientID, timeout = 5000) { From 3bb8d3e4834001759f6196d3b6b8e3132e8d0f3e Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 22:19:45 +0100 Subject: [PATCH 167/190] fix missing redirectURl for noauth --- src/auth.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auth.js b/src/auth.js index 5bb51a1..09a8029 100644 --- a/src/auth.js +++ b/src/auth.js @@ -52,7 +52,7 @@ async function handleServiceUrl(req, res) { await WriteToCache(`service=${sessionID}`, originalUrl) - return res.redirect(`${redirectURL.origin}/?session_id=${sessionID}`) + return res.redirect(`/?session_id=${sessionID}`) } function registerOauth() { From 282dde0f29f29384bd608b22fc285e29a544daab Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 22:25:12 +0100 Subject: [PATCH 168/190] add check before sending --- src/auth.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/auth.js b/src/auth.js index 09a8029..9cfc74d 100644 --- a/src/auth.js +++ b/src/auth.js @@ -126,15 +126,18 @@ function registerOauth() { }) } + let handled if (req.hostname !== redirectURL.hostname) { - await handleServiceUrl(req, res) + handled = await handleServiceUrl(req, res) } if (!req.isAuthenticated()) { return res.redirect("/auth") } - next() + if (!handled) { + next() + } }) router.get("/auth", passport.authenticate("oauth2")) @@ -163,9 +166,11 @@ function registerFakeAuth() { }) } - await handleServiceUrl(req, res) + const handled = await handleServiceUrl(req, res) - next() + if (!handled) { + next() + } }) router.get("/auth", (req, res) => { From cb49a753ee78fee9bc70036ae509c429be5ab674 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 22:37:01 +0100 Subject: [PATCH 169/190] testing ?fix? --- src/auth.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/auth.js b/src/auth.js index 9cfc74d..234d0b7 100644 --- a/src/auth.js +++ b/src/auth.js @@ -126,18 +126,15 @@ function registerOauth() { }) } - let handled if (req.hostname !== redirectURL.hostname) { - handled = await handleServiceUrl(req, res) + return handleServiceUrl(req, res) } if (!req.isAuthenticated()) { return res.redirect("/auth") } - if (!handled) { - next() - } + next() }) router.get("/auth", passport.authenticate("oauth2")) @@ -164,13 +161,11 @@ function registerFakeAuth() { sameSite: "lax", maxAge: 1000 * 60 * 60, }) + } else { + return await handleServiceUrl(req, res) } - const handled = await handleServiceUrl(req, res) - - if (!handled) { - next() - } + next() }) router.get("/auth", (req, res) => { From 0fddf51570bcb0ec1653362ed7d05e0c75c37782 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 22:39:53 +0100 Subject: [PATCH 170/190] add session to noauth --- src/auth.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/auth.js b/src/auth.js index 234d0b7..2da0af0 100644 --- a/src/auth.js +++ b/src/auth.js @@ -153,6 +153,20 @@ function registerOauth() { } function registerFakeAuth() { + router.use( + session({ + store: new RedisStore({ client: redisClient }), + secret: ENV.sessionKey, + resave: false, + saveUninitialized: false, + cookie: { + secure: true, + sameSite: "lax", + maxAge: 1000 * 60 * 60, + }, + }) + ) + router.get("/", async (req, res, next) => { if (req.query.session_id) { res.cookie("session_id", req.query.session_id, { From 01b82f7dc420b240b0b4b7e47db58f65662e9068 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 22:42:27 +0100 Subject: [PATCH 171/190] add "auth" to noauth --- src/auth.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/auth.js b/src/auth.js index 2da0af0..5e5bed2 100644 --- a/src/auth.js +++ b/src/auth.js @@ -179,6 +179,10 @@ function registerFakeAuth() { return await handleServiceUrl(req, res) } + if (!req.isAuthenticated()) { + return res.redirect("/auth") + } + next() }) From 02016342cc486a604342b51f7270ec97d96899c2 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 22:47:41 +0100 Subject: [PATCH 172/190] check if isAuthenticated is a func / exists --- src/auth.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auth.js b/src/auth.js index 5e5bed2..712afa8 100644 --- a/src/auth.js +++ b/src/auth.js @@ -179,7 +179,7 @@ function registerFakeAuth() { return await handleServiceUrl(req, res) } - if (!req.isAuthenticated()) { + if (!req.isAuthenticated) { return res.redirect("/auth") } From a7fefb2ad5ebc2ab7c9c58f388c3eb52097d2769 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 22:53:49 +0100 Subject: [PATCH 173/190] add session managament for fakeauth --- src/auth.js | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/auth.js b/src/auth.js index 712afa8..d1760f4 100644 --- a/src/auth.js +++ b/src/auth.js @@ -167,6 +167,16 @@ function registerFakeAuth() { }) ) + router.use((req, res, next) => { + if (req.session?.user) { + req.user = req.session.user + req.isAuthenticated = () => true + } else { + req.isAuthenticated = () => false + } + next() + }) + router.get("/", async (req, res, next) => { if (req.query.session_id) { res.cookie("session_id", req.query.session_id, { @@ -179,7 +189,7 @@ function registerFakeAuth() { return await handleServiceUrl(req, res) } - if (!req.isAuthenticated) { + if (!req.isAuthenticated()) { return res.redirect("/auth") } @@ -187,18 +197,13 @@ function registerFakeAuth() { }) router.get("/auth", (req, res) => { - if (!req.session.user) { - req.session.user = { - username: "user", - email: "", - locale: "", - accessToken: null, - } + req.session.user = { + username: "user", + email: "", + locale: "", } - req.user = req.session.user - - req.isAuthenticated = () => true + return res.redirect("/") }) router.get("/logout", (req, res) => { From f2d2e2c36cdc2765f4a849bd213524249c33e281 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 22:56:52 +0100 Subject: [PATCH 174/190] add icon-color --- public/style/theme.css | 1 + 1 file changed, 1 insertion(+) diff --git a/public/style/theme.css b/public/style/theme.css index 57fbd32..4226066 100644 --- a/public/style/theme.css +++ b/public/style/theme.css @@ -57,6 +57,7 @@ html[data-theme="light"] { .theme-toggle #sun, .theme-toggle #moon { color: var(--icon-color); + fill: var(--icon-color); display: none; } From 6f30d7cf7f244ac1b5df177eda910a1a903ac146 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 23:00:00 +0100 Subject: [PATCH 175/190] remove unnecessary css --- public/style/user.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/public/style/user.css b/public/style/user.css index 2915f12..b366853 100644 --- a/public/style/user.css +++ b/public/style/user.css @@ -17,11 +17,7 @@ } .profile { - display: flex; - flex-direction: column; - align-self: center; text-align: center; - justify-content: center; margin: 3px; padding: 1px; From 3f4397a9c52849367b9751e52bef65427bed57a2 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 13 Dec 2025 23:02:52 +0100 Subject: [PATCH 176/190] fix css --- public/style/user.css | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/public/style/user.css b/public/style/user.css index b366853..62b99c5 100644 --- a/public/style/user.css +++ b/public/style/user.css @@ -17,10 +17,13 @@ } .profile { + display: flex; + align-self: center; text-align: center; + justify-content: center; - margin: 3px; - padding: 1px; + margin: 3px 3px 3px 3px; + padding: 1px 1px 1px 1px; border-radius: 360px; aspect-ratio: 1 / 1; From d943f0234c5d2b4060a039bb52c59530494517c7 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 14 Dec 2025 12:02:00 +0100 Subject: [PATCH 177/190] remove unnecessary redirects with noauth --- src/auth.js | 52 +++++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/auth.js b/src/auth.js index d1760f4..3bf68a1 100644 --- a/src/auth.js +++ b/src/auth.js @@ -41,18 +41,14 @@ async function fetchUserInfo(accessToken) { } } -async function handleServiceUrl(req, res) { +async function getOriginalUrl(req) { const originalHost = req.headers["x-forwarded-host"] || req.get("host") const originalProto = req.headers["x-forwarded-proto"] || req.protocol const originalUri = req.headers["x-forwarded-uri"] || req.originalUrl const originalUrl = `${originalProto}://${originalHost}${originalUri}` - const sessionID = uuidv4() - - await WriteToCache(`service=${sessionID}`, originalUrl) - - return res.redirect(`/?session_id=${sessionID}`) + return originalUrl } function registerOauth() { @@ -127,7 +123,13 @@ function registerOauth() { } if (req.hostname !== redirectURL.hostname) { - return handleServiceUrl(req, res) + const originalUrl = getOriginalUrl(req, res) + + const sessionID = uuidv4() + + await WriteToCache(`service=${sessionID}`, originalUrl) + + return res.redirect(`${redirectURL.origin}/?session_id=${sessionID}`) } if (!req.isAuthenticated()) { @@ -178,31 +180,31 @@ function registerFakeAuth() { }) router.get("/", async (req, res, next) => { - if (req.query.session_id) { - res.cookie("session_id", req.query.session_id, { - httpOnly: true, - secure: true, - sameSite: "lax", - maxAge: 1000 * 60 * 60, - }) - } else { - return await handleServiceUrl(req, res) + if (!req.isAuthenticated) { + req.session.user = { + username: "user", + email: "", + locale: "", + } } - if (!req.isAuthenticated()) { - return res.redirect("/auth") - } + const originalUrl = getOriginalUrl(req, res) + + const sessionID = uuidv4() + + res.cookie("session_id", req.query.session_id, { + httpOnly: true, + secure: true, + sameSite: "lax", + maxAge: 1000 * 60 * 60, + }) + + await WriteToCache(`service=${sessionID}`, originalUrl) next() }) router.get("/auth", (req, res) => { - req.session.user = { - username: "user", - email: "", - locale: "", - } - return res.redirect("/") }) From ad29bd028790032e4b6fe6fc702eeaead898b6fb Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 14 Dec 2025 12:06:11 +0100 Subject: [PATCH 178/190] fix --- src/auth.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/auth.js b/src/auth.js index 3bf68a1..5931cb0 100644 --- a/src/auth.js +++ b/src/auth.js @@ -123,7 +123,9 @@ function registerOauth() { } if (req.hostname !== redirectURL.hostname) { - const originalUrl = getOriginalUrl(req, res) + const originalUrl = getOriginalUrl(req) + + logger.debug("Cached original url: ", originalUrl) const sessionID = uuidv4() @@ -188,7 +190,7 @@ function registerFakeAuth() { } } - const originalUrl = getOriginalUrl(req, res) + const originalUrl = getOriginalUrl(req) const sessionID = uuidv4() From 0b5660b480a630f6a037c7bcc3af96e942ab5c1c Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 14 Dec 2025 12:07:03 +0100 Subject: [PATCH 179/190] fix remove async --- src/auth.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auth.js b/src/auth.js index 5931cb0..1592ab2 100644 --- a/src/auth.js +++ b/src/auth.js @@ -41,7 +41,7 @@ async function fetchUserInfo(accessToken) { } } -async function getOriginalUrl(req) { +function getOriginalUrl(req) { const originalHost = req.headers["x-forwarded-host"] || req.get("host") const originalProto = req.headers["x-forwarded-proto"] || req.protocol const originalUri = req.headers["x-forwarded-uri"] || req.originalUrl From a4efb8d4790b1385d850acf576162b459f73a47c Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 14 Dec 2025 12:10:35 +0100 Subject: [PATCH 180/190] fix debug --- src/auth.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auth.js b/src/auth.js index 1592ab2..bd260f9 100644 --- a/src/auth.js +++ b/src/auth.js @@ -125,7 +125,7 @@ function registerOauth() { if (req.hostname !== redirectURL.hostname) { const originalUrl = getOriginalUrl(req) - logger.debug("Cached original url: ", originalUrl) + logger.debug("Cached original url: " + originalUrl) const sessionID = uuidv4() From b39acafee0bcb926386c9d92819f3181f0cf4d6f Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 14 Dec 2025 12:31:16 +0100 Subject: [PATCH 181/190] improve session_id management, use state instead of query --- src/auth.js | 26 ++++++++++++++++++++------ src/db.js | 10 +++++++--- src/wol.js | 10 +++++----- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/auth.js b/src/auth.js index bd260f9..eb91da9 100644 --- a/src/auth.js +++ b/src/auth.js @@ -12,7 +12,7 @@ import { logger } from "./utils/logger.js" import { redisClient, - GetFromCache, + ReadFromCache, WriteToCache, DeleteFromCache, } from "./db.js" @@ -112,8 +112,18 @@ function registerOauth() { router.use(passport.session()) router.get("/", async (req, res, next) => { - if (req.query.session_id) { - res.cookie("session_id", req.query.session_id, { + // auth.com => app.com + if (req.query.state) { + const state = req.query.state + + const sessionID = await ReadFromCache(`oauth_state=${state}`) + if (!sessionID) { + return res.status(400).send("Invalid or expired oauth state") + } + + await DeleteFromCache(`oauth_state=${state}`) + + res.cookie("session_id", sessionID, { domain: redirectURL.hostname, httpOnly: true, secure: true, @@ -122,18 +132,22 @@ function registerOauth() { }) } + // entry.com => app.com if (req.hostname !== redirectURL.hostname) { const originalUrl = getOriginalUrl(req) - - logger.debug("Cached original url: " + originalUrl) + logger.debug("Cached entrypoint: " + originalUrl) const sessionID = uuidv4() + const state = uuidv4() await WriteToCache(`service=${sessionID}`, originalUrl) - return res.redirect(`${redirectURL.origin}/?session_id=${sessionID}`) + await WriteToCache(`oauth_state=${state}`, sessionID, { expire: 600 }) + + return res.redirect(`${redirectURL.origin}/?state=${state}`) } + // app.com => auth.com if (!req.isAuthenticated()) { return res.redirect("/auth") } diff --git a/src/db.js b/src/db.js index e0add4d..067b48b 100644 --- a/src/db.js +++ b/src/db.js @@ -19,7 +19,7 @@ export async function Init() { logger.debug("Connected to Redis") } -export async function GetFromCache(key, { hash = false } = {}) { +export async function ReadFromCache(key, { hash = false } = {}) { if (hash) { return await redisClient.hGetAll(key) } else { @@ -27,14 +27,18 @@ export async function GetFromCache(key, { hash = false } = {}) { } } -export async function WriteToCache(key, value, { hash = false } = {}) { +export async function WriteToCache( + key, + value, + { hash = false, expire = 3600 } = {} +) { if (hash) { await redisClient.hSet(key, value) } else { await redisClient.set(key, value) } - await redisClient.expire(key, 3600) + await redisClient.expire(key, expire) } export async function DeleteFromCache(key, { hash = false } = {}) { diff --git a/src/wol.js b/src/wol.js index cda4cbe..5a3dba1 100644 --- a/src/wol.js +++ b/src/wol.js @@ -7,7 +7,7 @@ import { ENV } from "./env.js" import request from "./utils/request.js" import * as wss from "./wss.js" -import { GetFromCache, DeleteFromCache } from "./db.js" +import { ReadFromCache, DeleteFromCache } from "./db.js" const router = express.Router() @@ -335,7 +335,7 @@ async function startProcessing(req, res) { } const key = `service=${sessionID}` - const originalUrl = await GetFromCache(key) + const originalUrl = await ReadFromCache(key) await DeleteFromCache(key) @@ -441,11 +441,11 @@ export function Router() { } router.get("/", async (req, res, next) => { - if (!req.session) { - return res.status(500).send("Bad Request: Missing session_id") + if (!req.cookies.session_id) { + return res.redirect("/auth") } - const serviceUrl = await GetFromCache(`service=${req.query.session_id}`) + const serviceUrl = await ReadFromCache(`service=${req.cookies.session_id}`) return res.render("home", { user: { From 61d34b484ae3cd3a174bbe353dabcbe1fcbcb13d Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 14 Dec 2025 15:27:52 +0100 Subject: [PATCH 182/190] fix animation --- public/style/default.css | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/public/style/default.css b/public/style/default.css index cf5d30d..30d1d16 100644 --- a/public/style/default.css +++ b/public/style/default.css @@ -70,7 +70,7 @@ body { .spinner { height: clamp(80px, 14vmin, 120px); - aspect-ratio: 1 / 1; + width: clamp(80px, 14vmin, 120px); border: 8px solid; border-color: var(--spinner-color) var(--spinner-color) var(--spinner-color) var(--spinner-color-transparent); @@ -79,8 +79,8 @@ body { .line { position: absolute; - height: 80px; - width: 120px; + height: clamp(80px, 14vmin, 120px); + width: clamp(80px, 14vmin, 120px); border: 8px solid; border-color: var(--line-color) var(--line-color) var(--line-color) var(--line-color); @@ -88,7 +88,7 @@ body { } #hide { - opacity: 0; + display: none; } #spin { @@ -123,13 +123,13 @@ body { @keyframes add-line { 20% { - opacity: 1; + display: none; } 40% { border-color: var(--line-color) transparent var(--line-color) transparent; } 100% { - opacity: 1; + display: block; height: 0px; border-radius: 6px; border-color: var(--line-color) transparent var(--line-color) transparent; From 253b81b747fbc12af678b34ee3cd93e5725777b7 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 14 Dec 2025 15:36:45 +0100 Subject: [PATCH 183/190] fix user name centering --- public/style/user.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/style/user.css b/public/style/user.css index 62b99c5..618386f 100644 --- a/public/style/user.css +++ b/public/style/user.css @@ -18,9 +18,9 @@ .profile { display: flex; - align-self: center; - text-align: center; + justify-content: center; + align-items: center; margin: 3px 3px 3px 3px; padding: 1px 1px 1px 1px; From 93ea6d2d3aad7f8652a6b075268970b6d04b4b8f Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 14 Dec 2025 15:41:20 +0100 Subject: [PATCH 184/190] fix log --- src/wol.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wol.js b/src/wol.js index 5a3dba1..f241979 100644 --- a/src/wol.js +++ b/src/wol.js @@ -212,7 +212,7 @@ async function trySendWoLPackets(client, hosts, serviceUrl) { const response = await request.post(targetUrl, payload) if (!response?.ok) { - logger.error(`${url} returned ${response.statusText}`) + logger.error(`${targetUrl} returned ${response.statusText}`) err = true break } From 9a856f04445dd2bf31295a485f8e5b96a3b3ac39 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Mon, 15 Dec 2025 20:00:40 +0100 Subject: [PATCH 185/190] use return of func instead of func object --- src/auth.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auth.js b/src/auth.js index eb91da9..80a997a 100644 --- a/src/auth.js +++ b/src/auth.js @@ -196,7 +196,7 @@ function registerFakeAuth() { }) router.get("/", async (req, res, next) => { - if (!req.isAuthenticated) { + if (!req.isAuthenticated()) { req.session.user = { username: "user", email: "", From edc7ff538393a33a9172aab9511646c1913c70c0 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Mon, 15 Dec 2025 20:10:53 +0100 Subject: [PATCH 186/190] fix: use sessionID generated by server instead of query --- src/auth.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auth.js b/src/auth.js index 80a997a..7c77c01 100644 --- a/src/auth.js +++ b/src/auth.js @@ -208,7 +208,7 @@ function registerFakeAuth() { const sessionID = uuidv4() - res.cookie("session_id", req.query.session_id, { + res.cookie("session_id", sessionID, { httpOnly: true, secure: true, sameSite: "lax", From bd30e52b6fbaf554a007311b0699c814824e942b Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Mon, 15 Dec 2025 20:32:16 +0100 Subject: [PATCH 187/190] handle premature websocket close as error instead of waiting --- public/js/wol.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/public/js/wol.js b/public/js/wol.js index f4abd5e..8fa80c3 100644 --- a/public/js/wol.js +++ b/public/js/wol.js @@ -7,8 +7,13 @@ export async function startWoLProcess({ outputHandler("WebSocket connection failed") errorHandler() }, - onwsclose = () => { - outputHandler("WebSocket closed") + onwsclose = (success) => { + if (success) { + outputHandler("WebSocket closed") + } else { + outputHandler("WebSocket closed unexpectedly") + errorHandler("Process ended early") + } }, onerror = (ws, msg) => { outputHandler("Failed to start service") @@ -45,6 +50,8 @@ export async function startWoLProcess({ `${protocol}://${location.host}/ws?client_id=${clientID}` ) + let success = false + ws.onopen = onwsopen ws.onmessage = (event) => { @@ -55,6 +62,7 @@ export async function startWoLProcess({ } if (!msg.error && msg.url) { + success = true onsuccess(ws, msg) } @@ -65,7 +73,9 @@ export async function startWoLProcess({ ws.onerror = onwserror - ws.onclose = onwsclose + ws.onclose = () => { + onwsclose(success) + } } catch (err) { outputHandler(`Failed to start process: ${err.message}`) errorHandler(err.message) From 16f5cca226a39cb8208609f823f77d1f3dd15876 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Mon, 15 Dec 2025 20:37:45 +0100 Subject: [PATCH 188/190] use hostname as username --- src/auth.js | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/auth.js b/src/auth.js index 7c77c01..02bc92c 100644 --- a/src/auth.js +++ b/src/auth.js @@ -52,8 +52,6 @@ function getOriginalUrl(req) { } function registerOauth() { - redirectURL = new URL(ENV.redirectURL) - passport.use( new OAuth2Strategy( { @@ -196,16 +194,23 @@ function registerFakeAuth() { }) router.get("/", async (req, res, next) => { + const originalUrl = getOriginalUrl(req) + + let originalURL + try { + originalURL = new URL(originalUrl) + } catch (err) { + logger.error("Error parsing service URL: ", originalUrl) + } + if (!req.isAuthenticated()) { req.session.user = { - username: "user", + username: originalURL.hostname, email: "", locale: "", } } - const originalUrl = getOriginalUrl(req) - const sessionID = uuidv4() res.cookie("session_id", sessionID, { @@ -215,7 +220,10 @@ function registerFakeAuth() { maxAge: 1000 * 60 * 60, }) - await WriteToCache(`service=${sessionID}`, originalUrl) + await WriteToCache( + `${redirectURL?.origin || ""}/service=${sessionID}`, + originalUrl + ) next() }) @@ -232,6 +240,12 @@ function registerFakeAuth() { } export function Router() { + try { + redirectURL = new URL(ENV.redirectURL) + } catch (err) { + logger.error("Error parsing redirect URL: ", ENV.redirectURL) + } + if (ENV.useOauth) { registerOauth() } else { From 90883be06138b66090a6da53fc9ddedfa3c62789 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Mon, 15 Dec 2025 20:41:44 +0100 Subject: [PATCH 189/190] make redirectURL optional for noauth --- src/auth.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/auth.js b/src/auth.js index 02bc92c..633f689 100644 --- a/src/auth.js +++ b/src/auth.js @@ -52,6 +52,8 @@ function getOriginalUrl(req) { } function registerOauth() { + if (!redirectURL) return + passport.use( new OAuth2Strategy( { @@ -242,11 +244,13 @@ function registerFakeAuth() { export function Router() { try { redirectURL = new URL(ENV.redirectURL) - } catch (err) { - logger.error("Error parsing redirect URL: ", ENV.redirectURL) - } + } catch {} if (ENV.useOauth) { + if (!redirectURL) { + logger.error("Error parsing redirect URL: ", ENV.redirectURL) + } + registerOauth() } else { registerFakeAuth() From 319c41460a15c28fe299c1fb0d3284a076e6efcd Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Mon, 15 Dec 2025 20:52:15 +0100 Subject: [PATCH 190/190] reorder noauth router --- src/auth.js | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/auth.js b/src/auth.js index 633f689..6c01b76 100644 --- a/src/auth.js +++ b/src/auth.js @@ -213,19 +213,25 @@ function registerFakeAuth() { } } - const sessionID = uuidv4() + if ( + (redirectURL && req.hostname == redirectURL?.hostname) || + !redirectURL + ) { + const sessionID = uuidv4() - res.cookie("session_id", sessionID, { - httpOnly: true, - secure: true, - sameSite: "lax", - maxAge: 1000 * 60 * 60, - }) + res.cookie("session_id", sessionID, { + httpOnly: true, + secure: true, + sameSite: "lax", + maxAge: 1000 * 60 * 60, + }) - await WriteToCache( - `${redirectURL?.origin || ""}/service=${sessionID}`, - originalUrl - ) + await WriteToCache(`service=${sessionID}`, originalUrl) + } + + if (redirectURL && req.hostname !== redirectURL?.hostname) { + return res.redirect(`${redirectURL.origin}`) + } next() })