WireGuardApp: use file to communicate launch-by-login-helper
Apple event params are broken on recent macOS versions. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
d882a486a9
commit
7171df84fa
|
@ -35,6 +35,10 @@ extension FileManager {
|
||||||
return sharedFolderURL?.appendingPathComponent("last-error.txt")
|
return sharedFolderURL?.appendingPathComponent("last-error.txt")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static var loginHelperTimestampURL: URL? {
|
||||||
|
return sharedFolderURL?.appendingPathComponent("login-helper-timestamp.bin")
|
||||||
|
}
|
||||||
|
|
||||||
static func deleteFile(at url: URL) -> Bool {
|
static func deleteFile(at url: URL) -> Bool {
|
||||||
do {
|
do {
|
||||||
try FileManager.default.removeItem(at: url)
|
try FileManager.default.removeItem(at: url)
|
||||||
|
|
|
@ -65,19 +65,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
@objc func confirmAndQuit() {
|
||||||
let alert = NSAlert()
|
let alert = NSAlert()
|
||||||
alert.messageText = tr("macConfirmAndQuitAlertMessage")
|
alert.messageText = tr("macConfirmAndQuitAlertMessage")
|
||||||
|
|
|
@ -4,25 +4,16 @@
|
||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class LaunchedAtLoginDetector {
|
class LaunchedAtLoginDetector {
|
||||||
static let launchCode = "LaunchedByWireGuardLoginItemHelper"
|
|
||||||
|
|
||||||
static func isLaunchedAtLogin(openAppleEvent: NSAppleEventDescriptor) -> Bool {
|
static func isLaunchedAtLogin(openAppleEvent: NSAppleEventDescriptor) -> Bool {
|
||||||
guard isOpenEvent(openAppleEvent) else { return false }
|
let now = clock_gettime_nsec_np(CLOCK_UPTIME_RAW)
|
||||||
guard let propData = openAppleEvent.paramDescriptor(forKeyword: keyAEPropData) else { return false }
|
guard openAppleEvent.eventClass == kCoreEventClass && openAppleEvent.eventID == kAEOpenApplication else { return false }
|
||||||
return propData.stringValue == launchCode
|
guard let url = FileManager.loginHelperTimestampURL else { return false }
|
||||||
}
|
guard let data = try? Data(contentsOf: url) else { return false }
|
||||||
|
_ = FileManager.deleteFile(at: url)
|
||||||
static func isReopenedByLoginItemHelper(reopenAppleEvent: NSAppleEventDescriptor) -> Bool {
|
guard data.count == 8 else { return false }
|
||||||
guard isReopenEvent(reopenAppleEvent) else { return false }
|
let then = data.withUnsafeBytes { ptr in
|
||||||
guard let propData = reopenAppleEvent.paramDescriptor(forKeyword: keyAEPropData) else { return false }
|
ptr.load(as: UInt64.self)
|
||||||
return propData.stringValue == launchCode
|
}
|
||||||
|
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
|
|
||||||
}
|
|
||||||
|
|
|
@ -32,5 +32,7 @@
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.wireguard.macos.app_id</key>
|
<key>com.wireguard.macos.app_id</key>
|
||||||
<string>$(APP_ID_MACOS)</string>
|
<string>$(APP_ID_MACOS)</string>
|
||||||
|
<key>com.wireguard.macos.app_group_id</key>
|
||||||
|
<string>$(DEVELOPMENT_TEAM).group.$(APP_ID_MACOS)</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -4,5 +4,9 @@
|
||||||
<dict>
|
<dict>
|
||||||
<key>com.apple.security.app-sandbox</key>
|
<key>com.apple.security.app-sandbox</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>com.apple.security.application-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>$(DEVELOPMENT_TEAM).group.$(APP_ID_MACOS)</string>
|
||||||
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -5,13 +5,32 @@
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
NSString *appIdInfoDictionaryKey = @"com.wireguard.macos.app_id";
|
NSString *appId = [NSBundle.mainBundle objectForInfoDictionaryKey:@"com.wireguard.macos.app_id"];
|
||||||
NSString *appId = [NSBundle.mainBundle objectForInfoDictionaryKey:appIdInfoDictionaryKey];
|
NSString *appGroupId = [NSBundle.mainBundle objectForInfoDictionaryKey:@"com.wireguard.macos.app_group_id"];
|
||||||
|
if (!appId || !appGroupId)
|
||||||
NSString *launchCode = @"LaunchedByWireGuardLoginItemHelper";
|
return 1;
|
||||||
NSAppleEventDescriptor *paramDescriptor = [NSAppleEventDescriptor descriptorWithString:launchCode];
|
NSURL *containerUrl = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:appGroupId];
|
||||||
|
if (!containerUrl)
|
||||||
[NSWorkspace.sharedWorkspace launchAppWithBundleIdentifier:appId options:NSWorkspaceLaunchWithoutActivation
|
return 2;
|
||||||
additionalEventParamDescriptor:paramDescriptor launchIdentifier:NULL];
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue