aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoopesh Chander <roop@roopc.net>2019-04-30 15:38:38 +0530
committerJason A. Donenfeld <Jason@zx2c4.com>2019-05-25 13:24:01 +0200
commitf852b6f91931fa545968ee38c4b43e1233a6ac43 (patch)
treeabfc7e701be7ac4c9433b5099b61f13d0e62a564
parentmacOS: Workaround for unresponsive main menu when launched from Xcode (diff)
downloadwireguard-apple-f852b6f91931fa545968ee38c4b43e1233a6ac43.tar.xz
wireguard-apple-f852b6f91931fa545968ee38c4b43e1233a6ac43.zip
iOS: Keep track of most-recently-activated tunnels
Signed-off-by: Roopesh Chander <roop@roopc.net>
-rw-r--r--WireGuard/WireGuard.xcodeproj/project.pbxproj4
-rw-r--r--WireGuard/WireGuard/Tunnel/TunnelsManager.swift19
-rw-r--r--WireGuard/WireGuard/UI/iOS/RecentTunnelsTracker.swift72
3 files changed, 94 insertions, 1 deletions
diff --git a/WireGuard/WireGuard.xcodeproj/project.pbxproj b/WireGuard/WireGuard.xcodeproj/project.pbxproj
index ead1556..d499929 100644
--- a/WireGuard/WireGuard.xcodeproj/project.pbxproj
+++ b/WireGuard/WireGuard.xcodeproj/project.pbxproj
@@ -54,6 +54,7 @@
6F19D30422402B8700A126F2 /* ConfirmationAlertPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F19D30322402B8700A126F2 /* ConfirmationAlertPresenter.swift */; };
6F2449E8226587B90047B9E9 /* MacAppStoreUpdateDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2449E7226587B80047B9E9 /* MacAppStoreUpdateDetector.swift */; };
6F3E02E9228000F6001FE7E3 /* MainMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F3E02E8228000F6001FE7E3 /* MainMenu.swift */; };
+ 6F29A9432278518D00DC6A6B /* RecentTunnelsTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F29A9422278518D00DC6A6B /* RecentTunnelsTracker.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 */; };
@@ -303,6 +304,7 @@
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>"; };
6F3E02E8228000F6001FE7E3 /* MainMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainMenu.swift; sourceTree = "<group>"; };
+ 6F29A9422278518D00DC6A6B /* RecentTunnelsTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentTunnelsTracker.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>"; };
@@ -568,6 +570,7 @@
6F919EC2218A2AE90023B400 /* ErrorPresenter.swift */,
6F19D30322402B8700A126F2 /* ConfirmationAlertPresenter.swift */,
5F45417C21C1B23600994C13 /* UITableViewCell+Reuse.swift */,
+ 6F29A9422278518D00DC6A6B /* RecentTunnelsTracker.swift */,
6FF4AC23211EC472002C96EB /* Info.plist */,
6FF4AC482120B9E0002C96EB /* WireGuard.entitlements */,
);
@@ -1395,6 +1398,7 @@
6F7774EA217229DB006A79B3 /* IPAddressRange.swift in Sources */,
6F7774E82172020C006A79B3 /* TunnelConfiguration.swift in Sources */,
6FDEF7FB21863B6100D8FBF6 /* unzip.c in Sources */,
+ 6F29A9432278518D00DC6A6B /* RecentTunnelsTracker.swift in Sources */,
6F6899A8218044FC0012E523 /* Curve25519.swift in Sources */,
6F0F44C9222D55BB00B0FF04 /* TextCell.swift in Sources */,
5F4541A021C2D6B700994C13 /* TunnelListCell.swift in Sources */,
diff --git a/WireGuard/WireGuard/Tunnel/TunnelsManager.swift b/WireGuard/WireGuard/Tunnel/TunnelsManager.swift
index edf7690..460a9f6 100644
--- a/WireGuard/WireGuard/Tunnel/TunnelsManager.swift
+++ b/WireGuard/WireGuard/Tunnel/TunnelsManager.swift
@@ -46,7 +46,11 @@ class TunnelsManager {
var tunnelManagers = managers ?? []
var refs: Set<Data> = []
+ var tunnelNames: Set<String> = []
for (index, tunnelManager) in tunnelManagers.enumerated().reversed() {
+ if let tunnelName = tunnelManager.localizedDescription {
+ tunnelNames.insert(tunnelName)
+ }
guard let proto = tunnelManager.protocolConfiguration as? NETunnelProviderProtocol else { continue }
if proto.migrateConfigurationIfNeeded(called: tunnelManager.localizedDescription ?? "unknown") {
tunnelManager.saveToPreferences { _ in }
@@ -66,6 +70,7 @@ class TunnelsManager {
}
}
Keychain.deleteReferences(except: refs)
+ RecentTunnelsTracker.cleanupTunnels(except: tunnelNames)
completionHandler(.success(TunnelsManager(tunnelProviders: tunnelManagers)))
}
#endif
@@ -188,7 +193,8 @@ class TunnelsManager {
}
let tunnelProviderManager = tunnel.tunnelProvider
- let isNameChanged = tunnelName != tunnelProviderManager.localizedDescription
+ let oldName = tunnelProviderManager.localizedDescription ?? ""
+ let isNameChanged = tunnelName != oldName
if isNameChanged {
guard !tunnels.contains(where: { $0.name == tunnelName }) else {
completionHandler(TunnelsManagerError.tunnelAlreadyExistsWithThatName)
@@ -220,6 +226,9 @@ class TunnelsManager {
self.tunnels.sort { TunnelsManager.tunnelNameIsLessThan($0.name, $1.name) }
let newIndex = self.tunnels.firstIndex(of: tunnel)!
self.tunnelsListDelegate?.tunnelMoved(from: oldIndex, to: newIndex)
+ #if os(iOS)
+ RecentTunnelsTracker.handleTunnelRenamed(oldName: oldName, newName: tunnelName)
+ #endif
}
self.tunnelsListDelegate?.tunnelModified(at: self.tunnels.firstIndex(of: tunnel)!)
@@ -266,6 +275,10 @@ class TunnelsManager {
self.tunnelsListDelegate?.tunnelRemoved(at: index, tunnel: tunnel)
}
completionHandler(nil)
+
+ #if os(iOS)
+ RecentTunnelsTracker.handleTunnelRemoved(tunnelName: tunnel.name)
+ #endif
}
}
@@ -343,6 +356,10 @@ class TunnelsManager {
#else
tunnel.startActivation(activationDelegate: activationDelegate)
#endif
+
+ #if os(iOS)
+ RecentTunnelsTracker.handleTunnelActivated(tunnelName: tunnel.name)
+ #endif
}
func startDeactivation(of tunnel: TunnelContainer) {
diff --git a/WireGuard/WireGuard/UI/iOS/RecentTunnelsTracker.swift b/WireGuard/WireGuard/UI/iOS/RecentTunnelsTracker.swift
new file mode 100644
index 0000000..787a624
--- /dev/null
+++ b/WireGuard/WireGuard/UI/iOS/RecentTunnelsTracker.swift
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: MIT
+// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
+
+import Foundation
+
+class RecentTunnelsTracker {
+
+ private static let keyRecentlyActivatedTunnelNames = "recentlyActivatedTunnelNames"
+ private static let maxNumberOfTunnels = 10
+
+ private static var userDefaults: UserDefaults? {
+ guard let appGroupId = FileManager.appGroupId else {
+ wg_log(.error, staticMessage: "Cannot obtain app group ID from bundle for tracking recently used tunnels")
+ return nil
+ }
+ guard let userDefaults = UserDefaults(suiteName: appGroupId) else {
+ wg_log(.error, staticMessage: "Cannot obtain shared user defaults for tracking recently used tunnels")
+ return nil
+ }
+ return userDefaults
+ }
+
+ static func handleTunnelActivated(tunnelName: String) {
+ guard let userDefaults = RecentTunnelsTracker.userDefaults else { return }
+ var recentTunnels = userDefaults.stringArray(forKey: keyRecentlyActivatedTunnelNames) ?? []
+ if let existingIndex = recentTunnels.firstIndex(of: tunnelName) {
+ recentTunnels.remove(at: existingIndex)
+ }
+ recentTunnels.insert(tunnelName, at: 0)
+ if recentTunnels.count > maxNumberOfTunnels {
+ recentTunnels.removeLast(recentTunnels.count - maxNumberOfTunnels)
+ }
+ userDefaults.set(recentTunnels, forKey: keyRecentlyActivatedTunnelNames)
+ }
+
+ static func handleTunnelRemoved(tunnelName: String) {
+ guard let userDefaults = RecentTunnelsTracker.userDefaults else { return }
+ var recentTunnels = userDefaults.stringArray(forKey: keyRecentlyActivatedTunnelNames) ?? []
+ if let existingIndex = recentTunnels.firstIndex(of: tunnelName) {
+ recentTunnels.remove(at: existingIndex)
+ userDefaults.set(recentTunnels, forKey: keyRecentlyActivatedTunnelNames)
+ }
+ }
+
+ static func handleTunnelRenamed(oldName: String, newName: String) {
+ guard let userDefaults = RecentTunnelsTracker.userDefaults else { return }
+ var recentTunnels = userDefaults.stringArray(forKey: keyRecentlyActivatedTunnelNames) ?? []
+ if let existingIndex = recentTunnels.firstIndex(of: oldName) {
+ recentTunnels[existingIndex] = newName
+ userDefaults.set(recentTunnels, forKey: keyRecentlyActivatedTunnelNames)
+ }
+ }
+
+ static func cleanupTunnels(except tunnelNamesToKeep: Set<String>) {
+ guard let userDefaults = RecentTunnelsTracker.userDefaults else { return }
+ var recentTunnels = userDefaults.stringArray(forKey: keyRecentlyActivatedTunnelNames) ?? []
+ let oldCount = recentTunnels.count
+ recentTunnels.removeAll { !tunnelNamesToKeep.contains($0) }
+ if oldCount != recentTunnels.count {
+ userDefaults.set(recentTunnels, forKey: keyRecentlyActivatedTunnelNames)
+ }
+ }
+
+ static func recentlyActivatedTunnelNames(limit: Int) -> [String] {
+ guard let userDefaults = RecentTunnelsTracker.userDefaults else { return [] }
+ var recentTunnels = userDefaults.stringArray(forKey: keyRecentlyActivatedTunnelNames) ?? []
+ if limit < recentTunnels.count {
+ recentTunnels.removeLast(recentTunnels.count - limit)
+ }
+ return recentTunnels
+ }
+}