From 72f229df700207a838a8dee75d0b14f55bc64325 Mon Sep 17 00:00:00 2001 From: Sid Hill <12677016+ThatdBeSid@users.noreply.github.com> Date: Wed, 1 Jul 2026 11:25:38 -0700 Subject: [PATCH 1/2] Fix NSURL misdetection routing SSH commands to openURL Only treat command strings as URLs when they have an explicit http/https scheme, since NSURL's parser has become more lenient over time and was misrouting SSH commands to NSWorkspace openURL. Also logs AppleScript execution errors instead of discarding them. Bumps minimum deployment target from 10.9 to 10.13. --- Shuttle.xcodeproj/project.pbxproj | 5 +++-- Shuttle/AppDelegate.m | 11 +++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Shuttle.xcodeproj/project.pbxproj b/Shuttle.xcodeproj/project.pbxproj index d174fef..a79150c 100644 --- a/Shuttle.xcodeproj/project.pbxproj +++ b/Shuttle.xcodeproj/project.pbxproj @@ -234,6 +234,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, "zh-Hans", Base, @@ -454,7 +455,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Shuttle/Shuttle-Prefix.pch"; INFOPLIST_FILE = "Shuttle/Shuttle-Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_BUNDLE_IDENTIFIER = "shuttle.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; @@ -470,7 +471,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Shuttle/Shuttle-Prefix.pch"; INFOPLIST_FILE = "Shuttle/Shuttle-Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_BUNDLE_IDENTIFIER = "shuttle.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; diff --git a/Shuttle/AppDelegate.m b/Shuttle/AppDelegate.m index 2f77935..df641bd 100644 --- a/Shuttle/AppDelegate.m +++ b/Shuttle/AppDelegate.m @@ -558,7 +558,10 @@ - (void) openHost:(NSMenuItem *) sender { NSURL *url; if ( ![terminalWindow isEqualToString:@"virtual"] ) { passParameters = @[escapedObject, terminalTheme, terminalTitle]; - url = [NSURL URLWithString:escapedObject]; + NSURL *candidateURL = [NSURL URLWithString:escapedObject]; + if (candidateURL && ([candidateURL.scheme isEqualToString:@"http"] || [candidateURL.scheme isEqualToString:@"https"])) { + url = candidateURL; + } } else { passParameters = @[escapedObject, terminalTitle]; @@ -700,7 +703,11 @@ - (void) runScript:(NSString *)scriptPath handler:(NSString*)handlerName paramet [containerEvent setParamDescriptor:arguments forKeyword:keyDirectObject]; } //Execute the event - [appleScript executeAppleEvent:containerEvent error:nil]; + NSDictionary *executionError = nil; + [appleScript executeAppleEvent:containerEvent error:&executionError]; + if (executionError) { + NSLog(@"Shuttle AppleScript execution error for %@: %@", scriptPath, executionError); + } } } From cec5d003e2a960f52bbc167d865644be1c837824 Mon Sep 17 00:00:00 2001 From: Sid Hill <12677016+ThatdBeSid@users.noreply.github.com> Date: Thu, 30 Jul 2026 11:18:24 -0700 Subject: [PATCH 2/2] Use whitespace check instead of scheme allowlist for URL detection Restricting to http/https broke vnc:// and ssh:// entries, which legitimately need to go through -openURL: to reach Screen Sharing and the registered SSH handler. A URL never contains unescaped whitespace, so checking for that instead (plus requiring a non-empty scheme) correctly distinguishes shell commands from real URLs regardless of which schemes exist. Root cause credit and this fix approach: github.com/morri5, via PR comment. --- Shuttle/AppDelegate.m | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/Shuttle/AppDelegate.m b/Shuttle/AppDelegate.m index df641bd..d62063a 100644 --- a/Shuttle/AppDelegate.m +++ b/Shuttle/AppDelegate.m @@ -463,6 +463,22 @@ - (void) separatorSortRemoval:(NSString *)currentName { } } +// Determines whether a shuttle entry should be treated as a URL (e.g. vnc://, ssh://, +// http://) versus a shell command to run in Terminal/iTerm. A real URL never contains +// unescaped whitespace, so that's a more reliable signal than scheme alone: NSURL's +// parser has become considerably more lenient over time (and its exact behavior is +// gated on the SDK the binary is linked against), so plain shell commands like +// "ssh user@host" can now parse into a non-nil NSURL on current macOS/Xcode even +// though they never did in 2016. Checking for whitespace first avoids misrouting +// commands to -openURL: while still preserving legitimate scheme-based entries. +- (NSURL *) urlForEntry:(NSString *)entry { + if ([entry rangeOfCharacterFromSet:[NSCharacterSet whitespaceCharacterSet]].location != NSNotFound) { + return nil; + } + NSURL *url = [NSURL URLWithString:entry]; + return url.scheme.length ? url : nil; +} + - (void) openHost:(NSMenuItem *) sender { //NSLog(@"sender: %@", sender); //NSLog(@"Command: %@",[sender representedObject]); @@ -558,10 +574,7 @@ - (void) openHost:(NSMenuItem *) sender { NSURL *url; if ( ![terminalWindow isEqualToString:@"virtual"] ) { passParameters = @[escapedObject, terminalTheme, terminalTitle]; - NSURL *candidateURL = [NSURL URLWithString:escapedObject]; - if (candidateURL && ([candidateURL.scheme isEqualToString:@"http"] || [candidateURL.scheme isEqualToString:@"https"])) { - url = candidateURL; - } + url = [self urlForEntry:escapedObject]; } else { passParameters = @[escapedObject, terminalTitle];