Keychain: store configurations in keychain instead of providerConfig
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
a26d620f11
commit
8c3557a907
|
@ -5,7 +5,7 @@ import Foundation
|
||||||
import os.log
|
import os.log
|
||||||
|
|
||||||
extension FileManager {
|
extension FileManager {
|
||||||
private static var sharedFolderURL: URL? {
|
static var appGroupId: String? {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
let appGroupIdInfoDictionaryKey = "com.wireguard.ios.app_group_id"
|
let appGroupIdInfoDictionaryKey = "com.wireguard.ios.app_group_id"
|
||||||
#elseif os(macOS)
|
#elseif os(macOS)
|
||||||
|
@ -13,7 +13,10 @@ extension FileManager {
|
||||||
#else
|
#else
|
||||||
#error("Unimplemented")
|
#error("Unimplemented")
|
||||||
#endif
|
#endif
|
||||||
guard let appGroupId = Bundle.main.object(forInfoDictionaryKey: appGroupIdInfoDictionaryKey) as? String else {
|
return Bundle.main.object(forInfoDictionaryKey: appGroupIdInfoDictionaryKey) as? String
|
||||||
|
}
|
||||||
|
private static var sharedFolderURL: URL? {
|
||||||
|
guard let appGroupId = FileManager.appGroupId else {
|
||||||
os_log("Cannot obtain app group ID from bundle", log: OSLog.default, type: .error)
|
os_log("Cannot obtain app group ID from bundle", log: OSLog.default, type: .error)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Security
|
||||||
|
|
||||||
|
class Keychain {
|
||||||
|
static func openReference(called ref: Data) -> String? {
|
||||||
|
var result: CFTypeRef?
|
||||||
|
let ret = SecItemCopyMatching([kSecClass as String: kSecClassGenericPassword,
|
||||||
|
kSecValuePersistentRef as String: ref,
|
||||||
|
kSecReturnData as String: true] as CFDictionary,
|
||||||
|
&result)
|
||||||
|
if ret != errSecSuccess || result == nil {
|
||||||
|
wg_log(.error, message: "Unable to open config from keychain: \(ret)")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
guard let data = result as? Data else { return nil }
|
||||||
|
return String(data: data, encoding: String.Encoding.utf8)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func makeReference(containing value: String, called name: String, previouslyReferencedBy oldRef: Data? = nil) -> Data? {
|
||||||
|
var ret: OSStatus
|
||||||
|
guard var id = Bundle.main.bundleIdentifier else {
|
||||||
|
wg_log(.error, staticMessage: "Unable to determine bundle identifier")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if id.hasSuffix(".network-extension") {
|
||||||
|
id.removeLast(".network-extension".count)
|
||||||
|
}
|
||||||
|
var items: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
|
||||||
|
kSecAttrLabel as String: "WireGuard Tunnel: " + name,
|
||||||
|
kSecAttrAccount as String: name + ": " + UUID().uuidString,
|
||||||
|
kSecAttrDescription as String: "wg-quick(8) config",
|
||||||
|
kSecAttrService as String: id,
|
||||||
|
kSecValueData as String: value.data(using: .utf8) as Any,
|
||||||
|
kSecReturnPersistentRef as String: true]
|
||||||
|
|
||||||
|
#if os(iOS)
|
||||||
|
items[kSecAttrAccessGroup as String] = FileManager.appGroupId
|
||||||
|
items[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock
|
||||||
|
#elseif os(macOS)
|
||||||
|
items[kSecAttrSynchronizable as String] = false
|
||||||
|
items[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
|
||||||
|
|
||||||
|
guard let extensionPath = Bundle.main.builtInPlugInsURL?.appendingPathComponent("WireGuardNetworkExtension.appex").path else {
|
||||||
|
wg_log(.error, staticMessage: "Unable to determine app extension path")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var extensionApp: SecTrustedApplication?
|
||||||
|
var mainApp: SecTrustedApplication?
|
||||||
|
ret = SecTrustedApplicationCreateFromPath(extensionPath, &extensionApp)
|
||||||
|
if ret != kOSReturnSuccess || extensionApp == nil {
|
||||||
|
wg_log(.error, message: "Unable to create keychain extension trusted application object: \(ret)")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ret = SecTrustedApplicationCreateFromPath(nil, &mainApp)
|
||||||
|
if ret != errSecSuccess || mainApp == nil {
|
||||||
|
wg_log(.error, message: "Unable to create keychain local trusted application object: \(ret)")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var access: SecAccess?
|
||||||
|
ret = SecAccessCreate((items[kSecAttrLabel as String] as? String)! as CFString,
|
||||||
|
[extensionApp!, mainApp!] as CFArray,
|
||||||
|
&access)
|
||||||
|
if ret != errSecSuccess || access == nil {
|
||||||
|
wg_log(.error, message: "Unable to create keychain ACL object: \(ret)")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
items[kSecAttrAccess as String] = access!
|
||||||
|
#else
|
||||||
|
#error("Unimplemented")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
var ref: CFTypeRef?
|
||||||
|
ret = SecItemAdd(items as CFDictionary, &ref)
|
||||||
|
if ret != errSecSuccess || ref == nil {
|
||||||
|
wg_log(.error, message: "Unable to add config to keychain: \(ret)")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if let oldRef = oldRef {
|
||||||
|
deleteReference(called: oldRef)
|
||||||
|
}
|
||||||
|
return ref as? Data
|
||||||
|
}
|
||||||
|
|
||||||
|
static func deleteReference(called ref: Data) {
|
||||||
|
let ret = SecItemDelete([kSecValuePersistentRef as String: ref] as CFDictionary)
|
||||||
|
if ret != errSecSuccess {
|
||||||
|
wg_log(.error, message: "Unable to delete config from keychain: \(ret)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func deleteReferences(except whitelist: Set<Data>) {
|
||||||
|
var result: CFTypeRef?
|
||||||
|
let ret = SecItemCopyMatching([kSecClass as String: kSecClassGenericPassword,
|
||||||
|
kSecAttrService as String: Bundle.main.bundleIdentifier as Any,
|
||||||
|
kSecMatchLimit as String: kSecMatchLimitAll,
|
||||||
|
kSecReturnPersistentRef as String: true] as CFDictionary,
|
||||||
|
&result)
|
||||||
|
if ret != errSecSuccess || result == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard let items = result as? [Data] else { return }
|
||||||
|
for item in items {
|
||||||
|
if !whitelist.contains(item) {
|
||||||
|
deleteReference(called: item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func verifyReference(called ref: Data) -> Bool {
|
||||||
|
return SecItemCopyMatching([kSecClass as String: kSecClassGenericPassword,
|
||||||
|
kSecValuePersistentRef as String: ref] as CFDictionary,
|
||||||
|
nil) == errSecSuccess
|
||||||
|
}
|
||||||
|
}
|
|
@ -174,20 +174,32 @@ final class LegacyTunnelConfiguration: LegacyModel {
|
||||||
extension NETunnelProviderProtocol {
|
extension NETunnelProviderProtocol {
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
func migrateConfigurationIfNeeded() -> Bool {
|
func migrateConfigurationIfNeeded(called name: String) -> Bool {
|
||||||
guard let configurationVersion = providerConfiguration?["tunnelConfigurationVersion"] as? Int else { return false }
|
var ret = false
|
||||||
if configurationVersion == 1 {
|
if migrateFromConfigurationV1() {
|
||||||
migrateFromConfigurationV1()
|
ret = true
|
||||||
} else {
|
|
||||||
fatalError("No migration from configuration version \(configurationVersion) exists.")
|
|
||||||
}
|
}
|
||||||
|
if migrateFromConfigurationV2(called: name) {
|
||||||
|
ret = true
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
private func migrateFromConfigurationV1() -> Bool {
|
||||||
|
guard let configurationVersion = providerConfiguration?["tunnelConfigurationVersion"] as? Int else { return false }
|
||||||
|
guard configurationVersion == 1 else { return false }
|
||||||
|
guard let serializedTunnelConfiguration = providerConfiguration?["tunnelConfiguration"] as? Data else { return false }
|
||||||
|
guard let configuration = try? JSONDecoder().decode(LegacyTunnelConfiguration.self, from: serializedTunnelConfiguration) else { return false }
|
||||||
|
providerConfiguration = ["WgQuickConfig": configuration.migrated.asWgQuickConfig()]
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private func migrateFromConfigurationV1() {
|
private func migrateFromConfigurationV2(called name: String) -> Bool {
|
||||||
guard let serializedTunnelConfiguration = providerConfiguration?["tunnelConfiguration"] as? Data else { return }
|
guard let oldConfig = providerConfiguration?["WgQuickConfig"] as? String else { return false }
|
||||||
guard let configuration = try? JSONDecoder().decode(LegacyTunnelConfiguration.self, from: serializedTunnelConfiguration) else { return }
|
providerConfiguration = nil
|
||||||
providerConfiguration = [Keys.wgQuickConfig.rawValue: configuration.migrated.asWgQuickConfig()]
|
guard passwordReference == nil else { return true }
|
||||||
|
passwordReference = Keychain.makeReference(containing: oldConfig, called: name)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,17 +12,16 @@ enum PacketTunnelProviderError: String, Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NETunnelProviderProtocol {
|
extension NETunnelProviderProtocol {
|
||||||
|
convenience init?(tunnelConfiguration: TunnelConfiguration, previouslyFrom old: NEVPNProtocol? = nil) {
|
||||||
enum Keys: String {
|
|
||||||
case wgQuickConfig = "WgQuickConfig"
|
|
||||||
}
|
|
||||||
|
|
||||||
convenience init?(tunnelConfiguration: TunnelConfiguration) {
|
|
||||||
self.init()
|
self.init()
|
||||||
|
|
||||||
let appId = Bundle.main.bundleIdentifier!
|
guard let name = tunnelConfiguration.name else { return nil }
|
||||||
|
guard let appId = Bundle.main.bundleIdentifier else { return nil }
|
||||||
providerBundleIdentifier = "\(appId).network-extension"
|
providerBundleIdentifier = "\(appId).network-extension"
|
||||||
providerConfiguration = [Keys.wgQuickConfig.rawValue: tunnelConfiguration.asWgQuickConfig()]
|
passwordReference = Keychain.makeReference(containing: tunnelConfiguration.asWgQuickConfig(), called: name, previouslyReferencedBy: old?.passwordReference)
|
||||||
|
if passwordReference == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
let endpoints = tunnelConfiguration.peers.compactMap { $0.endpoint }
|
let endpoints = tunnelConfiguration.peers.compactMap { $0.endpoint }
|
||||||
if endpoints.count == 1 {
|
if endpoints.count == 1 {
|
||||||
|
@ -35,9 +34,26 @@ extension NETunnelProviderProtocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
func asTunnelConfiguration(called name: String? = nil) -> TunnelConfiguration? {
|
func asTunnelConfiguration(called name: String? = nil) -> TunnelConfiguration? {
|
||||||
migrateConfigurationIfNeeded()
|
migrateConfigurationIfNeeded(called: name ?? "unknown")
|
||||||
guard let serializedConfig = providerConfiguration?[Keys.wgQuickConfig.rawValue] as? String else { return nil }
|
//TODO: in the case where migrateConfigurationIfNeeded is called by the network extension,
|
||||||
return try? TunnelConfiguration(fromWgQuickConfig: serializedConfig, called: name)
|
// before the app has started, and when there is, in fact, configuration that needs to be
|
||||||
|
// put into the keychain, this will generate one new keychain item every time it is started,
|
||||||
|
// until finally the app is open. Would it be possible to call saveToPreferences here? Or is
|
||||||
|
// that generally not available to network extensions? In which case, what should our
|
||||||
|
// behavior be?
|
||||||
|
|
||||||
|
guard let passwordReference = passwordReference else { return nil }
|
||||||
|
guard let config = Keychain.openReference(called: passwordReference) else { return nil }
|
||||||
|
return try? TunnelConfiguration(fromWgQuickConfig: config, called: name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func destroyConfigurationReference() {
|
||||||
|
guard let ref = passwordReference else { return }
|
||||||
|
Keychain.deleteReference(called: ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyConfigurationReference() -> Data? {
|
||||||
|
guard let ref = passwordReference else { return nil }
|
||||||
|
return Keychain.verifyReference(called: ref) ? ref : nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,10 @@
|
||||||
5FF7B96321CC95DE00A7DD74 /* InterfaceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF7B96121CC95DE00A7DD74 /* InterfaceConfiguration.swift */; };
|
5FF7B96321CC95DE00A7DD74 /* InterfaceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF7B96121CC95DE00A7DD74 /* InterfaceConfiguration.swift */; };
|
||||||
5FF7B96521CC95FA00A7DD74 /* PeerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */; };
|
5FF7B96521CC95FA00A7DD74 /* PeerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */; };
|
||||||
5FF7B96621CC95FA00A7DD74 /* PeerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */; };
|
5FF7B96621CC95FA00A7DD74 /* PeerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */; };
|
||||||
|
6B5C5E27220A48D30024272E /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5C5E26220A48D30024272E /* Keychain.swift */; };
|
||||||
|
6B5C5E28220A48D30024272E /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5C5E26220A48D30024272E /* Keychain.swift */; };
|
||||||
|
6B5C5E29220A48D30024272E /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5C5E26220A48D30024272E /* Keychain.swift */; };
|
||||||
|
6B5C5E2A220A48D30024272E /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5C5E26220A48D30024272E /* Keychain.swift */; };
|
||||||
6B707D8421F918D4000A8F73 /* TunnelConfiguration+UapiConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B707D8321F918D4000A8F73 /* TunnelConfiguration+UapiConfig.swift */; };
|
6B707D8421F918D4000A8F73 /* TunnelConfiguration+UapiConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B707D8321F918D4000A8F73 /* TunnelConfiguration+UapiConfig.swift */; };
|
||||||
6B707D8621F918D4000A8F73 /* TunnelConfiguration+UapiConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B707D8321F918D4000A8F73 /* TunnelConfiguration+UapiConfig.swift */; };
|
6B707D8621F918D4000A8F73 /* TunnelConfiguration+UapiConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B707D8321F918D4000A8F73 /* TunnelConfiguration+UapiConfig.swift */; };
|
||||||
6F4DD16B21DA558800690EAE /* TunnelListRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F4DD16A21DA558800690EAE /* TunnelListRow.swift */; };
|
6F4DD16B21DA558800690EAE /* TunnelListRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F4DD16A21DA558800690EAE /* TunnelListRow.swift */; };
|
||||||
|
@ -238,6 +242,7 @@
|
||||||
5F9696AF21CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TunnelConfiguration+WgQuickConfig.swift"; sourceTree = "<group>"; };
|
5F9696AF21CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TunnelConfiguration+WgQuickConfig.swift"; sourceTree = "<group>"; };
|
||||||
5FF7B96121CC95DE00A7DD74 /* InterfaceConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterfaceConfiguration.swift; sourceTree = "<group>"; };
|
5FF7B96121CC95DE00A7DD74 /* InterfaceConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterfaceConfiguration.swift; sourceTree = "<group>"; };
|
||||||
5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeerConfiguration.swift; sourceTree = "<group>"; };
|
5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeerConfiguration.swift; sourceTree = "<group>"; };
|
||||||
|
6B5C5E26220A48D30024272E /* Keychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keychain.swift; sourceTree = "<group>"; };
|
||||||
6B707D8321F918D4000A8F73 /* TunnelConfiguration+UapiConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TunnelConfiguration+UapiConfig.swift"; sourceTree = "<group>"; };
|
6B707D8321F918D4000A8F73 /* TunnelConfiguration+UapiConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TunnelConfiguration+UapiConfig.swift"; sourceTree = "<group>"; };
|
||||||
6F4DD16721DA552B00690EAE /* NSTableView+Reuse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSTableView+Reuse.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>"; };
|
6F4DD16A21DA558800690EAE /* TunnelListRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelListRow.swift; sourceTree = "<group>"; };
|
||||||
|
@ -427,6 +432,7 @@
|
||||||
6FF3526A21C23F720008484E /* Logging */,
|
6FF3526A21C23F720008484E /* Logging */,
|
||||||
6F7774E6217201E0006A79B3 /* Model */,
|
6F7774E6217201E0006A79B3 /* Model */,
|
||||||
6F5A2B4421AFDE020081EDD8 /* FileManager+Extension.swift */,
|
6F5A2B4421AFDE020081EDD8 /* FileManager+Extension.swift */,
|
||||||
|
6B5C5E26220A48D30024272E /* Keychain.swift */,
|
||||||
);
|
);
|
||||||
path = Shared;
|
path = Shared;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -1075,6 +1081,7 @@
|
||||||
6F5A2B4621AFDED40081EDD8 /* FileManager+Extension.swift in Sources */,
|
6F5A2B4621AFDED40081EDD8 /* FileManager+Extension.swift in Sources */,
|
||||||
6FFA5DA021958ECC0001E2F7 /* ErrorNotifier.swift in Sources */,
|
6FFA5DA021958ECC0001E2F7 /* ErrorNotifier.swift in Sources */,
|
||||||
5F9696B121CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift in Sources */,
|
5F9696B121CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift in Sources */,
|
||||||
|
6B5C5E28220A48D30024272E /* Keychain.swift in Sources */,
|
||||||
6FFA5D96219446380001E2F7 /* NETunnelProviderProtocol+Extension.swift in Sources */,
|
6FFA5D96219446380001E2F7 /* NETunnelProviderProtocol+Extension.swift in Sources */,
|
||||||
6FFA5D8E2194370D0001E2F7 /* TunnelConfiguration.swift in Sources */,
|
6FFA5D8E2194370D0001E2F7 /* TunnelConfiguration.swift in Sources */,
|
||||||
5FF7B96621CC95FA00A7DD74 /* PeerConfiguration.swift in Sources */,
|
5FF7B96621CC95FA00A7DD74 /* PeerConfiguration.swift in Sources */,
|
||||||
|
@ -1105,6 +1112,7 @@
|
||||||
6FB1BDD321D50F5300A991BF /* ZipArchive.swift in Sources */,
|
6FB1BDD321D50F5300A991BF /* ZipArchive.swift in Sources */,
|
||||||
6FB1BDD421D50F5300A991BF /* ioapi.c in Sources */,
|
6FB1BDD421D50F5300A991BF /* ioapi.c in Sources */,
|
||||||
6FDB3C3C21DCF6BB00A0C0BF /* TunnelViewModel.swift in Sources */,
|
6FDB3C3C21DCF6BB00A0C0BF /* TunnelViewModel.swift in Sources */,
|
||||||
|
6B5C5E29220A48D30024272E /* Keychain.swift in Sources */,
|
||||||
6FCD99AF21E0EA1700BA4C82 /* ImportPanelPresenter.swift in Sources */,
|
6FCD99AF21E0EA1700BA4C82 /* ImportPanelPresenter.swift in Sources */,
|
||||||
6FB1BDD521D50F5300A991BF /* unzip.c in Sources */,
|
6FB1BDD521D50F5300A991BF /* unzip.c in Sources */,
|
||||||
6FB1BDD621D50F5300A991BF /* zip.c in Sources */,
|
6FB1BDD621D50F5300A991BF /* zip.c in Sources */,
|
||||||
|
@ -1162,6 +1170,7 @@
|
||||||
6FB1BDB221D4F55700A991BF /* DNSResolver.swift in Sources */,
|
6FB1BDB221D4F55700A991BF /* DNSResolver.swift in Sources */,
|
||||||
6FB1BDB321D4F55700A991BF /* ErrorNotifier.swift in Sources */,
|
6FB1BDB321D4F55700A991BF /* ErrorNotifier.swift in Sources */,
|
||||||
6FB1BDA221D4F53300A991BF /* ringlogger.c in Sources */,
|
6FB1BDA221D4F53300A991BF /* ringlogger.c in Sources */,
|
||||||
|
6B5C5E2A220A48D30024272E /* Keychain.swift in Sources */,
|
||||||
6FB1BDA421D4F53300A991BF /* Logger.swift in Sources */,
|
6FB1BDA421D4F53300A991BF /* Logger.swift in Sources */,
|
||||||
6FB1BDA521D4F53300A991BF /* TunnelConfiguration+WgQuickConfig.swift in Sources */,
|
6FB1BDA521D4F53300A991BF /* TunnelConfiguration+WgQuickConfig.swift in Sources */,
|
||||||
6FB1BDA621D4F53300A991BF /* NETunnelProviderProtocol+Extension.swift in Sources */,
|
6FB1BDA621D4F53300A991BF /* NETunnelProviderProtocol+Extension.swift in Sources */,
|
||||||
|
@ -1200,6 +1209,7 @@
|
||||||
6FDEF80021863C0100D8FBF6 /* ioapi.c in Sources */,
|
6FDEF80021863C0100D8FBF6 /* ioapi.c in Sources */,
|
||||||
6F7F7E5F21C7D74B00527607 /* TunnelErrors.swift in Sources */,
|
6F7F7E5F21C7D74B00527607 /* TunnelErrors.swift in Sources */,
|
||||||
6FDEF7FC21863B6100D8FBF6 /* zip.c in Sources */,
|
6FDEF7FC21863B6100D8FBF6 /* zip.c in Sources */,
|
||||||
|
6B5C5E27220A48D30024272E /* Keychain.swift in Sources */,
|
||||||
6F628C3F217F3413003482A3 /* DNSServer.swift in Sources */,
|
6F628C3F217F3413003482A3 /* DNSServer.swift in Sources */,
|
||||||
6F628C3D217F09E9003482A3 /* TunnelViewModel.swift in Sources */,
|
6F628C3D217F09E9003482A3 /* TunnelViewModel.swift in Sources */,
|
||||||
5F4541A621C4449E00994C13 /* ButtonCell.swift in Sources */,
|
5F4541A621C4449E00994C13 /* ButtonCell.swift in Sources */,
|
||||||
|
|
|
@ -44,12 +44,21 @@ class TunnelsManager {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let tunnelManagers = managers ?? []
|
var tunnelManagers = managers ?? []
|
||||||
tunnelManagers.forEach { tunnelManager in
|
var refs: Set<Data> = []
|
||||||
if (tunnelManager.protocolConfiguration as? NETunnelProviderProtocol)?.migrateConfigurationIfNeeded() == true {
|
for (index, tunnelManager) in tunnelManagers.enumerated().reversed() {
|
||||||
|
let proto = tunnelManager.protocolConfiguration as? NETunnelProviderProtocol
|
||||||
|
if proto?.migrateConfigurationIfNeeded(called: tunnelManager.localizedDescription ?? "unknown") ?? false {
|
||||||
tunnelManager.saveToPreferences { _ in }
|
tunnelManager.saveToPreferences { _ in }
|
||||||
}
|
}
|
||||||
|
if let ref = proto?.verifyConfigurationReference() {
|
||||||
|
refs.insert(ref)
|
||||||
|
} else {
|
||||||
|
tunnelManager.removeFromPreferences { _ in }
|
||||||
|
tunnelManagers.remove(at: index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Keychain.deleteReferences(except: refs)
|
||||||
completionHandler(.success(TunnelsManager(tunnelProviders: tunnelManagers)))
|
completionHandler(.success(TunnelsManager(tunnelProviders: tunnelManagers)))
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -105,6 +114,7 @@ class TunnelsManager {
|
||||||
tunnelProviderManager.saveToPreferences { [weak self] error in
|
tunnelProviderManager.saveToPreferences { [weak self] error in
|
||||||
guard error == nil else {
|
guard error == nil else {
|
||||||
wg_log(.error, message: "Add: Saving configuration failed: \(error!)")
|
wg_log(.error, message: "Add: Saving configuration failed: \(error!)")
|
||||||
|
(tunnelProviderManager.protocolConfiguration as? NETunnelProviderProtocol)?.destroyConfigurationReference()
|
||||||
completionHandler(.failure(TunnelsManagerError.systemErrorOnAddTunnel(systemError: error!)))
|
completionHandler(.failure(TunnelsManagerError.systemErrorOnAddTunnel(systemError: error!)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -153,7 +163,7 @@ class TunnelsManager {
|
||||||
tunnel.name = tunnelName
|
tunnel.name = tunnelName
|
||||||
}
|
}
|
||||||
|
|
||||||
tunnelProviderManager.protocolConfiguration = NETunnelProviderProtocol(tunnelConfiguration: tunnelConfiguration)
|
tunnelProviderManager.protocolConfiguration = NETunnelProviderProtocol(tunnelConfiguration: tunnelConfiguration, previouslyFrom: tunnelProviderManager.protocolConfiguration)
|
||||||
tunnelProviderManager.localizedDescription = tunnelConfiguration.name
|
tunnelProviderManager.localizedDescription = tunnelConfiguration.name
|
||||||
tunnelProviderManager.isEnabled = true
|
tunnelProviderManager.isEnabled = true
|
||||||
|
|
||||||
|
@ -162,6 +172,7 @@ class TunnelsManager {
|
||||||
|
|
||||||
tunnelProviderManager.saveToPreferences { [weak self] error in
|
tunnelProviderManager.saveToPreferences { [weak self] error in
|
||||||
guard error == nil else {
|
guard error == nil else {
|
||||||
|
//TODO: the passwordReference for the old one has already been removed at this point and we can't easily roll back!
|
||||||
wg_log(.error, message: "Modify: Saving configuration failed: \(error!)")
|
wg_log(.error, message: "Modify: Saving configuration failed: \(error!)")
|
||||||
completionHandler(TunnelsManagerError.systemErrorOnModifyTunnel(systemError: error!))
|
completionHandler(TunnelsManagerError.systemErrorOnModifyTunnel(systemError: error!))
|
||||||
return
|
return
|
||||||
|
@ -202,6 +213,7 @@ class TunnelsManager {
|
||||||
|
|
||||||
func remove(tunnel: TunnelContainer, completionHandler: @escaping (TunnelsManagerError?) -> Void) {
|
func remove(tunnel: TunnelContainer, completionHandler: @escaping (TunnelsManagerError?) -> Void) {
|
||||||
let tunnelProviderManager = tunnel.tunnelProvider
|
let tunnelProviderManager = tunnel.tunnelProvider
|
||||||
|
(tunnelProviderManager.protocolConfiguration as? NETunnelProviderProtocol)?.destroyConfigurationReference()
|
||||||
|
|
||||||
tunnelProviderManager.removeFromPreferences { [weak self] error in
|
tunnelProviderManager.removeFromPreferences { [weak self] error in
|
||||||
guard error == nil else {
|
guard error == nil else {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
</array>
|
</array>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>group.$(APP_ID_IOS)</string>
|
<string>group.$(APP_ID_IOS)</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
</array>
|
</array>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>group.$(APP_ID_IOS)</string>
|
<string>group.$(APP_ID_IOS)</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
Loading…
Reference in New Issue