diff --git a/Shuttle.entitlements b/Shuttle.entitlements new file mode 100644 index 0000000..e7f7f62 --- /dev/null +++ b/Shuttle.entitlements @@ -0,0 +1,15 @@ + + + + + com.apple.security.automation.apple-events + + com.apple.security.temporary-exception.apple-events + + com.apple.Terminal + com.googlecode.iterm2 + + com.apple.security.get-task-allow + + + \ No newline at end of file diff --git a/Shuttle.xcodeproj/project.pbxproj b/Shuttle.xcodeproj/project.pbxproj index d174fef..3222d0e 100644 --- a/Shuttle.xcodeproj/project.pbxproj +++ b/Shuttle.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -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; }; @@ -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; @@ -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; @@ -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; }; @@ -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; }; @@ -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; }; diff --git a/Shuttle/AppDelegate.m b/Shuttle/AppDelegate.m index 2f77935..d71dfee 100644 --- a/Shuttle/AppDelegate.m +++ b/Shuttle/AppDelegate.m @@ -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 { @@ -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 @@ -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 ) { @@ -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]; diff --git a/Shuttle/Shuttle-Info.plist b/Shuttle/Shuttle-Info.plist index b760d03..dda7449 100644 --- a/Shuttle/Shuttle-Info.plist +++ b/Shuttle/Shuttle-Info.plist @@ -27,7 +27,9 @@ LSUIElement NSAppleEventsUsageDescription - Shuttle needs Automation privileges in Security & Privacy to run applescripts + Shuttle needs Automation privileges to control Terminal.app and iTerm2 for SSH connections + NSAppleEventsUsageDescriptionAutomation + Shuttle uses AppleScript to open SSH connections in your preferred terminal application NSHumanReadableCopyright Copyright © 2016 Trevor Fitzgerald. All rights reserved. NSMainNibFile