Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Shuttle.entitlements
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.automation.apple-events</key>
<true/>
<key>com.apple.security.temporary-exception.apple-events</key>
<array>
<string>com.apple.Terminal</string>
<string>com.googlecode.iterm2</string>
</array>
<key>com.apple.security.get-task-allow</key>
<true/>
</dict>
</plist>
26 changes: 19 additions & 7 deletions Shuttle.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objectVersion = 54;
objects = {

/* Begin PBXBuildFile section */
Expand Down Expand Up @@ -398,9 +398,13 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8;
MACOSX_DEPLOYMENT_TARGET = 10.15;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
ARCHS = "$(ARCHS_STANDARD)";
VALID_ARCHS = "arm64 x86_64";
SUPPORTS_MACCATALYST = NO;
EXCLUDED_ARCHS = "";
};
name = Debug;
};
Expand All @@ -409,7 +413,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
Expand All @@ -431,7 +435,7 @@
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_C_LANGUAGE_STANDARD = gnu17;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
Expand All @@ -440,8 +444,12 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8;
MACOSX_DEPLOYMENT_TARGET = 10.15;
SDKROOT = macosx;
ARCHS = "$(ARCHS_STANDARD)";
VALID_ARCHS = "arm64 x86_64";
SUPPORTS_MACCATALYST = NO;
EXCLUDED_ARCHS = "";
};
name = Release;
};
Expand All @@ -454,10 +462,12 @@
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.15;
PRODUCT_BUNDLE_IDENTIFIER = "shuttle.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
ARCHS = "$(ARCHS_STANDARD)";
VALID_ARCHS = "arm64 x86_64";
};
name = Debug;
};
Expand All @@ -470,10 +480,12 @@
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.15;
PRODUCT_BUNDLE_IDENTIFIER = "shuttle.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
ARCHS = "$(ARCHS_STANDARD)";
VALID_ARCHS = "arm64 x86_64";
};
name = Release;
};
Expand Down
58 changes: 42 additions & 16 deletions Shuttle/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
#import "AppDelegate.h"
#import "AboutWindowController.h"

// Add version detection macro for macOS compatibility
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[NSProcessInfo processInfo] operatingSystemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)

@implementation AppDelegate

- (void) awakeFromNib {
Expand Down Expand Up @@ -72,19 +75,9 @@ - (void) awakeFromNib {
[statusItem setMenu:menu];
[statusItem setImage: regularIcon];

// Check for AppKit Version, add support for darkmode if > 10.9
BOOL oldAppKitVersion = (floor(NSAppKitVersionNumber) <= 1265);

// 10.10 or higher, dont load the alt image let OS X style it.
if (!oldAppKitVersion)
{
regularIcon.template = YES;
}
// Load the alt image for OS X < 10.10
else{
[statusItem setHighlightMode:YES];
[statusItem setAlternateImage: altIcon];
}
// Modern macOS versions (10.10+) support dynamic icons
// Since we now require 10.15+, we can always use template images
regularIcon.template = YES;

launchAtLoginController = [[LaunchAtLoginController alloc] init];
// Needed to trigger the menuWillOpen event
Expand Down Expand Up @@ -563,11 +556,12 @@ - (void) openHost:(NSMenuItem *) sender {
else {
passParameters = @[escapedObject, terminalTitle];
}
// Check if Url
if (url)
// Modern macOS permission prompt: System will automatically prompt on first attempt

// Check if url is valid
if (url && [self isValidURL:escapedObject])
{
[[NSWorkspace sharedWorkspace] openURL:url];

}
//If the JSON file is set to use iTerm
else if ( [terminalPref rangeOfString: @"iterm"].location !=NSNotFound ) {
Expand Down Expand Up @@ -723,6 +717,38 @@ - (IBAction)showImportPanel:(id)sender {

}

// New: Simplified permission check - relies on system prompts
- (BOOL)checkAppleEventsPermission {
// In macOS 10.15+, system will automatically prompt permissions, return YES
return YES;
}

// New: Simplified permission request - provide user guidance
- (void)requestAppleEventsPermission {
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:@"Permission Required"];
[alert setInformativeText:@"Shuttle requires Accessibility permissions to control terminal applications. Please go to System Preferences → Security & Privacy → Accessibility, add and enable Shuttle."];
[alert addButtonWithTitle:@"Open System Preferences"];
[alert addButtonWithTitle:@"Later"];

if ([alert runModal] == NSAlertFirstButtonReturn) {
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"]];
}
}

// New: Enhanced URL validation
- (BOOL)isValidURL:(NSString *)string {
NSURL *url = [NSURL URLWithString:string];
if (!url) return NO;

NSString *scheme = [url scheme];
if (!scheme) return NO;

// Only allow standard protocols
NSArray *validSchemes = @[@"http", @"https", @"ftp", @"file", @"ssh", @"telnet"];
return [validSchemes containsObject:scheme.lowercaseString];
}

-(void) throwError:(NSString*)errorMessage additionalInfo:(NSString*)errorInfo continueOnErrorOption:(BOOL)continueOption {
NSAlert *alert = [[NSAlert alloc] init];
[alert setInformativeText:errorInfo];
Expand Down
4 changes: 3 additions & 1 deletion Shuttle/Shuttle-Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
<key>LSUIElement</key>
<true/>
<key>NSAppleEventsUsageDescription</key>
<string>Shuttle needs Automation privileges in Security &amp; Privacy to run applescripts</string>
<string>Shuttle needs Automation privileges to control Terminal.app and iTerm2 for SSH connections</string>
<key>NSAppleEventsUsageDescriptionAutomation</key>
<string>Shuttle uses AppleScript to open SSH connections in your preferred terminal application</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2016 Trevor Fitzgerald. All rights reserved.</string>
<key>NSMainNibFile</key>
Expand Down