diff --git a/launcher/Launcher.qml b/launcher/Launcher.qml index a03c810..14f6a26 100644 --- a/launcher/Launcher.qml +++ b/launcher/Launcher.qml @@ -32,6 +32,14 @@ PanelWindow { property var allItems: [] property bool loading: false property bool proxyMode: false + property string proxyUrl: "" + + Component.onCompleted: readProxyUrl() + + function readProxyUrl() { + proxyUrlProc.command = ["cat", Cfg.Config.launcherCacheDir + "/proxy.conf"] + proxyUrlProc.running = true + } // When launcherSelectFirst is true the first result is pre-selected; // otherwise the list starts with no selection (-1). @@ -77,21 +85,92 @@ PanelWindow { function readCache() { const path = Cfg.Config.launcherCacheDir + "/" + (mode === "drun" ? "drun.txt" : "run.txt") dataProc.rawOutput = "" - dataProc.command = ["bash", "-c", "cat " + path] + dataProc.command = ["cat", path] dataProc.running = true } + function shellQuote(str) { + // POSIX single-quote escaping: wrap in ' and replace every ' with '\'' + return "'" + str.replace(/'/g, "'\\''") + "'" + } + + function parseExec(str) { + const args = [] + let current = "" + let inSingle = false + let inDouble = false + + for (let i = 0; i < str.length; i++) { + const ch = str[i] + + if (inSingle) { + if (ch === "'") inSingle = false + else current += ch + } else if (inDouble) { + if (ch === '"') inDouble = false + else current += ch + } else if (ch === "'") { + inSingle = true + } else if (ch === '"') { + inDouble = true + } else if (/\s/.test(ch)) { + if (current.length > 0) { + args.push(current) + current = "" + } + } else { + current += ch + } + } + if (current.length > 0) args.push(current) + return args + } + function launch(item) { if (!item || !item.exec) return - const cleanExec = item.exec.replace(/%[fFuUik]/g, "").trim() - const finalExec = root.proxyMode ? "proxychains4 " + cleanExec : cleanExec - const logPath = "/tmp/qml_launch.log" + let cleanExec = item.exec.replace(/%[fFuUik]/g, "").trim() + const logPath = "/tmp/qml_launch.log" - launchProc.command = ["sh", "-c", finalExec + " > " + logPath + " 2>&1 &"] + const lowerExec = cleanExec.toLowerCase() + const isBrowser = lowerExec.includes("chromium") || lowerExec.includes("chrome") || lowerExec.includes("firefox") + + let extraArgs = [] + let envVars = [] + let prefix = "" + let useProxyChains = false + + if (root.proxyMode) { + if (isBrowser && root.proxyUrl) { + // Browsers: use native proxy flags instead of proxychains4 + // to avoid LD_PRELOAD sandbox conflicts + if (lowerExec.includes("chromium") || lowerExec.includes("chrome")) { + extraArgs.push("--proxy-server=" + root.proxyUrl) + } + if (lowerExec.includes("firefox")) { + envVars.push("all_proxy=" + root.proxyUrl) + } + } else { + // Non-browsers: use proxychains4 normally + useProxyChains = true + } + } + + const envPrefix = envVars.length > 0 ? "env " + envVars.join(" ") + " " : "" + if (useProxyChains) { + prefix = envPrefix + "/usr/bin/proxychains4 " + } else { + prefix = envPrefix + } + + const args = parseExec(cleanExec) + const fullArgs = args.concat(extraArgs) + const cmd = prefix + fullArgs.map(a => shellQuote(a)).join(" ") + " > " + shellQuote(logPath) + " 2>&1 < /dev/null &" + + launchProc.command = ["sh", "-c", cmd] launchProc.running = true - console.log("Launching: " + finalExec) + console.log("Launching: " + prefix + cleanExec + (extraArgs.length ? " " + extraArgs.join(" ") : "")) if (typeof close === "function") close() } @@ -146,6 +225,17 @@ PanelWindow { Process { id: launchProc } + Process { + id: proxyUrlProc + property string rawOutput: "" + stdout: SplitParser { onRead: data => proxyUrlProc.rawOutput = data.trim() } + onRunningChanged: { + if (!running && rawOutput) { + root.proxyUrl = rawOutput + } + } + } + // Transparent overlay — captures clicks outside the bubble and closes the // launcher. Sits below clipContainer in stacking order (declared first), // so clicks inside the bubble still reach the bubble's own MouseAreas. diff --git a/launcher/launcher.sh b/launcher/launcher.sh index 504184d..084ae99 100755 --- a/launcher/launcher.sh +++ b/launcher/launcher.sh @@ -31,8 +31,7 @@ get_desktop_files() { exec=$( grep -m1 '^Exec=' "$f" \ | cut -d= -f2- \ - | sed 's/%[fFuUik]//g' \ - | xargs + | sed 's/%[fFuUik]//g' ) type=$( @@ -90,12 +89,31 @@ build_run() { } +extract_proxy() { + local conf="${PROXYCHAINS_CONF_FILE:-/etc/proxychains4.conf}" + [ -f "$conf" ] || conf="/etc/proxychains.conf" + [ -f "$conf" ] || return + + local line + line=$(awk '/^\[ProxyList\]/{found=1; next} found && NF && !/^#/{print; exit}' "$conf") + [ -n "$line" ] || return + + local ptype host port + ptype=$(echo "$line" | awk '{print $1}') + host=$(echo "$line" | awk '{print $2}') + port=$(echo "$line" | awk '{print $3}') + + echo "${ptype}://${host}:${port}" +} + update_cache() { build_drun > "$DRUN_CACHE.tmp" build_run > "$RUN_CACHE.tmp" mv "$DRUN_CACHE.tmp" "$DRUN_CACHE" mv "$RUN_CACHE.tmp" "$RUN_CACHE" + + extract_proxy > "$CACHE_DIR/proxy.conf" }