Apple event params are broken on recent macOS versions.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
return sharedFolderURL?.appendingPathComponent("last-error.txt")
}
+ static var loginHelperTimestampURL: URL? {
+ return sharedFolderURL?.appendingPathComponent("login-helper-timestamp.bin")
+ }
+
static func deleteFile(at url: URL) -> Bool {
do {
try FileManager.default.removeItem(at: url)
}
}
- func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows: Bool) -> Bool {
- if let appleEvent = NSAppleEventManager.shared().currentAppleEvent {
- if LaunchedAtLoginDetector.isReopenedByLoginItemHelper(reopenAppleEvent: appleEvent) {
- return false
- }
- }
- if hasVisibleWindows {
- return true
- }
- showManageTunnelsWindow(completion: nil)
- return false
- }
-
@objc func confirmAndQuit() {
let alert = NSAlert()
alert.messageText = tr("macConfirmAndQuitAlertMessage")
import Cocoa
class LaunchedAtLoginDetector {
- static let launchCode = "LaunchedByWireGuardLoginItemHelper"
-
static func isLaunchedAtLogin(openAppleEvent: NSAppleEventDescriptor) -> Bool {
- guard isOpenEvent(openAppleEvent) else { return false }
- guard let propData = openAppleEvent.paramDescriptor(forKeyword: keyAEPropData) else { return false }
- return propData.stringValue == launchCode
- }
-
- static func isReopenedByLoginItemHelper(reopenAppleEvent: NSAppleEventDescriptor) -> Bool {
- guard isReopenEvent(reopenAppleEvent) else { return false }
- guard let propData = reopenAppleEvent.paramDescriptor(forKeyword: keyAEPropData) else { return false }
- return propData.stringValue == launchCode
+ let now = clock_gettime_nsec_np(CLOCK_UPTIME_RAW)
+ guard openAppleEvent.eventClass == kCoreEventClass && openAppleEvent.eventID == kAEOpenApplication else { return false }
+ guard let url = FileManager.loginHelperTimestampURL else { return false }
+ guard let data = try? Data(contentsOf: url) else { return false }
+ _ = FileManager.deleteFile(at: url)
+ guard data.count == 8 else { return false }
+ let then = data.withUnsafeBytes { ptr in
+ ptr.load(as: UInt64.self)
+ }
+ return now - then <= 5000000000
}
}
-
-private func isOpenEvent(_ event: NSAppleEventDescriptor) -> Bool {
- return event.eventClass == kCoreEventClass && event.eventID == kAEOpenApplication
-}
-
-private func isReopenEvent(_ event: NSAppleEventDescriptor) -> Bool {
- return event.eventClass == kCoreEventClass && event.eventID == kAEReopenApplication
-}
<true/>
<key>com.wireguard.macos.app_id</key>
<string>$(APP_ID_MACOS)</string>
+ <key>com.wireguard.macos.app_group_id</key>
+ <string>$(DEVELOPMENT_TEAM).group.$(APP_ID_MACOS)</string>
</dict>
</plist>
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
+ <key>com.apple.security.application-groups</key>
+ <array>
+ <string>$(DEVELOPMENT_TEAM).group.$(APP_ID_MACOS)</string>
+ </array>
</dict>
</plist>
int main(int argc, char *argv[])
{
- NSString *appIdInfoDictionaryKey = @"com.wireguard.macos.app_id";
- NSString *appId = [NSBundle.mainBundle objectForInfoDictionaryKey:appIdInfoDictionaryKey];
-
- NSString *launchCode = @"LaunchedByWireGuardLoginItemHelper";
- NSAppleEventDescriptor *paramDescriptor = [NSAppleEventDescriptor descriptorWithString:launchCode];
-
- [NSWorkspace.sharedWorkspace launchAppWithBundleIdentifier:appId options:NSWorkspaceLaunchWithoutActivation
- additionalEventParamDescriptor:paramDescriptor launchIdentifier:NULL];
+ NSString *appId = [NSBundle.mainBundle objectForInfoDictionaryKey:@"com.wireguard.macos.app_id"];
+ NSString *appGroupId = [NSBundle.mainBundle objectForInfoDictionaryKey:@"com.wireguard.macos.app_group_id"];
+ if (!appId || !appGroupId)
+ return 1;
+ NSURL *containerUrl = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:appGroupId];
+ if (!containerUrl)
+ return 2;
+ uint64_t now = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
+ if (![[NSData dataWithBytes:&now length:sizeof(now)] writeToURL:[containerUrl URLByAppendingPathComponent:@"login-helper-timestamp.bin"] atomically:YES])
+ return 3;
+ if (@available(macOS 10.15, *)) {
+ NSCondition *condition = [[NSCondition alloc] init];
+ NSURL *appURL = [NSWorkspace.sharedWorkspace URLForApplicationWithBundleIdentifier:appId];
+ if (!appURL)
+ return 4;
+ NSWorkspaceOpenConfiguration *openConfiguration = [NSWorkspaceOpenConfiguration configuration];
+ openConfiguration.activates = NO;
+ openConfiguration.addsToRecentItems = NO;
+ openConfiguration.hides = YES;
+ [NSWorkspace.sharedWorkspace openApplicationAtURL:appURL configuration:openConfiguration completionHandler:^(NSRunningApplication * _Nullable app, NSError * _Nullable error) {
+ [condition signal];
+ }];
+ [condition wait];
+ } else {
+ [NSWorkspace.sharedWorkspace launchAppWithBundleIdentifier:appId options:NSWorkspaceLaunchWithoutActivation
+ additionalEventParamDescriptor:NULL launchIdentifier:NULL];
+ }
return 0;
}