]> git.ipfire.org Git - thirdparty/wireguard-apple.git/commitdiff
macOS: Detect when updating from the App Store
authorRoopesh Chander <roop@roopc.net>
Wed, 17 Apr 2019 08:05:43 +0000 (13:35 +0530)
committerRoopesh Chander <roop@roopc.net>
Sun, 21 Apr 2019 10:13:10 +0000 (15:43 +0530)
And show an alert when tunnels are active during updation -- that
might cause the update to not work correctly.

Signed-off-by: Roopesh Chander <roop@roopc.net>
WireGuard/WireGuard.xcodeproj/project.pbxproj
WireGuard/WireGuard/Base.lproj/Localizable.strings
WireGuard/WireGuard/UI/macOS/AppDelegate.swift
WireGuard/WireGuard/UI/macOS/MacAppStoreUpdateDetector.swift [new file with mode: 0644]
WireGuard/WireGuard/WireGuard-Bridging-Header.h

index 3177787019c9ecd0e57744df9be0c3332888006d..6631380ca4f4d9e1f663f38349a86cc0f0ddd822 100644 (file)
@@ -52,6 +52,7 @@
                6F0F44CB222D55FD00B0FF04 /* EditableTextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F0F44CA222D55FD00B0FF04 /* EditableTextCell.swift */; };
                6F1075642258AE9800D78929 /* DeleteTunnelsConfirmationAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F1075632258AE9800D78929 /* DeleteTunnelsConfirmationAlert.swift */; };
                6F19D30422402B8700A126F2 /* ConfirmationAlertPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F19D30322402B8700A126F2 /* ConfirmationAlertPresenter.swift */; };
+               6F2449E8226587B90047B9E9 /* MacAppStoreUpdateDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2449E7226587B80047B9E9 /* MacAppStoreUpdateDetector.swift */; };
                6F4DD16B21DA558800690EAE /* TunnelListRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F4DD16A21DA558800690EAE /* TunnelListRow.swift */; };
                6F4DD16C21DA558F00690EAE /* NSTableView+Reuse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F4DD16721DA552B00690EAE /* NSTableView+Reuse.swift */; };
                6F4DD16E21DBEA0700690EAE /* ManageTunnelsRootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F4DD16D21DBEA0700690EAE /* ManageTunnelsRootViewController.swift */; };
                6F0F44CA222D55FD00B0FF04 /* EditableTextCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditableTextCell.swift; sourceTree = "<group>"; };
                6F1075632258AE9800D78929 /* DeleteTunnelsConfirmationAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteTunnelsConfirmationAlert.swift; sourceTree = "<group>"; };
                6F19D30322402B8700A126F2 /* ConfirmationAlertPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationAlertPresenter.swift; sourceTree = "<group>"; };
+               6F2449E7226587B80047B9E9 /* MacAppStoreUpdateDetector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacAppStoreUpdateDetector.swift; sourceTree = "<group>"; };
                6F4DD16721DA552B00690EAE /* NSTableView+Reuse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSTableView+Reuse.swift"; sourceTree = "<group>"; };
                6F4DD16A21DA558800690EAE /* TunnelListRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelListRow.swift; sourceTree = "<group>"; };
                6F4DD16D21DBEA0700690EAE /* ManageTunnelsRootViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageTunnelsRootViewController.swift; sourceTree = "<group>"; };
                                6F89E17B21F090CC00C97BB9 /* TunnelsTracker.swift */,
                                6FBA104121D6BC210051C35F /* ErrorPresenter.swift */,
                                6FCD99AE21E0EA1700BA4C82 /* ImportPanelPresenter.swift */,
+                               6F2449E7226587B80047B9E9 /* MacAppStoreUpdateDetector.swift */,
                                6FB1BD6121D2607E00A991BF /* Assets.xcassets */,
                                6FB1BD6621D2607E00A991BF /* Info.plist */,
                                6FB1BD6721D2607E00A991BF /* WireGuard.entitlements */,
                                6FBA104321D6BC250051C35F /* ErrorPresenter.swift in Sources */,
                                6FB1BDC521D50F0300A991BF /* Endpoint.swift in Sources */,
                                6FB1BDC621D50F0300A991BF /* DNSServer.swift in Sources */,
+                               6F2449E8226587B90047B9E9 /* MacAppStoreUpdateDetector.swift in Sources */,
                                6FB1BDC721D50F0300A991BF /* InterfaceConfiguration.swift in Sources */,
                                6F907C9D224663A2003CED21 /* LogViewHelper.swift in Sources */,
                                6FB1BDC821D50F0300A991BF /* PeerConfiguration.swift in Sources */,
index 8600a6341f2ba0c806809cdd8b97bdb192423fde..9cfaef1898d44d98ec70c7111ee48f8000c2f550 100644 (file)
 "macUnusableTunnelMessage" = "The configuration for this tunnel cannot be found in the keychain.";
 "macUnusableTunnelInfo" = "In case this tunnel was created by another user, only that user can view, edit, or activate this tunnel.";
 "macUnusableTunnelButtonTitleDeleteTunnel" = "Delete tunnel";
+
+// Mac App Store updating alert
+
+"macAppStoreUpdatingAlertMessage" = "App Store would like to update WireGuard";
+"macAppStoreUpdatingAlertInfoWithOnDemand (%@)" = "Please disable on-demand for tunnel ‘%@’, deactivate it, and then continue updating in App Store.";
+"macAppStoreUpdatingAlertInfoWithoutOnDemand (%@)" = "Please deactivate tunnel ‘%@’ and then continue updating in App Store.";
index e80d97120aff3b95471904ee22cc5c54cf90bd5b..3e98c20d724864a6a009ac01db9b5d7b813d5a45 100644 (file)
@@ -68,6 +68,36 @@ class AppDelegate: NSObject, NSApplicationDelegate {
             NSApp.terminate(nil)
         }
     }
+
+    func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
+        if UserDefaults.standard.bool(forKey: "shouldSuppressAppStoreUpdateDetection") {
+            wg_log(.debug, staticMessage: "App Store update detection is suppressed")
+            return .terminateNow
+        }
+        guard let currentTunnel = tunnelsTracker?.currentTunnel, currentTunnel.status == .active || currentTunnel.status == .activating else {
+            return .terminateNow
+        }
+        guard let appleEvent = NSAppleEventManager.shared().currentAppleEvent else {
+            return .terminateNow
+        }
+        guard MacAppStoreUpdateDetector.isUpdatingFromMacAppStore(quitAppleEvent: appleEvent) else {
+            return .terminateNow
+        }
+        let alert = NSAlert()
+        alert.messageText = tr("macAppStoreUpdatingAlertMessage")
+        if currentTunnel.isActivateOnDemandEnabled {
+            alert.informativeText = tr(format: "macAppStoreUpdatingAlertInfoWithOnDemand (%@)", currentTunnel.name)
+        } else {
+            alert.informativeText = tr(format: "macAppStoreUpdatingAlertInfoWithoutOnDemand (%@)", currentTunnel.name)
+        }
+        NSApp.activate(ignoringOtherApps: true)
+        if let manageWindow = manageTunnelsWindowObject {
+            alert.beginSheetModal(for: manageWindow) { _ in }
+        } else {
+            alert.runModal()
+        }
+        return .terminateCancel
+    }
 }
 
 extension AppDelegate: StatusMenuWindowDelegate {
diff --git a/WireGuard/WireGuard/UI/macOS/MacAppStoreUpdateDetector.swift b/WireGuard/WireGuard/UI/macOS/MacAppStoreUpdateDetector.swift
new file mode 100644 (file)
index 0000000..7fbb011
--- /dev/null
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: MIT
+// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
+
+import Cocoa
+
+class MacAppStoreUpdateDetector {
+    static func isUpdatingFromMacAppStore(quitAppleEvent: NSAppleEventDescriptor) -> Bool {
+        guard isQuitEvent(quitAppleEvent) else { return false }
+        guard let senderPIDDescriptor = quitAppleEvent.attributeDescriptor(forKeyword: keySenderPIDAttr) else { return false }
+        let pid = senderPIDDescriptor.int32Value
+        guard let executablePath = getExecutablePath(from: pid) else { return false }
+        wg_log(.debug, message: "aevt/quit Apple event received from: \(executablePath)")
+        if executablePath.hasPrefix("/System/Library/") {
+            let executableName = URL(fileURLWithPath: executablePath, isDirectory: false).lastPathComponent
+            return executableName == "com.apple.CommerceKit.StoreAEService"
+        }
+        return false
+    }
+}
+
+private func isQuitEvent(_ event: NSAppleEventDescriptor) -> Bool {
+    if let eventClassDescriptor = event.attributeDescriptor(forKeyword: keyEventClassAttr),
+        let eventIdDescriptor = event.attributeDescriptor(forKeyword: keyEventIDAttr) {
+        return eventClassDescriptor.typeCodeValue == kCoreEventClass && eventIdDescriptor.typeCodeValue == kAEQuitApplication
+    }
+    return false
+}
+
+private func getExecutablePath(from pid: pid_t) -> String? {
+    let bufferSize = Int(PATH_MAX)
+    var buffer = Data(capacity: bufferSize)
+    return buffer.withUnsafeMutableBytes { (ptr: UnsafeMutableRawBufferPointer) -> String? in
+        if let basePtr = ptr.baseAddress {
+            let byteCount = proc_pidpath(pid, basePtr, UInt32(bufferSize))
+            return byteCount > 0 ? String(cString: basePtr.bindMemory(to: CChar.self, capacity: bufferSize)) : nil
+        }
+        return nil
+    }
+}
index 210b3df74747085d96f99c67db653d3f7f3a5574..81766ab4021a89f00d113ea5ae9f5a6ee521b55f 100644 (file)
@@ -5,3 +5,8 @@
 #include "ringlogger.h"
 #include "highlighter.h"
 #include "key.h"
+
+#import "TargetConditionals.h"
+#if TARGET_OS_OSX
+#include <libproc.h>
+#endif