From 8a1db9da371ef1a8528d4ccb919eb6872cde17ae Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Tue, 28 Jul 2026 01:49:21 +0800 Subject: [PATCH] fail the guacamole-lite patch when an anchor is gone (#1126) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each patch bails out with a console.log and process.exit(0) when its anchor string is missing. The write-back happens at the end of the file, so an upstream release that moves any one anchor drops every patch, exits successfully, and leaves postinstall reporting nothing wrong. Termix then builds and starts normally and drops VNC/RDP sessions at runtime — with no signal pointing at the patch. Every patch here is required for correctness: protocol negotiation, the guacd 1.6.0 name handshake, dynamic argument answering, UTF-8 tokens, read-only joins. A missing anchor means the patch no longer applies, so exit non-zero and say which one and what to do. Unchanged: a missing guacamole-lite still skips quietly, and an already-patched tree still exits 0. --- scripts/patch-guacamole-lite.cjs | 57 +++++++++++++------------------- 1 file changed, 23 insertions(+), 34 deletions(-) diff --git a/scripts/patch-guacamole-lite.cjs b/scripts/patch-guacamole-lite.cjs index b9a76efe..c3d37bce 100644 --- a/scripts/patch-guacamole-lite.cjs +++ b/scripts/patch-guacamole-lite.cjs @@ -35,6 +35,20 @@ if ( process.exit(0); } +// Every patch below is required for correctness: protocol negotiation, the +// guacd 1.6.0 name handshake, dynamic argument answering, UTF-8 tokens and +// read-only joins. If an upstream release moves an anchor string, silently +// skipping would ship a Termix that looks fine and then drops VNC/RDP sessions +// at runtime, so a missing anchor has to stop the install instead. +function missingAnchor(patch) { + console.error( + `[patch-guacamole-lite] ${patch} anchor not found in guacamole-lite. ` + + "The upstream file has changed and this patch no longer applies — " + + "update scripts/patch-guacamole-lite.cjs to match the new source.", + ); + process.exit(1); +} + let guacdClientContent = fs.readFileSync(guacdClientPath, "utf8"); let cryptContent = fs.readFileSync(cryptPath, "utf8"); let clientConnectionContent = fs.readFileSync(clientConnectionPath, "utf8"); @@ -157,18 +171,14 @@ if (!guacdClientContent.includes("} else if (/^1_\\d+_0$/.test(version)) {")) { newVersionBlock, ); } else { - console.log( - "[patch-guacamole-lite] Version check target not found, skipping", - ); - process.exit(0); + missingAnchor("Version check"); } patched = true; } if (!guacdClientContent.includes(newTimezone)) { if (!guacdClientContent.includes(oldTimezone)) { - console.log("[patch-guacamole-lite] Timezone target not found, skipping"); - process.exit(0); + missingAnchor("Timezone"); } guacdClientContent = guacdClientContent.replace(oldTimezone, newTimezone); patched = true; @@ -180,20 +190,14 @@ if (!guacdClientContent.includes(newConnect)) { } else if (guacdClientContent.includes(oldConnect)) { guacdClientContent = guacdClientContent.replace(oldConnect, newConnect); } else { - console.log( - "[patch-guacamole-lite] Connect target not found, skipping name patch", - ); - process.exit(0); + missingAnchor("Connect"); } patched = true; } if (!guacdClientContent.includes("this.nextArgumentStreamIndex = 0;")) { if (!guacdClientContent.includes(oldSendBuffer)) { - console.log( - "[patch-guacamole-lite] Argument stream index target not found, skipping", - ); - process.exit(0); + missingAnchor("Argument stream index"); } guacdClientContent = guacdClientContent.replace(oldSendBuffer, newSendBuffer); patched = true; @@ -201,10 +205,7 @@ if (!guacdClientContent.includes("this.nextArgumentStreamIndex = 0;")) { if (!guacdClientContent.includes("sendRequiredArguments(params) {")) { if (!guacdClientContent.includes(oldSendInstructionBlock)) { - console.log( - "[patch-guacamole-lite] Required argument helper target not found, skipping", - ); - process.exit(0); + missingAnchor("Required argument helper"); } guacdClientContent = guacdClientContent.replace( oldSendInstructionBlock, @@ -217,10 +218,7 @@ if ( !guacdClientContent.includes("opcode === 'required' || opcode === 'require'") ) { if (!guacdClientContent.includes(oldReadyHandler)) { - console.log( - "[patch-guacamole-lite] Required opcode target not found, skipping", - ); - process.exit(0); + missingAnchor("Required opcode"); } guacdClientContent = guacdClientContent.replace( oldReadyHandler, @@ -273,10 +271,7 @@ if (!cryptContent.includes(newDecryptBlock)) { newDecryptBlock, ); } else { - console.log( - "[patch-guacamole-lite] UTF-8 token decrypt target not found, skipping", - ); - process.exit(0); + missingAnchor("UTF-8 token decrypt"); } patched = true; } @@ -329,10 +324,7 @@ const newSendMessageToGuacd = if (!clientConnectionContent.includes("isReadOnlyJoin()")) { if (!clientConnectionContent.includes(oldSendMessageToGuacd)) { - console.log( - "[patch-guacamole-lite] sendMessageToGuacd target not found, skipping read-only patch", - ); - process.exit(0); + missingAnchor("sendMessageToGuacd"); } clientConnectionContent = clientConnectionContent.replace( oldSendMessageToGuacd, @@ -357,10 +349,7 @@ const newPreserveJoin = if (!clientConnectionContent.includes("compiledSettings.readOnly")) { if (!clientConnectionContent.includes(oldPreserveJoin)) { - console.log( - "[patch-guacamole-lite] join-preserve target not found, skipping readOnly propagation patch", - ); - process.exit(0); + missingAnchor("join-preserve"); } clientConnectionContent = clientConnectionContent.replace( oldPreserveJoin,