Skip to content

Commit f9e17ba

Browse files
fix(split-tunnel): parse Exec= paths per XDG desktop entry spec (#5122) (#5136)
1 parent cb65e5b commit f9e17ba

3 files changed

Lines changed: 32 additions & 2 deletions

File tree

nym-vpn-app/src/screens/settings/split-tunneling/SplitTunneling.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { Spinner } from '../../../ui';
1212
import InfoDialog from './InfoDialog';
1313
import LaunchConfirmDialog from './LaunchConfirmDialog';
1414
import AppItem, { AppEntry } from './AppItem';
15-
import { useSplitTunnel } from './utils';
15+
import { parseExecArgs, useSplitTunnel } from './utils';
1616
import { PROBLEMATIC_APPS } from './utils/constants';
1717

1818
function SplitTunneling() {
@@ -35,7 +35,7 @@ function SplitTunneling() {
3535
try {
3636
const command = Command.create(
3737
'nym-exclude',
38-
app.executable_path.split(' '),
38+
parseExecArgs(app.executable_path),
3939
);
4040

4141
command.on('close', (data) => {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './useSplitTunnel';
2+
export * from './parseExec';
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* Parses a desktop entry Exec= value into an argument list suitable for
3+
* passing to Command.create().
4+
*
5+
* Per the XDG Desktop Entry Specification:
6+
* - If the executable path contains spaces it MUST be wrapped in double quotes
7+
* and spaces inside the quoted path MUST be escaped as \s.
8+
* - Arguments following the executable are separated by regular spaces.
9+
*
10+
* Examples:
11+
* '/usr/bin/firefox' → ['/usr/bin/firefox']
12+
* '/usr/bin/app --flag' → ['/usr/bin/app', '--flag']
13+
* '"/opt/My\sApp/app" --flag' → ['/opt/My App/app', '--flag']
14+
*/
15+
export function parseExecArgs(exec: string): string[] {
16+
const trimmed = exec.trim();
17+
18+
if (trimmed.startsWith('"')) {
19+
const closingQuote = trimmed.indexOf('"', 1);
20+
if (closingQuote !== -1) {
21+
const path = trimmed.slice(1, closingQuote).replace(/\\s/g, ' ');
22+
const rest = trimmed.slice(closingQuote + 1).trim();
23+
return [path, ...rest.split(' ').filter(Boolean)];
24+
}
25+
}
26+
27+
// Unquoted path: split on spaces as before
28+
return trimmed.split(' ').filter(Boolean);
29+
}

0 commit comments

Comments
 (0)