Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fcca2d4fec | |||
| 58181a4d40 | |||
| cf816ede13 | |||
| fbac282bdc | |||
| 61f5e017c8 | |||
| 4547e01283 | |||
| 5792db22a6 | |||
| 9d5aa1d8fa | |||
| 6331b81b5d | |||
| 77f929789c | |||
| b5b72b309f | |||
| 966fa7909b | |||
| 115059f2bb | |||
| e53c2d4d17 | |||
| 0a3a5ee900 | |||
| 7720307fc9 | |||
| ea827e2ebd | |||
| 91b1734b7a | |||
| bac4851e95 | |||
| 0e2556544e | |||
| 2ec51ba8cf | |||
| 998bbd73e4 | |||
| 38a6ba7091 | |||
| 407b367c8d |
+145
@@ -0,0 +1,145 @@
|
||||
# Installing WireGuard tunnels using Configuration Profiles
|
||||
|
||||
WireGuard configurations can be installed using Configuration Profiles
|
||||
through .mobileconfig files.
|
||||
|
||||
### Top-level payload entries
|
||||
|
||||
A .mobileconfig file is a plist file in XML format. The top-level XML item is a top-level payload dictionary (dict). This payload dictionary should contain the following keys:
|
||||
|
||||
- `PayloadDisplayName` (string): The name of the configuration profile, visible when installing the profile
|
||||
|
||||
- `PayloadType` (string): Should be `Configuration`
|
||||
|
||||
- `PayloadVersion` (integer): Should be `1`
|
||||
|
||||
- `PayloadIdentifier` (string): A reverse-DNS style unique identifier for the profile file.
|
||||
|
||||
If you install another .mobileconfig file with the same identifier, the new one
|
||||
overwrites the old one.
|
||||
|
||||
- `PayloadUUID` (string): A randomly generated UUID for this payload
|
||||
|
||||
- `PayloadContent` (array): Should contain an array of payload dictionaries.
|
||||
|
||||
Each of these payload dictionaries can represent a WireGuard tunnel
|
||||
configuration.
|
||||
|
||||
Here's an example .mobileconfig with the above fields filled in:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>WireGuard Demo Configuration Profile</string>
|
||||
<key>PayloadType</key>
|
||||
<string>Configuration</string>
|
||||
<key>PayloadVersion</key>
|
||||
<integer>1</integer>
|
||||
<key>PayloadIdentifier</key>
|
||||
<string>com.your-org.wireguard.FCC9BF80-C540-44C1-B243-521FDD1B2905</string>
|
||||
<key>PayloadUUID</key>
|
||||
<string>F346AAF4-53A2-4FA1-ACA3-EEE74DBED029</string>
|
||||
<key>PayloadContent</key>
|
||||
<array>
|
||||
<!-- An array of WireGuard configuration payload dictionaries -->
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
### WireGuard payload entries
|
||||
|
||||
Each WireGuard configuration payload dictionary should contain the following
|
||||
keys:
|
||||
|
||||
- `PayloadDisplayName` (string): Should be `VPN`
|
||||
|
||||
- `PayloadType` (string): Should be `com.apple.vpn.managed`
|
||||
|
||||
- `PayloadVersion` (integer): Should be `1`
|
||||
|
||||
- `PayloadIdentifier` (string): A reverse-DNS style unique identifier for the WireGuard configuration profile.
|
||||
|
||||
- `PayloadUUID` (string): A randomly generated UUID for this payload
|
||||
|
||||
- `UserDefinedName` (string): The name of the WireGuard tunnel.
|
||||
|
||||
This name shall be used to represent the tunnel in the WireGuard app, and in the System UI for VPNs (Settings > VPN on iOS, System Preferences > Network on macOS).
|
||||
|
||||
- `VPNType` (string): Should be `VPN`
|
||||
|
||||
- `VPNSubType` (string): Should be set as the bundle identifier of the WireGuard app.
|
||||
|
||||
- iOS: `com.wireguard.ios`
|
||||
- macOS: `com.wireguard.macos`
|
||||
|
||||
- `VendorConfig` (dict): Should be a dictionary with the following key:
|
||||
|
||||
- `WgQuickConfig` (string): Should be a WireGuard configuration in [wg-quick(8)] / [wg(8)] format.
|
||||
|
||||
The keys 'FwMark', 'Table', 'PreUp', 'PostUp', 'PreDown', 'PostDown' and 'SaveConfig' are not supported.
|
||||
|
||||
- `VPN` (dict): Should be a dictionary with the following keys:
|
||||
|
||||
- `RemoteAddress` (string): A non-empty string.
|
||||
|
||||
This string is displayed as the server name in the System UI for
|
||||
VPNs (Settings > VPN on iOS, System Preferences > Network on macOS).
|
||||
|
||||
- `AuthenticationMethod` (string): Should be `Password`
|
||||
|
||||
Here's an example WireGuard configuration payload dictionary:
|
||||
|
||||
```xml
|
||||
<!-- A WireGuard configuration payload dictionary -->
|
||||
<dict>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>VPN</string>
|
||||
<key>PayloadType</key>
|
||||
<string>com.apple.vpn.managed</string>
|
||||
<key>PayloadVersion</key>
|
||||
<integer>1</integer>
|
||||
<key>PayloadIdentifier</key>
|
||||
<string>com.your-org.wireguard.demo-profile-1.demo-tunnel</string>
|
||||
<key>PayloadUUID</key>
|
||||
<string>44CDFE9F-4DC7-472A-956F-61C68055117C</string>
|
||||
<key>UserDefinedName</key>
|
||||
<string>Demo from MobileConfig file</string>
|
||||
<key>VPNType</key>
|
||||
<string>VPN</string>
|
||||
<key>VPNSubType</key>
|
||||
<string>com.wireguard.ios</string>
|
||||
<key>VendorConfig</key>
|
||||
<dict>
|
||||
<key>WgQuickConfig</key>
|
||||
<string>
|
||||
[Interface]
|
||||
PrivateKey = mInDaw06K0NgfULRObHJjkWD3ahUC8XC1tVjIf6W+Vo=
|
||||
Address = 10.10.1.0/24
|
||||
DNS = 1.1.1.1, 1.0.0.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = JRI8Xc0zKP9kXk8qP84NdUQA04h6DLfFbwJn4g+/PFs=
|
||||
Endpoint = demo.wireguard.com:12912
|
||||
AllowedIPs = 0.0.0.0/0
|
||||
</string>
|
||||
</dict>
|
||||
<key>VPN</key>
|
||||
<dict>
|
||||
<key>RemoteAddress</key>
|
||||
<string>demo.wireguard.com:12912</string>
|
||||
<key>AuthenticationMethod</key>
|
||||
<string>Password</string>
|
||||
</dict>
|
||||
</dict>
|
||||
```
|
||||
|
||||
### Caveats
|
||||
|
||||
Configurations added via .mobileconfig will not be migrated into keychain until the WireGuard application is opened once.
|
||||
|
||||
[wg-quick(8)]: https://git.zx2c4.com/WireGuard/about/src/tools/man/wg-quick.8
|
||||
[wg(8)]: https://git.zx2c4.com/WireGuard/about/src/tools/man/wg.8
|
||||
@@ -2,6 +2,11 @@ disabled_rules:
|
||||
- line_length
|
||||
- trailing_whitespace
|
||||
- todo
|
||||
- cyclomatic_complexity
|
||||
- file_length
|
||||
- type_body_length
|
||||
- function_body_length
|
||||
- nesting
|
||||
opt_in_rules:
|
||||
- empty_count
|
||||
- empty_string
|
||||
@@ -14,14 +19,7 @@ opt_in_rules:
|
||||
- toggle_bool
|
||||
- unneeded_parentheses_in_closure_argument
|
||||
- unused_import
|
||||
# - trailing_closure
|
||||
file_length:
|
||||
warning: 500
|
||||
cyclomatic_complexity:
|
||||
warning: 10
|
||||
error: 25
|
||||
function_body_length:
|
||||
warning: 45
|
||||
- trailing_closure
|
||||
variable_name:
|
||||
min_length:
|
||||
warning: 0
|
||||
|
||||
@@ -23,9 +23,6 @@ extension Data {
|
||||
}
|
||||
|
||||
init?(hexKey hexString: String) {
|
||||
if hexString.utf8.count != WG_KEY_LEN_HEX - 1 {
|
||||
return nil
|
||||
}
|
||||
self.init(repeating: 0, count: Int(WG_KEY_LEN))
|
||||
|
||||
if !self.withUnsafeMutableBytes { key_from_hex($0, hexString) } {
|
||||
@@ -48,9 +45,6 @@ extension Data {
|
||||
}
|
||||
|
||||
init?(base64Key base64String: String) {
|
||||
if base64String.utf8.count != WG_KEY_LEN_BASE64 - 1 {
|
||||
return nil
|
||||
}
|
||||
self.init(repeating: 0, count: Int(WG_KEY_LEN))
|
||||
|
||||
if !self.withUnsafeMutableBytes { key_from_base64($0, base64String) } {
|
||||
@@ -34,17 +34,14 @@ extension NETunnelProviderProtocol {
|
||||
}
|
||||
|
||||
func asTunnelConfiguration(called name: String? = nil) -> TunnelConfiguration? {
|
||||
migrateConfigurationIfNeeded(called: name ?? "unknown")
|
||||
//TODO: in the case where migrateConfigurationIfNeeded is called by the network extension,
|
||||
// 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)
|
||||
if let passwordReference = passwordReference,
|
||||
let config = Keychain.openReference(called: passwordReference) {
|
||||
return try? TunnelConfiguration(fromWgQuickConfig: config, called: name)
|
||||
}
|
||||
if let oldConfig = providerConfiguration?["WgQuickConfig"] as? String {
|
||||
return try? TunnelConfiguration(fromWgQuickConfig: oldConfig, called: name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func destroyConfigurationReference() {
|
||||
@@ -66,6 +63,7 @@ extension NETunnelProviderProtocol {
|
||||
guard let oldConfig = providerConfiguration?["WgQuickConfig"] as? String else { return false }
|
||||
providerConfiguration = nil
|
||||
guard passwordReference == nil else { return true }
|
||||
wg_log(.debug, message: "Migrating tunnel configuration '\(name)'")
|
||||
passwordReference = Keychain.makeReference(containing: oldConfig, called: name)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ extension TunnelConfiguration {
|
||||
case multipleEntriesForKey(String)
|
||||
}
|
||||
|
||||
//swiftlint:disable:next function_body_length cyclomatic_complexity
|
||||
convenience init(fromWgQuickConfig wgQuickConfig: String, called name: String? = nil) throws {
|
||||
var interfaceConfiguration: InterfaceConfiguration?
|
||||
var peerConfigurations = [PeerConfiguration]()
|
||||
@@ -149,7 +148,7 @@ extension TunnelConfiguration {
|
||||
if let publicKey = peer.publicKey.base64Key() {
|
||||
output.append("PublicKey = \(publicKey)\n")
|
||||
}
|
||||
if let preSharedKey = peer.preSharedKey?.base64Key {
|
||||
if let preSharedKey = peer.preSharedKey?.base64Key() {
|
||||
output.append("PresharedKey = \(preSharedKey)\n")
|
||||
}
|
||||
if !peer.allowedIPs.isEmpty {
|
||||
@@ -167,7 +166,6 @@ extension TunnelConfiguration {
|
||||
return output
|
||||
}
|
||||
|
||||
//swiftlint:disable:next cyclomatic_complexity
|
||||
private static func collate(interfaceAttributes attributes: [String: String]) throws -> InterfaceConfiguration {
|
||||
guard let privateKeyString = attributes["privatekey"] else {
|
||||
throw ParseError.interfaceHasNoPrivateKey
|
||||
@@ -211,7 +209,6 @@ extension TunnelConfiguration {
|
||||
return interface
|
||||
}
|
||||
|
||||
//swiftlint:disable:next cyclomatic_complexity
|
||||
private static func collate(peerAttributes attributes: [String: String]) throws -> PeerConfiguration {
|
||||
guard let publicKeyString = attributes["publickey"] else {
|
||||
throw ParseError.peerHasNoPublicKey
|
||||
|
||||
@@ -28,19 +28,22 @@
|
||||
5FF7B96321CC95DE00A7DD74 /* InterfaceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF7B96121CC95DE00A7DD74 /* InterfaceConfiguration.swift */; };
|
||||
5FF7B96521CC95FA00A7DD74 /* PeerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */; };
|
||||
5FF7B96621CC95FA00A7DD74 /* PeerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */; };
|
||||
6B586C51220CACB600427C51 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6FF4AC462120B9E0002C96EB /* NetworkExtension.framework */; };
|
||||
6B586C53220CBA6D00427C51 /* Key.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Key.swift */; };
|
||||
6B586C54220CBA6D00427C51 /* Key.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Key.swift */; };
|
||||
6B586C55220CBA6D00427C51 /* Key.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Key.swift */; };
|
||||
6B586C56220CBA6D00427C51 /* Key.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Key.swift */; };
|
||||
6B586C53220CBA6D00427C51 /* Data+KeyEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Data+KeyEncoding.swift */; };
|
||||
6B586C54220CBA6D00427C51 /* Data+KeyEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Data+KeyEncoding.swift */; };
|
||||
6B586C55220CBA6D00427C51 /* Data+KeyEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Data+KeyEncoding.swift */; };
|
||||
6B586C56220CBA6D00427C51 /* Data+KeyEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Data+KeyEncoding.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 */; };
|
||||
6B5CA6B1220DE4E900F126CF /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6FF4AC462120B9E0002C96EB /* NetworkExtension.framework */; };
|
||||
6B5CA6B2220DE4F400F126CF /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6FB1BDB621D4F8B800A991BF /* NetworkExtension.framework */; };
|
||||
6B62E45F220A6FA900EF34A6 /* PrivateDataConfirmation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B62E45E220A6FA900EF34A6 /* PrivateDataConfirmation.swift */; };
|
||||
6B62E460220A6FA900EF34A6 /* PrivateDataConfirmation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B62E45E220A6FA900EF34A6 /* PrivateDataConfirmation.swift */; };
|
||||
6B653B86220DE2960050E69C /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6FF4AC462120B9E0002C96EB /* NetworkExtension.framework */; };
|
||||
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 */; };
|
||||
6BAC16E6221634B300A5FB78 /* AppStorePrivacyNotice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BAC16E42216324B00A5FB78 /* AppStorePrivacyNotice.swift */; };
|
||||
6BD5C97B220D1AE200784E08 /* key.c in Sources */ = {isa = PBXBuildFile; fileRef = 6BD5C979220D1AE100784E08 /* key.c */; };
|
||||
6BD5C97C220D1AE200784E08 /* key.c in Sources */ = {isa = PBXBuildFile; fileRef = 6BD5C979220D1AE100784E08 /* key.c */; };
|
||||
6BD5C97D220D1AE200784E08 /* key.c in Sources */ = {isa = PBXBuildFile; fileRef = 6BD5C979220D1AE100784E08 /* key.c */; };
|
||||
@@ -61,6 +64,8 @@
|
||||
6F6899A62180447E0012E523 /* x25519.c in Sources */ = {isa = PBXBuildFile; fileRef = 6F6899A52180447E0012E523 /* x25519.c */; };
|
||||
6F6899A8218044FC0012E523 /* Curve25519.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F6899A7218044FC0012E523 /* Curve25519.swift */; };
|
||||
6F693A562179E556008551C1 /* Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F693A552179E556008551C1 /* Endpoint.swift */; };
|
||||
6F70E20E221058E1008BDFB4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6F70E20C221058DF008BDFB4 /* InfoPlist.strings */; };
|
||||
6F70E20F221058E1008BDFB4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6F70E20C221058DF008BDFB4 /* InfoPlist.strings */; };
|
||||
6F7774E1217181B1006A79B3 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774DF217181B1006A79B3 /* MainViewController.swift */; };
|
||||
6F7774E2217181B1006A79B3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774E0217181B1006A79B3 /* AppDelegate.swift */; };
|
||||
6F7774E421718281006A79B3 /* TunnelsListTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774E321718281006A79B3 /* TunnelsListTableViewController.swift */; };
|
||||
@@ -98,7 +103,6 @@
|
||||
6FB1BDB121D4F55700A991BF /* PacketTunnelSettingsGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5D0C472183C6A3000F85AD /* PacketTunnelSettingsGenerator.swift */; };
|
||||
6FB1BDB221D4F55700A991BF /* DNSResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5D0C1421832391000F85AD /* DNSResolver.swift */; };
|
||||
6FB1BDB321D4F55700A991BF /* ErrorNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5D9F21958ECC0001E2F7 /* ErrorNotifier.swift */; };
|
||||
6FB1BDB721D4F8B800A991BF /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6FB1BDB621D4F8B800A991BF /* NetworkExtension.framework */; };
|
||||
6FB1BDBB21D50F0200A991BF /* Localizable.strings in Sources */ = {isa = PBXBuildFile; fileRef = 6FE1765421C90BBE002690EA /* Localizable.strings */; };
|
||||
6FB1BDBC21D50F0200A991BF /* ringlogger.c in Sources */ = {isa = PBXBuildFile; fileRef = 6FF3526C21C23F960008484E /* ringlogger.c */; };
|
||||
6FB1BDBD21D50F0200A991BF /* ringlogger.h in Sources */ = {isa = PBXBuildFile; fileRef = 6FF3526B21C23F960008484E /* ringlogger.h */; };
|
||||
@@ -248,10 +252,11 @@
|
||||
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>"; };
|
||||
5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeerConfiguration.swift; sourceTree = "<group>"; };
|
||||
6B586C52220CBA6D00427C51 /* Key.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Key.swift; sourceTree = "<group>"; };
|
||||
6B586C52220CBA6D00427C51 /* Data+KeyEncoding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+KeyEncoding.swift"; sourceTree = "<group>"; };
|
||||
6B5C5E26220A48D30024272E /* Keychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keychain.swift; sourceTree = "<group>"; };
|
||||
6B62E45E220A6FA900EF34A6 /* PrivateDataConfirmation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivateDataConfirmation.swift; sourceTree = "<group>"; };
|
||||
6B707D8321F918D4000A8F73 /* TunnelConfiguration+UapiConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TunnelConfiguration+UapiConfig.swift"; sourceTree = "<group>"; };
|
||||
6BAC16E42216324B00A5FB78 /* AppStorePrivacyNotice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStorePrivacyNotice.swift; sourceTree = "<group>"; };
|
||||
6BD5C979220D1AE100784E08 /* key.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = key.c; sourceTree = "<group>"; };
|
||||
6BD5C97A220D1AE200784E08 /* key.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = key.h; sourceTree = "<group>"; };
|
||||
6F4DD16721DA552B00690EAE /* NSTableView+Reuse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSTableView+Reuse.swift"; sourceTree = "<group>"; };
|
||||
@@ -276,6 +281,7 @@
|
||||
6F6899A52180447E0012E523 /* x25519.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x25519.c; sourceTree = "<group>"; };
|
||||
6F6899A7218044FC0012E523 /* Curve25519.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Curve25519.swift; sourceTree = "<group>"; };
|
||||
6F693A552179E556008551C1 /* Endpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Endpoint.swift; sourceTree = "<group>"; };
|
||||
6F70E20D221058DF008BDFB4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = WireGuard/Base.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
6F7774DF217181B1006A79B3 /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = "<group>"; };
|
||||
6F7774E0217181B1006A79B3 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
6F7774E321718281006A79B3 /* TunnelsListTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TunnelsListTableViewController.swift; sourceTree = "<group>"; };
|
||||
@@ -348,8 +354,8 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6B5CA6B1220DE4E900F126CF /* NetworkExtension.framework in Frameworks */,
|
||||
6FDEF7E421846C1A00D8FBF6 /* libwg-go.a in Frameworks */,
|
||||
6B586C51220CACB600427C51 /* NetworkExtension.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -365,8 +371,8 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6B5CA6B2220DE4F400F126CF /* NetworkExtension.framework in Frameworks */,
|
||||
6FB1BDA121D4E00A00A991BF /* libwg-go.a in Frameworks */,
|
||||
6FB1BDB721D4F8B800A991BF /* NetworkExtension.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -374,6 +380,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6B653B86220DE2960050E69C /* NetworkExtension.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -501,7 +508,7 @@
|
||||
6F628C3E217F3413003482A3 /* DNSServer.swift */,
|
||||
5FF7B96121CC95DE00A7DD74 /* InterfaceConfiguration.swift */,
|
||||
5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */,
|
||||
6B586C52220CBA6D00427C51 /* Key.swift */,
|
||||
6B586C52220CBA6D00427C51 /* Data+KeyEncoding.swift */,
|
||||
);
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
@@ -556,6 +563,7 @@
|
||||
6F4DD16721DA552B00690EAE /* NSTableView+Reuse.swift */,
|
||||
5F52D0BE21E3788900283CEA /* NSColor+Hex.swift */,
|
||||
6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */,
|
||||
6BAC16E42216324B00A5FB78 /* AppStorePrivacyNotice.swift */,
|
||||
);
|
||||
path = macOS;
|
||||
sourceTree = "<group>";
|
||||
@@ -617,6 +625,7 @@
|
||||
6FF4AC0B211EC46F002C96EB = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6F70E20C221058DF008BDFB4 /* InfoPlist.strings */,
|
||||
6FE1765421C90BBE002690EA /* Localizable.strings */,
|
||||
6F5D0C432183B4A4000F85AD /* Shared */,
|
||||
6FF4AC16211EC46F002C96EB /* WireGuard */,
|
||||
@@ -872,6 +881,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6FB1BD6221D2607E00A991BF /* Assets.xcassets in Resources */,
|
||||
6F70E20F221058E1008BDFB4 /* InfoPlist.strings in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -887,6 +897,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6F919ED9218C65C50023B400 /* wireguard_doc_logo_22x29.png in Resources */,
|
||||
6F70E20E221058E1008BDFB4 /* InfoPlist.strings in Resources */,
|
||||
6FE1765621C90BBE002690EA /* Localizable.strings in Resources */,
|
||||
6FF4AC22211EC472002C96EB /* LaunchScreen.storyboard in Resources */,
|
||||
6F919EDA218C65C50023B400 /* wireguard_doc_logo_44x58.png in Resources */,
|
||||
@@ -1101,7 +1112,7 @@
|
||||
5FF7B96621CC95FA00A7DD74 /* PeerConfiguration.swift in Sources */,
|
||||
5F9696AE21CD6F72008063FE /* String+ArrayConversion.swift in Sources */,
|
||||
6FFA5D8F2194370D0001E2F7 /* IPAddressRange.swift in Sources */,
|
||||
6B586C54220CBA6D00427C51 /* Key.swift in Sources */,
|
||||
6B586C54220CBA6D00427C51 /* Data+KeyEncoding.swift in Sources */,
|
||||
6FFA5D902194370D0001E2F7 /* Endpoint.swift in Sources */,
|
||||
5FF7B96321CC95DE00A7DD74 /* InterfaceConfiguration.swift in Sources */,
|
||||
6FFA5D9321943BC90001E2F7 /* DNSResolver.swift in Sources */,
|
||||
@@ -1146,8 +1157,9 @@
|
||||
6FCD99B121E0EDA900BA4C82 /* TunnelEditViewController.swift in Sources */,
|
||||
6FB1BDCA21D50F1700A991BF /* x25519.c in Sources */,
|
||||
6FB1BDCB21D50F1700A991BF /* Curve25519.swift in Sources */,
|
||||
6B586C55220CBA6D00427C51 /* Key.swift in Sources */,
|
||||
6B586C55220CBA6D00427C51 /* Data+KeyEncoding.swift in Sources */,
|
||||
6F9B582921E8D6D100544D02 /* PopupRow.swift in Sources */,
|
||||
6BAC16E6221634B300A5FB78 /* AppStorePrivacyNotice.swift in Sources */,
|
||||
6FB1BDBB21D50F0200A991BF /* Localizable.strings in Sources */,
|
||||
6FB1BDBC21D50F0200A991BF /* ringlogger.c in Sources */,
|
||||
6FB1BDBD21D50F0200A991BF /* ringlogger.h in Sources */,
|
||||
@@ -1193,7 +1205,7 @@
|
||||
6FB1BDA621D4F53300A991BF /* NETunnelProviderProtocol+Extension.swift in Sources */,
|
||||
6FB1BDA721D4F53300A991BF /* String+ArrayConversion.swift in Sources */,
|
||||
6FB1BDA921D4F53300A991BF /* TunnelConfiguration.swift in Sources */,
|
||||
6B586C56220CBA6D00427C51 /* Key.swift in Sources */,
|
||||
6B586C56220CBA6D00427C51 /* Data+KeyEncoding.swift in Sources */,
|
||||
6FB1BDAA21D4F53300A991BF /* IPAddressRange.swift in Sources */,
|
||||
6FB1BDAB21D4F53300A991BF /* Endpoint.swift in Sources */,
|
||||
6FB1BDAC21D4F53300A991BF /* DNSServer.swift in Sources */,
|
||||
@@ -1216,7 +1228,7 @@
|
||||
5F45417D21C1B23600994C13 /* UITableViewCell+Reuse.swift in Sources */,
|
||||
5F45419221C2D55800994C13 /* CheckmarkCell.swift in Sources */,
|
||||
6FE254FF219C60290028284D /* ZipExporter.swift in Sources */,
|
||||
6B586C53220CBA6D00427C51 /* Key.swift in Sources */,
|
||||
6B586C53220CBA6D00427C51 /* Data+KeyEncoding.swift in Sources */,
|
||||
6F693A562179E556008551C1 /* Endpoint.swift in Sources */,
|
||||
6FDEF7E62185EFB200D8FBF6 /* QRScanViewController.swift in Sources */,
|
||||
6FFA5D952194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift in Sources */,
|
||||
@@ -1289,6 +1301,14 @@
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
6F70E20C221058DF008BDFB4 /* InfoPlist.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
6F70E20D221058DF008BDFB4 /* Base */,
|
||||
);
|
||||
name = InfoPlist.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6FE1765421C90BBE002690EA /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
@@ -1311,6 +1331,7 @@
|
||||
6F5D0C23218352EF000F85AD /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = WireGuardNetworkExtension/WireGuardNetworkExtension_iOS.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
@@ -1332,6 +1353,7 @@
|
||||
6F5D0C24218352EF000F85AD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = WireGuardNetworkExtension/WireGuardNetworkExtension_iOS.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
@@ -1391,6 +1413,7 @@
|
||||
6FB1BD9A21D4BFE700A991BF /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
|
||||
CODE_SIGN_ENTITLEMENTS = WireGuardNetworkExtension/WireGuardNetworkExtension_macOS.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
INFOPLIST_FILE = WireGuardNetworkExtension/Info.plist;
|
||||
@@ -1411,6 +1434,7 @@
|
||||
6FB1BD9B21D4BFE700A991BF /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
|
||||
CODE_SIGN_ENTITLEMENTS = WireGuardNetworkExtension/WireGuardNetworkExtension_macOS.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
INFOPLIST_FILE = WireGuardNetworkExtension/Info.plist;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
||||
|
||||
// iOS permission prompts
|
||||
|
||||
NSCameraUsageDescription = "Camera is used for scanning QR codes for importing WireGuard configurations";
|
||||
NSFaceIDUsageDescription = "Face ID is used for authenticating viewing and exporting of private keys";
|
||||
@@ -111,6 +111,8 @@
|
||||
"tunnelHandshakeTimestampHours hh:mm:ss (%@)" = "%@ hours";
|
||||
"tunnelHandshakeTimestampMinutes mm:ss (%@)" = "%@ minutes";
|
||||
|
||||
"tunnelPeerPresharedKeyEnabled" = "enabled";
|
||||
|
||||
// Error alerts while creating / editing a tunnel configuration
|
||||
|
||||
/* Alert title for error in the interface data */
|
||||
@@ -331,3 +333,5 @@
|
||||
|
||||
"macAppExitingWithActiveTunnelMessage" = "WireGuard is exiting with an active tunnel";
|
||||
"macAppExitingWithActiveTunnelInfo" = "The tunnel will remain active after exiting. You may disable it by reopening this application or through the Network panel in System Preferences.";
|
||||
"macPrivacyNoticeMessage" = "Privacy notice: be sure you trust this configuration file";
|
||||
"macPrivacyNoticeInfo" = "You will be prompted by the system to allow or disallow adding a VPN configuration. While this application does not send any information to the WireGuard project, information is by design sent to the servers specified inside of the configuration file you have just added, which configures your computer to use those servers as a VPN. Be certain that you trust this configuration before clicking “Allow” in the following dialog.";
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
VERSION_NAME = 0.0.20190207
|
||||
VERSION_ID = 1
|
||||
VERSION_ID = 3
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
import Foundation
|
||||
|
||||
extension TunnelConfiguration {
|
||||
//swiftlint:disable:next function_body_length cyclomatic_complexity
|
||||
convenience init(fromUapiConfig uapiConfig: String, basedOn base: TunnelConfiguration? = nil) throws {
|
||||
var interfaceConfiguration: InterfaceConfiguration?
|
||||
var peerConfigurations = [PeerConfiguration]()
|
||||
@@ -103,7 +102,6 @@ extension TunnelConfiguration {
|
||||
return interface
|
||||
}
|
||||
|
||||
//swiftlint:disable:next cyclomatic_complexity
|
||||
private static func collate(peerAttributes attributes: [String: String]) throws -> PeerConfiguration {
|
||||
guard let publicKeyString = attributes["public_key"] else {
|
||||
throw ParseError.peerHasNoPublicKey
|
||||
|
||||
@@ -83,6 +83,11 @@ class TunnelsManager {
|
||||
matchingTunnel.refreshStatus()
|
||||
} else {
|
||||
// Tunnel was added outside the app
|
||||
if let proto = loadedTunnelProvider.protocolConfiguration as? NETunnelProviderProtocol {
|
||||
if proto.migrateConfigurationIfNeeded(called: loadedTunnelProvider.localizedDescription ?? "unknown") {
|
||||
loadedTunnelProvider.saveToPreferences { _ in }
|
||||
}
|
||||
}
|
||||
let tunnel = TunnelContainer(tunnel: loadedTunnelProvider)
|
||||
self.tunnels.append(tunnel)
|
||||
self.tunnels.sort { $0.name < $1.name }
|
||||
@@ -313,11 +318,7 @@ class TunnelsManager {
|
||||
guard let self = self,
|
||||
let session = statusChangeNotification.object as? NETunnelProviderSession,
|
||||
let tunnelProvider = session.manager as? NETunnelProviderManager,
|
||||
let tunnelConfiguration = tunnelProvider.tunnelConfiguration,
|
||||
let tunnel = self.tunnels.first(where: { $0.tunnelConfiguration == tunnelConfiguration }) else { return }
|
||||
if tunnel.tunnelProvider != tunnelProvider {
|
||||
return
|
||||
}
|
||||
let tunnel = self.tunnels.first(where: { $0.tunnelProvider == tunnelProvider }) else { return }
|
||||
|
||||
wg_log(.debug, message: "Tunnel '\(tunnel.name)' connection status changed to '\(tunnel.tunnelProvider.connection.status)'")
|
||||
|
||||
@@ -446,7 +447,6 @@ class TunnelContainer: NSObject {
|
||||
isActivateOnDemandEnabled = tunnelProvider.isOnDemandEnabled
|
||||
}
|
||||
|
||||
//swiftlint:disable:next function_body_length
|
||||
fileprivate func startActivation(recursionCount: UInt = 0, lastError: Error? = nil, activationDelegate: TunnelsManagerActivationDelegate?) {
|
||||
if recursionCount >= 8 {
|
||||
wg_log(.error, message: "startActivation: Failed after 8 attempts. Giving up with \(lastError!)")
|
||||
@@ -532,6 +532,7 @@ extension NETunnelProviderManager {
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
func setTunnelConfiguration(_ tunnelConfiguration: TunnelConfiguration) {
|
||||
protocolConfiguration = NETunnelProviderProtocol(tunnelConfiguration: tunnelConfiguration, previouslyFrom: protocolConfiguration)
|
||||
localizedDescription = tunnelConfiguration.name
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
//swiftlint:disable:next type_body_length
|
||||
class TunnelViewModel {
|
||||
|
||||
enum InterfaceField: CaseIterable {
|
||||
@@ -68,16 +67,17 @@ class TunnelViewModel {
|
||||
|
||||
static let keyLengthInBase64 = 44
|
||||
|
||||
struct ChangeHandlers {
|
||||
enum FieldChange {
|
||||
struct Changes {
|
||||
enum FieldChange: Equatable {
|
||||
case added
|
||||
case removed
|
||||
case modified
|
||||
case modified(newValue: String)
|
||||
}
|
||||
var interfaceChanged: ([InterfaceField: FieldChange]) -> Void
|
||||
var peerChangedAt: (Int, [PeerField: FieldChange]) -> Void
|
||||
var peersRemovedAt: ([Int]) -> Void
|
||||
var peersInsertedAt: ([Int]) -> Void
|
||||
|
||||
var interfaceChanges: [InterfaceField: FieldChange]
|
||||
var peerChanges: [(peerIndex: Int, changes: [PeerField: FieldChange])]
|
||||
var peersRemovedIndices: [Int]
|
||||
var peersInsertedIndices: [Int]
|
||||
}
|
||||
|
||||
class InterfaceData {
|
||||
@@ -141,7 +141,6 @@ class TunnelViewModel {
|
||||
return scratchpad
|
||||
}
|
||||
|
||||
//swiftlint:disable:next cyclomatic_complexity function_body_length
|
||||
func save() -> SaveResult<(String, InterfaceConfiguration)> {
|
||||
if let config = validatedConfiguration, let name = validatedName {
|
||||
return .saved((name, config))
|
||||
@@ -218,12 +217,12 @@ class TunnelViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
func applyConfiguration(other: InterfaceConfiguration, otherName: String, changeHandler: ([InterfaceField: ChangeHandlers.FieldChange]) -> Void) {
|
||||
func applyConfiguration(other: InterfaceConfiguration, otherName: String) -> [InterfaceField: Changes.FieldChange] {
|
||||
if scratchpad.isEmpty {
|
||||
populateScratchpad()
|
||||
}
|
||||
let otherScratchPad = InterfaceData.createScratchPad(from: other, name: otherName)
|
||||
var changes = [InterfaceField: ChangeHandlers.FieldChange]()
|
||||
var changes = [InterfaceField: Changes.FieldChange]()
|
||||
for field in InterfaceField.allCases {
|
||||
switch (scratchpad[field] ?? "", otherScratchPad[field] ?? "") {
|
||||
case ("", ""):
|
||||
@@ -234,14 +233,12 @@ class TunnelViewModel {
|
||||
changes[field] = .removed
|
||||
case (let this, let other):
|
||||
if this != other {
|
||||
changes[field] = .modified
|
||||
changes[field] = .modified(newValue: other)
|
||||
}
|
||||
}
|
||||
}
|
||||
scratchpad = otherScratchPad
|
||||
if !changes.isEmpty {
|
||||
changeHandler(changes)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,7 +324,6 @@ class TunnelViewModel {
|
||||
return scratchpad
|
||||
}
|
||||
|
||||
//swiftlint:disable:next cyclomatic_complexity
|
||||
func save() -> SaveResult<PeerConfiguration> {
|
||||
if let validatedConfiguration = validatedConfiguration {
|
||||
return .saved(validatedConfiguration)
|
||||
@@ -443,12 +439,12 @@ class TunnelViewModel {
|
||||
excludePrivateIPsValue = isOn
|
||||
}
|
||||
|
||||
func applyConfiguration(other: PeerConfiguration, peerIndex: Int, changeHandler: (Int, [PeerField: ChangeHandlers.FieldChange]) -> Void) {
|
||||
func applyConfiguration(other: PeerConfiguration) -> [PeerField: Changes.FieldChange] {
|
||||
if scratchpad.isEmpty {
|
||||
populateScratchpad()
|
||||
}
|
||||
let otherScratchPad = PeerData.createScratchPad(from: other)
|
||||
var changes = [PeerField: ChangeHandlers.FieldChange]()
|
||||
var changes = [PeerField: Changes.FieldChange]()
|
||||
for field in PeerField.allCases {
|
||||
switch (scratchpad[field] ?? "", otherScratchPad[field] ?? "") {
|
||||
case ("", ""):
|
||||
@@ -459,14 +455,12 @@ class TunnelViewModel {
|
||||
changes[field] = .removed
|
||||
case (let this, let other):
|
||||
if this != other {
|
||||
changes[field] = .modified
|
||||
changes[field] = .modified(newValue: other)
|
||||
}
|
||||
}
|
||||
}
|
||||
scratchpad = otherScratchPad
|
||||
if !changes.isEmpty {
|
||||
changeHandler(peerIndex, changes)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -550,21 +544,20 @@ class TunnelViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
func applyConfiguration(other: TunnelConfiguration, changeHandlers: ChangeHandlers) {
|
||||
@discardableResult
|
||||
func applyConfiguration(other: TunnelConfiguration) -> Changes {
|
||||
// Replaces current data with data from other TunnelConfiguration, ignoring any changes in peer ordering.
|
||||
// Change handler callbacks are processed in the following order, which is designed to work with both the
|
||||
// UITableView way (modify - delete - insert) and the NSTableView way (indices are based on past operations):
|
||||
// - interfaceChanged
|
||||
// - peerChangedAt
|
||||
// - peersRemovedAt
|
||||
// - peersInsertedAt
|
||||
|
||||
interfaceData.applyConfiguration(other: other.interface, otherName: other.name ?? "", changeHandler: changeHandlers.interfaceChanged)
|
||||
let interfaceChanges = interfaceData.applyConfiguration(other: other.interface, otherName: other.name ?? "")
|
||||
|
||||
var peerChanges = [(peerIndex: Int, changes: [PeerField: Changes.FieldChange])]()
|
||||
for otherPeer in other.peers {
|
||||
if let peersDataIndex = peersData.firstIndex(where: { $0.publicKey == otherPeer.publicKey }) {
|
||||
let peerData = peersData[peersDataIndex]
|
||||
peerData.applyConfiguration(other: otherPeer, peerIndex: peersDataIndex, changeHandler: changeHandlers.peerChangedAt)
|
||||
let changes = peerData.applyConfiguration(other: otherPeer)
|
||||
if !changes.isEmpty {
|
||||
peerChanges.append((peerIndex: peersDataIndex, changes: changes))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,9 +568,6 @@ class TunnelViewModel {
|
||||
peersData.remove(at: index)
|
||||
}
|
||||
}
|
||||
if !removedPeerIndices.isEmpty {
|
||||
changeHandlers.peersRemovedAt(removedPeerIndices)
|
||||
}
|
||||
|
||||
var addedPeerIndices = [Int]()
|
||||
for otherPeer in other.peers {
|
||||
@@ -588,15 +578,14 @@ class TunnelViewModel {
|
||||
peersData.append(peerData)
|
||||
}
|
||||
}
|
||||
if !addedPeerIndices.isEmpty {
|
||||
changeHandlers.peersInsertedAt(addedPeerIndices)
|
||||
}
|
||||
|
||||
for (index, peer) in peersData.enumerated() {
|
||||
peer.index = index
|
||||
peer.numberOfPeers = peersData.count
|
||||
peer.updateExcludePrivateIPsFieldState()
|
||||
}
|
||||
|
||||
return Changes(interfaceChanges: interfaceChanges, peerChanges: peerChanges, peersRemovedIndices: removedPeerIndices, peersInsertedIndices: addedPeerIndices)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||
<false/>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Camera is used for scanning QR codes for importing WireGuard configurations</string>
|
||||
<string>Localized</string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
@@ -123,7 +123,7 @@
|
||||
</dict>
|
||||
</array>
|
||||
<key>NSFaceIDUsageDescription</key>
|
||||
<string>Face ID is used for authenticating viewing and exporting of private keys</string>
|
||||
<string>Localized</string>
|
||||
<key>com.wireguard.ios.app_group_id</key>
|
||||
<string>group.$(APP_ID_IOS)</string>
|
||||
</dict>
|
||||
|
||||
@@ -147,21 +147,32 @@ class TunnelDetailTableViewController: UITableViewController {
|
||||
// Incorporates changes from tunnelConfiguation. Ignores any changes in peer ordering.
|
||||
guard let tableView = self.tableView else { return }
|
||||
let sections = self.sections
|
||||
let interfaceSectionIndex = sections.firstIndex(where: { if case .interface = $0 { return true } else { return false }})!
|
||||
let interfaceSectionIndex = sections.firstIndex {
|
||||
if case .interface = $0 {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}!
|
||||
let firstPeerSectionIndex = interfaceSectionIndex + 1
|
||||
var interfaceFieldIsVisible = self.interfaceFieldIsVisible
|
||||
var peerFieldIsVisible = self.peerFieldIsVisible
|
||||
|
||||
func sectionChanged<T>(fields: [T], fieldIsVisible fieldIsVisibleInput: [Bool], tableView: UITableView, section: Int, changes: [T: TunnelViewModel.ChangeHandlers.FieldChange]) {
|
||||
func handleSectionFieldsModified<T>(fields: [T], fieldIsVisible: [Bool], section: Int, changes: [T: TunnelViewModel.Changes.FieldChange]) {
|
||||
for (index, field) in fields.enumerated() {
|
||||
guard let change = changes[field] else { continue }
|
||||
if case .modified(let newValue) = change {
|
||||
let row = fieldIsVisible[0 ..< index].filter { $0 }.count
|
||||
let indexPath = IndexPath(row: row, section: section)
|
||||
if let cell = tableView.cellForRow(at: indexPath) as? KeyValueCell {
|
||||
cell.value = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleSectionRowsInsertedOrRemoved<T>(fields: [T], fieldIsVisible fieldIsVisibleInput: [Bool], section: Int, changes: [T: TunnelViewModel.Changes.FieldChange]) {
|
||||
var fieldIsVisible = fieldIsVisibleInput
|
||||
var modifiedIndexPaths = [IndexPath]()
|
||||
for (index, field) in fields.enumerated() where changes[field] == .modified {
|
||||
let row = fieldIsVisible[0 ..< index].filter { $0 }.count
|
||||
modifiedIndexPaths.append(IndexPath(row: row, section: section))
|
||||
}
|
||||
if !modifiedIndexPaths.isEmpty {
|
||||
tableView.reloadRows(at: modifiedIndexPaths, with: .none)
|
||||
}
|
||||
|
||||
var removedIndexPaths = [IndexPath]()
|
||||
for (index, field) in fields.enumerated().reversed() where changes[field] == .removed {
|
||||
@@ -184,30 +195,44 @@ class TunnelDetailTableViewController: UITableViewController {
|
||||
}
|
||||
}
|
||||
|
||||
let changeHandlers = TunnelViewModel.ChangeHandlers(
|
||||
interfaceChanged: { changes in
|
||||
sectionChanged(fields: TunnelDetailTableViewController.interfaceFields, fieldIsVisible: interfaceFieldIsVisible,
|
||||
tableView: tableView, section: interfaceSectionIndex, changes: changes)
|
||||
},
|
||||
peerChangedAt: { peerIndex, changes in
|
||||
sectionChanged(fields: TunnelDetailTableViewController.peerFields, fieldIsVisible: peerFieldIsVisible[peerIndex],
|
||||
tableView: tableView, section: firstPeerSectionIndex + peerIndex, changes: changes)
|
||||
},
|
||||
peersRemovedAt: { peerIndices in
|
||||
let sectionIndices = peerIndices.map { firstPeerSectionIndex + $0 }
|
||||
tableView.deleteSections(IndexSet(sectionIndices), with: .automatic)
|
||||
},
|
||||
peersInsertedAt: { peerIndices in
|
||||
let sectionIndices = peerIndices.map { firstPeerSectionIndex + $0 }
|
||||
tableView.insertSections(IndexSet(sectionIndices), with: .automatic)
|
||||
}
|
||||
)
|
||||
let changes = self.tunnelViewModel.applyConfiguration(other: tunnelConfiguration)
|
||||
|
||||
tableView.beginUpdates()
|
||||
self.tunnelViewModel.applyConfiguration(other: tunnelConfiguration, changeHandlers: changeHandlers)
|
||||
self.loadSections()
|
||||
self.loadVisibleFields()
|
||||
tableView.endUpdates()
|
||||
if !changes.interfaceChanges.isEmpty {
|
||||
handleSectionFieldsModified(fields: TunnelDetailTableViewController.interfaceFields, fieldIsVisible: interfaceFieldIsVisible,
|
||||
section: interfaceSectionIndex, changes: changes.interfaceChanges)
|
||||
}
|
||||
for (peerIndex, peerChanges) in changes.peerChanges {
|
||||
handleSectionFieldsModified(fields: TunnelDetailTableViewController.peerFields, fieldIsVisible: peerFieldIsVisible[peerIndex], section: firstPeerSectionIndex + peerIndex, changes: peerChanges)
|
||||
}
|
||||
|
||||
let isAnyInterfaceFieldAddedOrRemoved = changes.interfaceChanges.contains { $0.value == .added || $0.value == .removed }
|
||||
let isAnyPeerFieldAddedOrRemoved = changes.peerChanges.contains { $0.changes.contains { $0.value == .added || $0.value == .removed } }
|
||||
let peersRemovedSectionIndices = changes.peersRemovedIndices.map { firstPeerSectionIndex + $0 }
|
||||
let peersInsertedSectionIndices = changes.peersInsertedIndices.map { firstPeerSectionIndex + $0 }
|
||||
|
||||
if isAnyInterfaceFieldAddedOrRemoved || isAnyPeerFieldAddedOrRemoved || !peersRemovedSectionIndices.isEmpty || !peersInsertedSectionIndices.isEmpty {
|
||||
tableView.beginUpdates()
|
||||
if isAnyInterfaceFieldAddedOrRemoved {
|
||||
handleSectionRowsInsertedOrRemoved(fields: TunnelDetailTableViewController.interfaceFields, fieldIsVisible: interfaceFieldIsVisible, section: interfaceSectionIndex, changes: changes.interfaceChanges)
|
||||
}
|
||||
if isAnyPeerFieldAddedOrRemoved {
|
||||
for (peerIndex, peerChanges) in changes.peerChanges {
|
||||
handleSectionRowsInsertedOrRemoved(fields: TunnelDetailTableViewController.peerFields, fieldIsVisible: peerFieldIsVisible[peerIndex], section: firstPeerSectionIndex + peerIndex, changes: peerChanges)
|
||||
}
|
||||
}
|
||||
if !peersRemovedSectionIndices.isEmpty {
|
||||
tableView.deleteSections(IndexSet(peersRemovedSectionIndices), with: .automatic)
|
||||
}
|
||||
if !peersInsertedSectionIndices.isEmpty {
|
||||
tableView.insertSections(IndexSet(peersInsertedSectionIndices), with: .automatic)
|
||||
}
|
||||
self.loadSections()
|
||||
self.loadVisibleFields()
|
||||
tableView.endUpdates()
|
||||
} else {
|
||||
self.loadSections()
|
||||
self.loadVisibleFields()
|
||||
}
|
||||
}
|
||||
|
||||
private func reloadRuntimeConfiguration() {
|
||||
@@ -345,6 +370,8 @@ extension TunnelDetailTableViewController {
|
||||
cell.key = field.localizedUIString
|
||||
if field == .persistentKeepAlive {
|
||||
cell.value = tr(format: "tunnelPeerPersistentKeepaliveValue (%@)", peerData[field])
|
||||
} else if field == .preSharedKey {
|
||||
cell.value = tr("tunnelPeerPresharedKeyEnabled")
|
||||
} else {
|
||||
cell.value = peerData[field]
|
||||
}
|
||||
|
||||
@@ -302,6 +302,8 @@ extension TunnelEditTableViewController {
|
||||
guard let self = self else { return }
|
||||
let removedSectionIndices = self.deletePeer(peer: peerData)
|
||||
let shouldShowExcludePrivateIPs = (self.tunnelViewModel.peersData.count == 1 && self.tunnelViewModel.peersData[0].shouldAllowExcludePrivateIPsControl)
|
||||
|
||||
//swiftlint:disable:next trailing_closure
|
||||
tableView.performBatchUpdates({
|
||||
self.tableView.deleteSections(removedSectionIndices, with: .fade)
|
||||
if shouldShowExcludePrivateIPs {
|
||||
@@ -309,7 +311,6 @@ extension TunnelEditTableViewController {
|
||||
let rowIndexPath = IndexPath(row: row, section: self.interfaceFieldsBySection.count /* First peer section */)
|
||||
self.tableView.insertRows(at: [rowIndexPath], with: .fade)
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -359,9 +360,9 @@ extension TunnelEditTableViewController {
|
||||
cell.value = peerData[field]
|
||||
|
||||
if field == .allowedIPs {
|
||||
let firstInterfaceSection = sections.firstIndex(where: { $0 == .interface })!
|
||||
let interfaceSubSection = interfaceFieldsBySection.firstIndex(where: { $0.contains(.dns) })!
|
||||
let dnsRow = interfaceFieldsBySection[interfaceSubSection].firstIndex(where: { $0 == .dns })!
|
||||
let firstInterfaceSection = sections.firstIndex { $0 == .interface }!
|
||||
let interfaceSubSection = interfaceFieldsBySection.firstIndex { $0.contains(.dns) }!
|
||||
let dnsRow = interfaceFieldsBySection[interfaceSubSection].firstIndex { $0 == .dns }!
|
||||
|
||||
cell.onValueBeingEdited = { [weak self, weak peerData] value in
|
||||
guard let self = self, let peerData = peerData else { return }
|
||||
@@ -419,7 +420,7 @@ extension TunnelEditTableViewController {
|
||||
self.activateOnDemandSetting.isActivateOnDemandEnabled = isOn
|
||||
self.loadSections()
|
||||
|
||||
let section = self.sections.firstIndex(where: { $0 == .onDemand })!
|
||||
let section = self.sections.firstIndex { $0 == .onDemand }!
|
||||
let indexPaths = (1 ..< 4).map { IndexPath(row: $0, section: section) }
|
||||
if isOn {
|
||||
if self.activateOnDemandSetting.activateOnDemandOption == .none {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
||||
|
||||
import Cocoa
|
||||
|
||||
class AppStorePrivacyNotice {
|
||||
// The App Store Review Board does not comprehend the fact that this application
|
||||
// is not a service and does not have any servers of its own. They therefore require
|
||||
// us to give a notice regarding collection of user data using our non-existent
|
||||
// servers. This demand is obviously impossible to fulfill, since it doesn't make sense,
|
||||
// but we do our best here to show something in that category.
|
||||
static func show(from sourceVC: NSViewController?, into tunnelsManager: TunnelsManager, _ callback: @escaping () -> Void) {
|
||||
if tunnelsManager.numberOfTunnels() > 0 {
|
||||
callback()
|
||||
return
|
||||
}
|
||||
let alert = NSAlert()
|
||||
|
||||
alert.messageText = tr("macPrivacyNoticeMessage")
|
||||
alert.informativeText = tr("macPrivacyNoticeInfo")
|
||||
alert.alertStyle = NSAlert.Style.warning
|
||||
if let window = sourceVC?.view.window {
|
||||
alert.beginSheetModal(for: window) { _ in callback() }
|
||||
} else {
|
||||
alert.runModal()
|
||||
callback()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,9 @@ class ImportPanelPresenter {
|
||||
guard let tunnelsManager = tunnelsManager else { return }
|
||||
guard response == .OK else { return }
|
||||
guard let url = openPanel.url else { return }
|
||||
TunnelImporter.importFromFile(url: url, into: tunnelsManager, sourceVC: sourceVC, errorPresenterType: ErrorPresenter.self)
|
||||
AppStorePrivacyNotice.show(from: sourceVC, into: tunnelsManager) {
|
||||
TunnelImporter.importFromFile(url: url, into: tunnelsManager, sourceVC: sourceVC, errorPresenterType: ErrorPresenter.self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,6 @@ class StatusMenu: NSMenu {
|
||||
self.networksMenuItem = networksMenuItem
|
||||
}
|
||||
|
||||
//swiftlint:disable:next cyclomatic_complexity
|
||||
func updateStatusMenuItems(with tunnel: TunnelContainer?) {
|
||||
guard let statusMenuItem = statusMenuItem, let networksMenuItem = networksMenuItem else { return }
|
||||
guard let tunnel = tunnel else {
|
||||
|
||||
@@ -102,7 +102,7 @@ extension ManageTunnelsRootViewController {
|
||||
switch event.charactersIgnoringModifiers {
|
||||
case "n":
|
||||
tunnelsListVC?.handleAddEmptyTunnelAction()
|
||||
case "i":
|
||||
case "o":
|
||||
tunnelsListVC?.handleImportTunnelAction()
|
||||
case "t":
|
||||
tunnelDetailVC?.handleToggleActiveStatusAction()
|
||||
|
||||
@@ -263,7 +263,24 @@ class TunnelDetailTableViewController: NSViewController {
|
||||
|
||||
func applyTunnelConfiguration(tunnelConfiguration: TunnelConfiguration) {
|
||||
// Incorporates changes from tunnelConfiguation. Ignores any changes in peer ordering.
|
||||
func sectionChanged<T>(fields: [T], modelRowsInSection: inout [(isVisible: Bool, modelRow: TableViewModelRow)], tableView: NSTableView, rowOffset: Int, changes: [T: TunnelViewModel.ChangeHandlers.FieldChange]) {
|
||||
|
||||
let tableView = self.tableView
|
||||
|
||||
func handleSectionFieldsModified<T>(fields: [T], modelRowsInSection: [(isVisible: Bool, modelRow: TableViewModelRow)], rowOffset: Int, changes: [T: TunnelViewModel.Changes.FieldChange]) {
|
||||
var modifiedRowIndices = IndexSet()
|
||||
for (index, field) in fields.enumerated() {
|
||||
guard let change = changes[field] else { continue }
|
||||
if case .modified(_) = change {
|
||||
let row = modelRowsInSection[0 ..< index].filter { $0.isVisible }.count
|
||||
modifiedRowIndices.insert(rowOffset + row)
|
||||
}
|
||||
}
|
||||
if !modifiedRowIndices.isEmpty {
|
||||
tableView.reloadData(forRowIndexes: modifiedRowIndices, columnIndexes: IndexSet(integer: 0))
|
||||
}
|
||||
}
|
||||
|
||||
func handleSectionFieldsAddedOrRemoved<T>(fields: [T], modelRowsInSection: inout [(isVisible: Bool, modelRow: TableViewModelRow)], rowOffset: Int, changes: [T: TunnelViewModel.Changes.FieldChange]) {
|
||||
for (index, field) in fields.enumerated() {
|
||||
guard let change = changes[field] else { continue }
|
||||
let row = modelRowsInSection[0 ..< index].filter { $0.isVisible }.count
|
||||
@@ -275,42 +292,54 @@ class TunnelDetailTableViewController: NSViewController {
|
||||
tableView.removeRows(at: IndexSet(integer: rowOffset + row), withAnimation: .effectFade)
|
||||
modelRowsInSection[index].isVisible = false
|
||||
case .modified:
|
||||
tableView.removeRows(at: IndexSet(integer: rowOffset + row), withAnimation: [])
|
||||
tableView.insertRows(at: IndexSet(integer: rowOffset + row), withAnimation: [])
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var isChanged = false
|
||||
let changeHandlers = TunnelViewModel.ChangeHandlers(
|
||||
interfaceChanged: { [weak self] changes in
|
||||
guard let self = self else { return }
|
||||
sectionChanged(fields: TunnelDetailTableViewController.interfaceFields, modelRowsInSection: &self.tableViewModelRowsBySection[0],
|
||||
tableView: self.tableView, rowOffset: 0, changes: changes)
|
||||
isChanged = true
|
||||
},
|
||||
peerChangedAt: { [weak self] peerIndex, changes in
|
||||
guard let self = self else { return }
|
||||
let sectionIndex = 1 + peerIndex
|
||||
let rowOffset = self.tableViewModelRowsBySection[0 ..< sectionIndex].flatMap { $0.filter { $0.isVisible } }.count
|
||||
sectionChanged(fields: TunnelDetailTableViewController.peerFields, modelRowsInSection: &self.tableViewModelRowsBySection[sectionIndex],
|
||||
tableView: self.tableView, rowOffset: rowOffset, changes: changes)
|
||||
isChanged = true
|
||||
},
|
||||
peersRemovedAt: { [weak self] peerIndices in
|
||||
guard let self = self else { return }
|
||||
for peerIndex in peerIndices {
|
||||
let changes = self.tunnelViewModel.applyConfiguration(other: tunnelConfiguration)
|
||||
|
||||
if !changes.interfaceChanges.isEmpty {
|
||||
handleSectionFieldsModified(fields: TunnelDetailTableViewController.interfaceFields,
|
||||
modelRowsInSection: self.tableViewModelRowsBySection[0],
|
||||
rowOffset: 0, changes: changes.interfaceChanges)
|
||||
}
|
||||
for (peerIndex, peerChanges) in changes.peerChanges {
|
||||
let sectionIndex = 1 + peerIndex
|
||||
let rowOffset = self.tableViewModelRowsBySection[0 ..< sectionIndex].flatMap { $0.filter { $0.isVisible } }.count
|
||||
handleSectionFieldsModified(fields: TunnelDetailTableViewController.peerFields,
|
||||
modelRowsInSection: self.tableViewModelRowsBySection[sectionIndex],
|
||||
rowOffset: rowOffset, changes: peerChanges)
|
||||
}
|
||||
|
||||
let isAnyInterfaceFieldAddedOrRemoved = changes.interfaceChanges.contains { $0.value == .added || $0.value == .removed }
|
||||
let isAnyPeerFieldAddedOrRemoved = changes.peerChanges.contains { $0.changes.contains { $0.value == .added || $0.value == .removed } }
|
||||
|
||||
if isAnyInterfaceFieldAddedOrRemoved || isAnyPeerFieldAddedOrRemoved || !changes.peersRemovedIndices.isEmpty || !changes.peersInsertedIndices.isEmpty {
|
||||
tableView.beginUpdates()
|
||||
if isAnyInterfaceFieldAddedOrRemoved {
|
||||
handleSectionFieldsAddedOrRemoved(fields: TunnelDetailTableViewController.interfaceFields,
|
||||
modelRowsInSection: &self.tableViewModelRowsBySection[0],
|
||||
rowOffset: 0, changes: changes.interfaceChanges)
|
||||
}
|
||||
if isAnyPeerFieldAddedOrRemoved {
|
||||
for (peerIndex, peerChanges) in changes.peerChanges {
|
||||
let sectionIndex = 1 + peerIndex
|
||||
let rowOffset = self.tableViewModelRowsBySection[0 ..< sectionIndex].flatMap { $0.filter { $0.isVisible } }.count
|
||||
handleSectionFieldsAddedOrRemoved(fields: TunnelDetailTableViewController.peerFields, modelRowsInSection: &self.tableViewModelRowsBySection[sectionIndex], rowOffset: rowOffset, changes: peerChanges)
|
||||
}
|
||||
}
|
||||
if !changes.peersRemovedIndices.isEmpty {
|
||||
for peerIndex in changes.peersRemovedIndices {
|
||||
let sectionIndex = 1 + peerIndex
|
||||
let rowOffset = self.tableViewModelRowsBySection[0 ..< sectionIndex].flatMap { $0.filter { $0.isVisible } }.count
|
||||
let count = self.tableViewModelRowsBySection[sectionIndex].filter { $0.isVisible }.count
|
||||
self.tableView.removeRows(at: IndexSet(integersIn: rowOffset ..< rowOffset + count), withAnimation: .effectFade)
|
||||
self.tableViewModelRowsBySection.remove(at: sectionIndex)
|
||||
}
|
||||
isChanged = true
|
||||
},
|
||||
peersInsertedAt: { [weak self] peerIndices in
|
||||
guard let self = self else { return }
|
||||
for peerIndex in peerIndices {
|
||||
}
|
||||
if !changes.peersInsertedIndices.isEmpty {
|
||||
for peerIndex in changes.peersInsertedIndices {
|
||||
let peerData = self.tunnelViewModel.peersData[peerIndex]
|
||||
let sectionIndex = 1 + peerIndex
|
||||
let rowOffset = self.tableViewModelRowsBySection[0 ..< sectionIndex].flatMap { $0.filter { $0.isVisible } }.count
|
||||
@@ -322,16 +351,10 @@ class TunnelDetailTableViewController: NSViewController {
|
||||
self.tableView.insertRows(at: IndexSet(integersIn: rowOffset ..< rowOffset + count), withAnimation: .effectFade)
|
||||
self.tableViewModelRowsBySection.insert(modelRowsInSection, at: sectionIndex)
|
||||
}
|
||||
isChanged = true
|
||||
}
|
||||
)
|
||||
|
||||
tableView.beginUpdates()
|
||||
self.tunnelViewModel.applyConfiguration(other: tunnelConfiguration, changeHandlers: changeHandlers)
|
||||
if isChanged {
|
||||
updateTableViewModelRows()
|
||||
tableView.endUpdates()
|
||||
}
|
||||
tableView.endUpdates()
|
||||
}
|
||||
|
||||
private func reloadRuntimeConfiguration() {
|
||||
@@ -382,6 +405,8 @@ extension TunnelDetailTableViewController: NSTableViewDelegate {
|
||||
cell.key = tr(format: "macFieldKey (%@)", localizedKeyString)
|
||||
if field == .persistentKeepAlive {
|
||||
cell.value = tr(format: "tunnelPeerPersistentKeepaliveValue (%@)", peerData[field])
|
||||
} else if field == .preSharedKey {
|
||||
cell.value = tr("tunnelPeerPresharedKeyEnabled")
|
||||
} else {
|
||||
cell.value = peerData[field]
|
||||
}
|
||||
|
||||
@@ -219,14 +219,16 @@ class TunnelEditViewController: NSViewController {
|
||||
}
|
||||
} else {
|
||||
// We're creating a new tunnel
|
||||
tunnelsManager.add(tunnelConfiguration: tunnelConfiguration, activateOnDemandSetting: onDemandSetting) { [weak self] result in
|
||||
if let error = result.error {
|
||||
ErrorPresenter.showErrorAlert(error: error, from: self)
|
||||
return
|
||||
AppStorePrivacyNotice.show(from: self, into: tunnelsManager) { [weak self] in
|
||||
self?.tunnelsManager.add(tunnelConfiguration: tunnelConfiguration, activateOnDemandSetting: onDemandSetting) { [weak self] result in
|
||||
if let error = result.error {
|
||||
ErrorPresenter.showErrorAlert(error: error, from: self)
|
||||
return
|
||||
}
|
||||
let tunnel: TunnelContainer = result.value!
|
||||
self?.dismiss(self)
|
||||
self?.delegate?.tunnelSaved(tunnel: tunnel)
|
||||
}
|
||||
let tunnel: TunnelContainer = result.value!
|
||||
self?.dismiss(self)
|
||||
self?.delegate?.tunnelSaved(tunnel: tunnel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ class TunnelsListTableViewController: NSViewController {
|
||||
let addMenu: NSMenu = {
|
||||
let addMenu = NSMenu(title: "TunnelsListAdd")
|
||||
addMenu.addItem(withTitle: tr("macMenuAddEmptyTunnel"), action: #selector(handleAddEmptyTunnelAction), keyEquivalent: "n")
|
||||
addMenu.addItem(withTitle: tr("macMenuImportTunnels"), action: #selector(handleImportTunnelAction), keyEquivalent: "i")
|
||||
addMenu.addItem(withTitle: tr("macMenuImportTunnels"), action: #selector(handleImportTunnelAction), keyEquivalent: "o")
|
||||
return addMenu
|
||||
}()
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ class ZipArchive {
|
||||
static func unarchive(url: URL, requiredFileExtensions: [String]) throws -> [(fileBaseName: String, contents: Data)] {
|
||||
|
||||
var results = [(fileBaseName: String, contents: Data)]()
|
||||
var requiredFileExtensionsLowercased = requiredFileExtensions.map { $0.lowercased() }
|
||||
|
||||
guard let zipFile = unzOpen64(url.path) else {
|
||||
throw ZipArchiveError.cantOpenInputZipFile
|
||||
@@ -70,7 +71,7 @@ class ZipArchive {
|
||||
let isDirectory = (lastChar == "/" || lastChar == "\\")
|
||||
let fileURL = URL(fileURLWithFileSystemRepresentation: fileNameBuffer, isDirectory: isDirectory, relativeTo: nil)
|
||||
|
||||
if !isDirectory && requiredFileExtensions.contains(fileURL.pathExtension) {
|
||||
if !isDirectory && requiredFileExtensionsLowercased.contains(fileURL.pathExtension.lowercased()) {
|
||||
var unzippedData = Data()
|
||||
var bytesRead: Int32 = 0
|
||||
repeat {
|
||||
|
||||
@@ -17,7 +17,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
networkMonitor?.cancel()
|
||||
}
|
||||
|
||||
//swiftlint:disable:next function_body_length
|
||||
override func startTunnel(options: [String: NSObject]?, completionHandler startTunnelCompletionHandler: @escaping (Error?) -> Void) {
|
||||
let activationAttemptId = options?["activationAttemptId"] as? String
|
||||
let errorNotifier = ErrorNotifier(activationAttemptId: activationAttemptId)
|
||||
|
||||
+1
-1
Submodule wireguard-go updated: c4b43e35a7...f7170e5de2
@@ -0,0 +1,3 @@
|
||||
.cache/
|
||||
.tmp/
|
||||
out/
|
||||
@@ -16,7 +16,7 @@ BUILDDIR ?= $(CONFIGURATION_TEMP_DIR)/wireguard-go-bridge
|
||||
|
||||
UPSTREAM_FILES := $(filter-out %/main.go %/queueconstants.go,$(wildcard ../wireguard-go/*/*.go) $(wildcard ../wireguard-go/*.go)) ../wireguard-go/go.mod ../wireguard-go/go.sum
|
||||
DOWNSTREAM_FILES := $(wildcard src/*.go) $(wildcard src/*/*.go)
|
||||
CFLAGS_PREFIX := $(if $(DEPLOYMENT_TARGET_CLANG_FLAG_NAME),-$(DEPLOYMENT_TARGET_CLANG_FLAG_NAME)=$($(DEPLOYMENT_TARGET_CLANG_ENV_NAME)),) -isysroot $(SDKROOT) -arch
|
||||
CFLAGS_PREFIX := $(if $(DEPLOYMENT_TARGET_CLANG_FLAG_NAME),-$(DEPLOYMENT_TARGET_CLANG_FLAG_NAME)=$($(DEPLOYMENT_TARGET_CLANG_ENV_NAME)),) -Wno-unused-command-line-argument -isysroot $(SDKROOT) -arch
|
||||
GOARCH_arm64 := arm64
|
||||
GOARCH_armv7 := arm
|
||||
GOARCH_x86_64 := amd64
|
||||
@@ -29,7 +29,8 @@ version-header: $(DESTDIR)/wireguard-go-version.h
|
||||
GOBUILDARCH := $(GOARCH_$(shell uname -m))
|
||||
GOBUILDOS := $(shell uname -s | tr '[:upper:]' '[:lower:]')
|
||||
GOBUILDVERSION := 1.11.5
|
||||
GOBUILDTARBALL := https://dl.google.com/go/go$(GOBUILDVERSION).$(GOBUILDOS)-$(GOBUILDARCH).tar.gz
|
||||
GOBUILDTARBALL := go$(GOBUILDVERSION).$(GOBUILDOS)-$(GOBUILDARCH).tar.gz
|
||||
GOBUILDTARBALLURL := https://dl.google.com/go/$(GOBUILDTARBALL)
|
||||
GOBUILDVERSION_NEEDED := go version go$(GOBUILDVERSION) $(GOBUILDOS)/$(GOBUILDARCH)
|
||||
export GOROOT := $(BUILDDIR)/goroot
|
||||
export GOPATH := $(BUILDDIR)/gopath
|
||||
@@ -38,10 +39,14 @@ GOBUILDVERSION_CURRENT := $(shell $(GOROOT)/bin/go version 2>/dev/null)
|
||||
ifneq ($(GOBUILDVERSION_NEEDED),$(GOBUILDVERSION_CURRENT))
|
||||
$(shell rm -f $(GOROOT)/bin/go)
|
||||
endif
|
||||
$(GOROOT)/bin/go:
|
||||
.cache/$(GOBUILDTARBALL):
|
||||
mkdir -p $(dir $@)
|
||||
curl -o $@ $(GOBUILDTARBALLURL) || { rm -f $@; exit 1; }
|
||||
|
||||
$(GOROOT)/bin/go: .cache/$(GOBUILDTARBALL)
|
||||
rm -rf "$(GOROOT)"
|
||||
mkdir -p "$(GOROOT)"
|
||||
curl "$(GOBUILDTARBALL)" | tar -C "$(GOROOT)" --strip-components=1 -xzf - || { rm -rf "$(GOROOT)"; exit 1; }
|
||||
tar -C "$(GOROOT)" --strip-components=1 -xzf - < .cache/$(GOBUILDTARBALL) || { rm -rf "$(GOROOT)"; exit 1; }
|
||||
patch -p1 -f -N -r- -d "$(GOROOT)" < goruntime-boottime-over-monotonic.diff || { rm -rf "$(GOROOT)"; exit 1; }
|
||||
|
||||
$(shell test "$$(cat "$(BUILDDIR)/.gobuildversion" 2>/dev/null)" = "$(GOBUILDVERSION_CURRENT)" || rm -f "$(DESTDIR)/libwg-go.a")
|
||||
@@ -84,6 +89,9 @@ $(DESTDIR)/libwg-go.a: $(foreach ARCH,$(ARCHS),$(BUILDDIR)/libwg-go-$(ARCH).a)
|
||||
clean:
|
||||
rm -rf "$(BUILDDIR)" "$(DESTDIR)/libwg-go.a" "$(DESTDIR)/wireguard-go-version.h"
|
||||
|
||||
distclean: clean
|
||||
rm -rf .cache
|
||||
|
||||
install: build
|
||||
|
||||
.PHONY: clean build version-header install
|
||||
.PHONY: distclean clean build version-header install
|
||||
|
||||
Reference in New Issue
Block a user