Compare commits

...

24 Commits

Author SHA1 Message Date
Jason A. Donenfeld fcca2d4fec macOS: Show privacy notice on adding first tunnel
App store reviewers don't understand that this isn't a service.

Revert this as soon as they come to their senses.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-02-15 01:14:14 +01:00
Jason A. Donenfeld 58181a4d40 Version bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-02-14 23:07:06 +01:00
Jason A. Donenfeld cf816ede13 wireguard-go: bump for ARM64 ChaCha20
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-02-14 12:00:59 +01:00
Jason A. Donenfeld fbac282bdc .mobileconfig: fix formatting
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-02-13 14:31:02 +01:00
Jason A. Donenfeld 61f5e017c8 .mobileconfig: note keychain limitation
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-02-13 14:04:54 +01:00
Roopesh Chander 4547e01283 Preshared key field in the detail view should just say 'enabled'
Signed-off-by: Roopesh Chander <roop@roopc.net>
2019-02-12 19:30:59 +05:30
Roopesh Chander 5792db22a6 Log migration of tunnel configuration
Signed-off-by: Roopesh Chander <roop@roopc.net>
2019-02-12 19:17:32 +05:30
Roopesh Chander 9d5aa1d8fa Document installing WireGuard tunnels using Configuration Profiles
Signed-off-by: Roopesh Chander <roop@roopc.net>
2019-02-12 19:14:53 +05:30
Roopesh Chander 6331b81b5d Migrate when we notice a new tunnel in reload()
Signed-off-by: Roopesh Chander <roop@roopc.net>
2019-02-12 17:43:40 +05:30
Roopesh Chander 77f929789c Don't migrate in asTunnelConfiguration()
It causes problems when installing a tunnel through a
Configuration Profile on macOS and activating it first through
Network Preferences.

Signed-off-by: Roopesh Chander <roop@roopc.net>
2019-02-12 17:37:27 +05:30
Roopesh Chander b5b72b309f Info.plist: Localize with InfoPlist.strings
Signed-off-by: Roopesh Chander <roop@roopc.net>
2019-02-11 16:08:55 +05:30
Roopesh Chander 966fa7909b macOS: Change keyboard shortcut for importing to Cmd+O
Signed-off-by: Roopesh Chander <roop@roopc.net>
2019-02-10 17:55:50 +05:30
Roopesh Chander 115059f2bb macOS: Adapt to the new applyConfiguration API
Signed-off-by: Roopesh Chander <roop@roopc.net>
2019-02-10 03:35:24 +05:30
Roopesh Chander e53c2d4d17 iOS: Rewrite applying runtime configuration
To make scrolling smoother while the fields are modified

Signed-off-by: Roopesh Chander <roop@roopc.net>
2019-02-10 03:35:24 +05:30
Roopesh Chander 0a3a5ee900 Importing: Ignore case in matching file extensions inside zip files
Signed-off-by: Roopesh Chander <roop@roopc.net>
2019-02-09 19:42:50 +05:30
Roopesh Chander 7720307fc9 TunnelsManager: No need to access tunnelConfiguration on status change
Signed-off-by: Roopesh Chander <roop@roopc.net>
2019-02-09 19:42:50 +05:30
Jason A. Donenfeld ea827e2ebd Version bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-02-08 17:32:38 +01:00
Roopesh Chander 91b1734b7a Fix writing of preshared key to config format
Signed-off-by: Roopesh Chander <roop@roopc.net>
2019-02-09 14:57:24 +05:30
Jason A. Donenfeld bac4851e95 Project: don't embed swift binaries into appex
Otherwise we're rejected from the app store.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-02-08 17:26:05 +01:00
Jason A. Donenfeld 0e2556544e Global: fix swiftlint issues
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-02-08 17:07:28 +01:00
Jason A. Donenfeld 2ec51ba8cf wireguard-go-bridge: get rid of nopie warning
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-02-08 16:42:25 +01:00
Jason A. Donenfeld 998bbd73e4 wireguard-go-bridge: Cache go tarballs
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-02-08 16:23:40 +01:00
Jason A. Donenfeld 38a6ba7091 KeyEncoding: rename file to match extension filename style
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-02-08 16:15:10 +01:00
Jason A. Donenfeld 407b367c8d Key: we already do len checking in C
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-02-08 14:39:59 +01:00
27 changed files with 433 additions and 182 deletions
+145
View File
@@ -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
+6 -8
View File
@@ -2,6 +2,11 @@ disabled_rules:
- line_length - line_length
- trailing_whitespace - trailing_whitespace
- todo - todo
- cyclomatic_complexity
- file_length
- type_body_length
- function_body_length
- nesting
opt_in_rules: opt_in_rules:
- empty_count - empty_count
- empty_string - empty_string
@@ -14,14 +19,7 @@ opt_in_rules:
- toggle_bool - toggle_bool
- unneeded_parentheses_in_closure_argument - unneeded_parentheses_in_closure_argument
- unused_import - unused_import
# - trailing_closure - trailing_closure
file_length:
warning: 500
cyclomatic_complexity:
warning: 10
error: 25
function_body_length:
warning: 45
variable_name: variable_name:
min_length: min_length:
warning: 0 warning: 0
@@ -23,9 +23,6 @@ extension Data {
} }
init?(hexKey hexString: String) { init?(hexKey hexString: String) {
if hexString.utf8.count != WG_KEY_LEN_HEX - 1 {
return nil
}
self.init(repeating: 0, count: Int(WG_KEY_LEN)) self.init(repeating: 0, count: Int(WG_KEY_LEN))
if !self.withUnsafeMutableBytes { key_from_hex($0, hexString) } { if !self.withUnsafeMutableBytes { key_from_hex($0, hexString) } {
@@ -48,9 +45,6 @@ extension Data {
} }
init?(base64Key base64String: String) { init?(base64Key base64String: String) {
if base64String.utf8.count != WG_KEY_LEN_BASE64 - 1 {
return nil
}
self.init(repeating: 0, count: Int(WG_KEY_LEN)) self.init(repeating: 0, count: Int(WG_KEY_LEN))
if !self.withUnsafeMutableBytes { key_from_base64($0, base64String) } { if !self.withUnsafeMutableBytes { key_from_base64($0, base64String) } {
@@ -34,17 +34,14 @@ extension NETunnelProviderProtocol {
} }
func asTunnelConfiguration(called name: String? = nil) -> TunnelConfiguration? { func asTunnelConfiguration(called name: String? = nil) -> TunnelConfiguration? {
migrateConfigurationIfNeeded(called: name ?? "unknown") if let passwordReference = passwordReference,
//TODO: in the case where migrateConfigurationIfNeeded is called by the network extension, let config = Keychain.openReference(called: passwordReference) {
// before the app has started, and when there is, in fact, configuration that needs to be return try? TunnelConfiguration(fromWgQuickConfig: config, called: name)
// 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 if let oldConfig = providerConfiguration?["WgQuickConfig"] as? String {
// that generally not available to network extensions? In which case, what should our return try? TunnelConfiguration(fromWgQuickConfig: oldConfig, called: name)
// behavior be? }
return nil
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() { func destroyConfigurationReference() {
@@ -66,6 +63,7 @@ extension NETunnelProviderProtocol {
guard let oldConfig = providerConfiguration?["WgQuickConfig"] as? String else { return false } guard let oldConfig = providerConfiguration?["WgQuickConfig"] as? String else { return false }
providerConfiguration = nil providerConfiguration = nil
guard passwordReference == nil else { return true } guard passwordReference == nil else { return true }
wg_log(.debug, message: "Migrating tunnel configuration '\(name)'")
passwordReference = Keychain.makeReference(containing: oldConfig, called: name) passwordReference = Keychain.makeReference(containing: oldConfig, called: name)
return true return true
} }
@@ -35,7 +35,6 @@ extension TunnelConfiguration {
case multipleEntriesForKey(String) case multipleEntriesForKey(String)
} }
//swiftlint:disable:next function_body_length cyclomatic_complexity
convenience init(fromWgQuickConfig wgQuickConfig: String, called name: String? = nil) throws { convenience init(fromWgQuickConfig wgQuickConfig: String, called name: String? = nil) throws {
var interfaceConfiguration: InterfaceConfiguration? var interfaceConfiguration: InterfaceConfiguration?
var peerConfigurations = [PeerConfiguration]() var peerConfigurations = [PeerConfiguration]()
@@ -149,7 +148,7 @@ extension TunnelConfiguration {
if let publicKey = peer.publicKey.base64Key() { if let publicKey = peer.publicKey.base64Key() {
output.append("PublicKey = \(publicKey)\n") output.append("PublicKey = \(publicKey)\n")
} }
if let preSharedKey = peer.preSharedKey?.base64Key { if let preSharedKey = peer.preSharedKey?.base64Key() {
output.append("PresharedKey = \(preSharedKey)\n") output.append("PresharedKey = \(preSharedKey)\n")
} }
if !peer.allowedIPs.isEmpty { if !peer.allowedIPs.isEmpty {
@@ -167,7 +166,6 @@ extension TunnelConfiguration {
return output return output
} }
//swiftlint:disable:next cyclomatic_complexity
private static func collate(interfaceAttributes attributes: [String: String]) throws -> InterfaceConfiguration { private static func collate(interfaceAttributes attributes: [String: String]) throws -> InterfaceConfiguration {
guard let privateKeyString = attributes["privatekey"] else { guard let privateKeyString = attributes["privatekey"] else {
throw ParseError.interfaceHasNoPrivateKey throw ParseError.interfaceHasNoPrivateKey
@@ -211,7 +209,6 @@ extension TunnelConfiguration {
return interface return interface
} }
//swiftlint:disable:next cyclomatic_complexity
private static func collate(peerAttributes attributes: [String: String]) throws -> PeerConfiguration { private static func collate(peerAttributes attributes: [String: String]) throws -> PeerConfiguration {
guard let publicKeyString = attributes["publickey"] else { guard let publicKeyString = attributes["publickey"] else {
throw ParseError.peerHasNoPublicKey throw ParseError.peerHasNoPublicKey
+38 -14
View File
@@ -28,19 +28,22 @@
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 */; };
6B586C51220CACB600427C51 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6FF4AC462120B9E0002C96EB /* NetworkExtension.framework */; }; 6B586C53220CBA6D00427C51 /* Data+KeyEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Data+KeyEncoding.swift */; };
6B586C53220CBA6D00427C51 /* Key.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Key.swift */; }; 6B586C54220CBA6D00427C51 /* Data+KeyEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Data+KeyEncoding.swift */; };
6B586C54220CBA6D00427C51 /* Key.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Key.swift */; }; 6B586C55220CBA6D00427C51 /* Data+KeyEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Data+KeyEncoding.swift */; };
6B586C55220CBA6D00427C51 /* Key.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Key.swift */; }; 6B586C56220CBA6D00427C51 /* Data+KeyEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Data+KeyEncoding.swift */; };
6B586C56220CBA6D00427C51 /* Key.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B586C52220CBA6D00427C51 /* Key.swift */; };
6B5C5E27220A48D30024272E /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5C5E26220A48D30024272E /* Keychain.swift */; }; 6B5C5E27220A48D30024272E /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5C5E26220A48D30024272E /* Keychain.swift */; };
6B5C5E28220A48D30024272E /* 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 */; }; 6B5C5E29220A48D30024272E /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5C5E26220A48D30024272E /* Keychain.swift */; };
6B5C5E2A220A48D30024272E /* 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 */; }; 6B62E45F220A6FA900EF34A6 /* PrivateDataConfirmation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B62E45E220A6FA900EF34A6 /* PrivateDataConfirmation.swift */; };
6B62E460220A6FA900EF34A6 /* 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 */; }; 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 */; };
6BAC16E6221634B300A5FB78 /* AppStorePrivacyNotice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BAC16E42216324B00A5FB78 /* AppStorePrivacyNotice.swift */; };
6BD5C97B220D1AE200784E08 /* key.c in Sources */ = {isa = PBXBuildFile; fileRef = 6BD5C979220D1AE100784E08 /* key.c */; }; 6BD5C97B220D1AE200784E08 /* key.c in Sources */ = {isa = PBXBuildFile; fileRef = 6BD5C979220D1AE100784E08 /* key.c */; };
6BD5C97C220D1AE200784E08 /* 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 */; }; 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 */; }; 6F6899A62180447E0012E523 /* x25519.c in Sources */ = {isa = PBXBuildFile; fileRef = 6F6899A52180447E0012E523 /* x25519.c */; };
6F6899A8218044FC0012E523 /* Curve25519.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F6899A7218044FC0012E523 /* Curve25519.swift */; }; 6F6899A8218044FC0012E523 /* Curve25519.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F6899A7218044FC0012E523 /* Curve25519.swift */; };
6F693A562179E556008551C1 /* Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F693A552179E556008551C1 /* Endpoint.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 */; }; 6F7774E1217181B1006A79B3 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774DF217181B1006A79B3 /* MainViewController.swift */; };
6F7774E2217181B1006A79B3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774E0217181B1006A79B3 /* AppDelegate.swift */; }; 6F7774E2217181B1006A79B3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774E0217181B1006A79B3 /* AppDelegate.swift */; };
6F7774E421718281006A79B3 /* TunnelsListTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774E321718281006A79B3 /* TunnelsListTableViewController.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 */; }; 6FB1BDB121D4F55700A991BF /* PacketTunnelSettingsGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5D0C472183C6A3000F85AD /* PacketTunnelSettingsGenerator.swift */; };
6FB1BDB221D4F55700A991BF /* DNSResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5D0C1421832391000F85AD /* DNSResolver.swift */; }; 6FB1BDB221D4F55700A991BF /* DNSResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5D0C1421832391000F85AD /* DNSResolver.swift */; };
6FB1BDB321D4F55700A991BF /* ErrorNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5D9F21958ECC0001E2F7 /* ErrorNotifier.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 */; }; 6FB1BDBB21D50F0200A991BF /* Localizable.strings in Sources */ = {isa = PBXBuildFile; fileRef = 6FE1765421C90BBE002690EA /* Localizable.strings */; };
6FB1BDBC21D50F0200A991BF /* ringlogger.c in Sources */ = {isa = PBXBuildFile; fileRef = 6FF3526C21C23F960008484E /* ringlogger.c */; }; 6FB1BDBC21D50F0200A991BF /* ringlogger.c in Sources */ = {isa = PBXBuildFile; fileRef = 6FF3526C21C23F960008484E /* ringlogger.c */; };
6FB1BDBD21D50F0200A991BF /* ringlogger.h in Sources */ = {isa = PBXBuildFile; fileRef = 6FF3526B21C23F960008484E /* ringlogger.h */; }; 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>"; }; 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>"; };
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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 6F7774E321718281006A79B3 /* TunnelsListTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TunnelsListTableViewController.swift; sourceTree = "<group>"; };
@@ -348,8 +354,8 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
6B5CA6B1220DE4E900F126CF /* NetworkExtension.framework in Frameworks */,
6FDEF7E421846C1A00D8FBF6 /* libwg-go.a in Frameworks */, 6FDEF7E421846C1A00D8FBF6 /* libwg-go.a in Frameworks */,
6B586C51220CACB600427C51 /* NetworkExtension.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -365,8 +371,8 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
6B5CA6B2220DE4F400F126CF /* NetworkExtension.framework in Frameworks */,
6FB1BDA121D4E00A00A991BF /* libwg-go.a in Frameworks */, 6FB1BDA121D4E00A00A991BF /* libwg-go.a in Frameworks */,
6FB1BDB721D4F8B800A991BF /* NetworkExtension.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -374,6 +380,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
6B653B86220DE2960050E69C /* NetworkExtension.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -501,7 +508,7 @@
6F628C3E217F3413003482A3 /* DNSServer.swift */, 6F628C3E217F3413003482A3 /* DNSServer.swift */,
5FF7B96121CC95DE00A7DD74 /* InterfaceConfiguration.swift */, 5FF7B96121CC95DE00A7DD74 /* InterfaceConfiguration.swift */,
5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */, 5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */,
6B586C52220CBA6D00427C51 /* Key.swift */, 6B586C52220CBA6D00427C51 /* Data+KeyEncoding.swift */,
); );
path = Model; path = Model;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -556,6 +563,7 @@
6F4DD16721DA552B00690EAE /* NSTableView+Reuse.swift */, 6F4DD16721DA552B00690EAE /* NSTableView+Reuse.swift */,
5F52D0BE21E3788900283CEA /* NSColor+Hex.swift */, 5F52D0BE21E3788900283CEA /* NSColor+Hex.swift */,
6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */, 6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */,
6BAC16E42216324B00A5FB78 /* AppStorePrivacyNotice.swift */,
); );
path = macOS; path = macOS;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -617,6 +625,7 @@
6FF4AC0B211EC46F002C96EB = { 6FF4AC0B211EC46F002C96EB = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
6F70E20C221058DF008BDFB4 /* InfoPlist.strings */,
6FE1765421C90BBE002690EA /* Localizable.strings */, 6FE1765421C90BBE002690EA /* Localizable.strings */,
6F5D0C432183B4A4000F85AD /* Shared */, 6F5D0C432183B4A4000F85AD /* Shared */,
6FF4AC16211EC46F002C96EB /* WireGuard */, 6FF4AC16211EC46F002C96EB /* WireGuard */,
@@ -872,6 +881,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
6FB1BD6221D2607E00A991BF /* Assets.xcassets in Resources */, 6FB1BD6221D2607E00A991BF /* Assets.xcassets in Resources */,
6F70E20F221058E1008BDFB4 /* InfoPlist.strings in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -887,6 +897,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
6F919ED9218C65C50023B400 /* wireguard_doc_logo_22x29.png in Resources */, 6F919ED9218C65C50023B400 /* wireguard_doc_logo_22x29.png in Resources */,
6F70E20E221058E1008BDFB4 /* InfoPlist.strings in Resources */,
6FE1765621C90BBE002690EA /* Localizable.strings in Resources */, 6FE1765621C90BBE002690EA /* Localizable.strings in Resources */,
6FF4AC22211EC472002C96EB /* LaunchScreen.storyboard in Resources */, 6FF4AC22211EC472002C96EB /* LaunchScreen.storyboard in Resources */,
6F919EDA218C65C50023B400 /* wireguard_doc_logo_44x58.png in Resources */, 6F919EDA218C65C50023B400 /* wireguard_doc_logo_44x58.png in Resources */,
@@ -1101,7 +1112,7 @@
5FF7B96621CC95FA00A7DD74 /* PeerConfiguration.swift in Sources */, 5FF7B96621CC95FA00A7DD74 /* PeerConfiguration.swift in Sources */,
5F9696AE21CD6F72008063FE /* String+ArrayConversion.swift in Sources */, 5F9696AE21CD6F72008063FE /* String+ArrayConversion.swift in Sources */,
6FFA5D8F2194370D0001E2F7 /* IPAddressRange.swift in Sources */, 6FFA5D8F2194370D0001E2F7 /* IPAddressRange.swift in Sources */,
6B586C54220CBA6D00427C51 /* Key.swift in Sources */, 6B586C54220CBA6D00427C51 /* Data+KeyEncoding.swift in Sources */,
6FFA5D902194370D0001E2F7 /* Endpoint.swift in Sources */, 6FFA5D902194370D0001E2F7 /* Endpoint.swift in Sources */,
5FF7B96321CC95DE00A7DD74 /* InterfaceConfiguration.swift in Sources */, 5FF7B96321CC95DE00A7DD74 /* InterfaceConfiguration.swift in Sources */,
6FFA5D9321943BC90001E2F7 /* DNSResolver.swift in Sources */, 6FFA5D9321943BC90001E2F7 /* DNSResolver.swift in Sources */,
@@ -1146,8 +1157,9 @@
6FCD99B121E0EDA900BA4C82 /* TunnelEditViewController.swift in Sources */, 6FCD99B121E0EDA900BA4C82 /* TunnelEditViewController.swift in Sources */,
6FB1BDCA21D50F1700A991BF /* x25519.c in Sources */, 6FB1BDCA21D50F1700A991BF /* x25519.c in Sources */,
6FB1BDCB21D50F1700A991BF /* Curve25519.swift in Sources */, 6FB1BDCB21D50F1700A991BF /* Curve25519.swift in Sources */,
6B586C55220CBA6D00427C51 /* Key.swift in Sources */, 6B586C55220CBA6D00427C51 /* Data+KeyEncoding.swift in Sources */,
6F9B582921E8D6D100544D02 /* PopupRow.swift in Sources */, 6F9B582921E8D6D100544D02 /* PopupRow.swift in Sources */,
6BAC16E6221634B300A5FB78 /* AppStorePrivacyNotice.swift in Sources */,
6FB1BDBB21D50F0200A991BF /* Localizable.strings in Sources */, 6FB1BDBB21D50F0200A991BF /* Localizable.strings in Sources */,
6FB1BDBC21D50F0200A991BF /* ringlogger.c in Sources */, 6FB1BDBC21D50F0200A991BF /* ringlogger.c in Sources */,
6FB1BDBD21D50F0200A991BF /* ringlogger.h in Sources */, 6FB1BDBD21D50F0200A991BF /* ringlogger.h in Sources */,
@@ -1193,7 +1205,7 @@
6FB1BDA621D4F53300A991BF /* NETunnelProviderProtocol+Extension.swift in Sources */, 6FB1BDA621D4F53300A991BF /* NETunnelProviderProtocol+Extension.swift in Sources */,
6FB1BDA721D4F53300A991BF /* String+ArrayConversion.swift in Sources */, 6FB1BDA721D4F53300A991BF /* String+ArrayConversion.swift in Sources */,
6FB1BDA921D4F53300A991BF /* TunnelConfiguration.swift in Sources */, 6FB1BDA921D4F53300A991BF /* TunnelConfiguration.swift in Sources */,
6B586C56220CBA6D00427C51 /* Key.swift in Sources */, 6B586C56220CBA6D00427C51 /* Data+KeyEncoding.swift in Sources */,
6FB1BDAA21D4F53300A991BF /* IPAddressRange.swift in Sources */, 6FB1BDAA21D4F53300A991BF /* IPAddressRange.swift in Sources */,
6FB1BDAB21D4F53300A991BF /* Endpoint.swift in Sources */, 6FB1BDAB21D4F53300A991BF /* Endpoint.swift in Sources */,
6FB1BDAC21D4F53300A991BF /* DNSServer.swift in Sources */, 6FB1BDAC21D4F53300A991BF /* DNSServer.swift in Sources */,
@@ -1216,7 +1228,7 @@
5F45417D21C1B23600994C13 /* UITableViewCell+Reuse.swift in Sources */, 5F45417D21C1B23600994C13 /* UITableViewCell+Reuse.swift in Sources */,
5F45419221C2D55800994C13 /* CheckmarkCell.swift in Sources */, 5F45419221C2D55800994C13 /* CheckmarkCell.swift in Sources */,
6FE254FF219C60290028284D /* ZipExporter.swift in Sources */, 6FE254FF219C60290028284D /* ZipExporter.swift in Sources */,
6B586C53220CBA6D00427C51 /* Key.swift in Sources */, 6B586C53220CBA6D00427C51 /* Data+KeyEncoding.swift in Sources */,
6F693A562179E556008551C1 /* Endpoint.swift in Sources */, 6F693A562179E556008551C1 /* Endpoint.swift in Sources */,
6FDEF7E62185EFB200D8FBF6 /* QRScanViewController.swift in Sources */, 6FDEF7E62185EFB200D8FBF6 /* QRScanViewController.swift in Sources */,
6FFA5D952194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift in Sources */, 6FFA5D952194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift in Sources */,
@@ -1289,6 +1301,14 @@
/* End PBXTargetDependency section */ /* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */ /* Begin PBXVariantGroup section */
6F70E20C221058DF008BDFB4 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
6F70E20D221058DF008BDFB4 /* Base */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
6FE1765421C90BBE002690EA /* Localizable.strings */ = { 6FE1765421C90BBE002690EA /* Localizable.strings */ = {
isa = PBXVariantGroup; isa = PBXVariantGroup;
children = ( children = (
@@ -1311,6 +1331,7 @@
6F5D0C23218352EF000F85AD /* Debug */ = { 6F5D0C23218352EF000F85AD /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = WireGuardNetworkExtension/WireGuardNetworkExtension_iOS.entitlements; CODE_SIGN_ENTITLEMENTS = WireGuardNetworkExtension/WireGuardNetworkExtension_iOS.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "iPhone Developer";
@@ -1332,6 +1353,7 @@
6F5D0C24218352EF000F85AD /* Release */ = { 6F5D0C24218352EF000F85AD /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = WireGuardNetworkExtension/WireGuardNetworkExtension_iOS.entitlements; CODE_SIGN_ENTITLEMENTS = WireGuardNetworkExtension/WireGuardNetworkExtension_iOS.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "iPhone Developer";
@@ -1391,6 +1413,7 @@
6FB1BD9A21D4BFE700A991BF /* Debug */ = { 6FB1BD9A21D4BFE700A991BF /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
CODE_SIGN_ENTITLEMENTS = WireGuardNetworkExtension/WireGuardNetworkExtension_macOS.entitlements; CODE_SIGN_ENTITLEMENTS = WireGuardNetworkExtension/WireGuardNetworkExtension_macOS.entitlements;
CODE_SIGN_IDENTITY = "Mac Developer"; CODE_SIGN_IDENTITY = "Mac Developer";
INFOPLIST_FILE = WireGuardNetworkExtension/Info.plist; INFOPLIST_FILE = WireGuardNetworkExtension/Info.plist;
@@ -1411,6 +1434,7 @@
6FB1BD9B21D4BFE700A991BF /* Release */ = { 6FB1BD9B21D4BFE700A991BF /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
CODE_SIGN_ENTITLEMENTS = WireGuardNetworkExtension/WireGuardNetworkExtension_macOS.entitlements; CODE_SIGN_ENTITLEMENTS = WireGuardNetworkExtension/WireGuardNetworkExtension_macOS.entitlements;
CODE_SIGN_IDENTITY = "Mac Developer"; CODE_SIGN_IDENTITY = "Mac Developer";
INFOPLIST_FILE = WireGuardNetworkExtension/Info.plist; 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"; "tunnelHandshakeTimestampHours hh:mm:ss (%@)" = "%@ hours";
"tunnelHandshakeTimestampMinutes mm:ss (%@)" = "%@ minutes"; "tunnelHandshakeTimestampMinutes mm:ss (%@)" = "%@ minutes";
"tunnelPeerPresharedKeyEnabled" = "enabled";
// Error alerts while creating / editing a tunnel configuration // Error alerts while creating / editing a tunnel configuration
/* Alert title for error in the interface data */ /* Alert title for error in the interface data */
@@ -331,3 +333,5 @@
"macAppExitingWithActiveTunnelMessage" = "WireGuard is exiting with an active tunnel"; "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."; "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 -1
View File
@@ -1,2 +1,2 @@
VERSION_NAME = 0.0.20190207 VERSION_NAME = 0.0.20190207
VERSION_ID = 1 VERSION_ID = 3
@@ -4,7 +4,6 @@
import Foundation import Foundation
extension TunnelConfiguration { extension TunnelConfiguration {
//swiftlint:disable:next function_body_length cyclomatic_complexity
convenience init(fromUapiConfig uapiConfig: String, basedOn base: TunnelConfiguration? = nil) throws { convenience init(fromUapiConfig uapiConfig: String, basedOn base: TunnelConfiguration? = nil) throws {
var interfaceConfiguration: InterfaceConfiguration? var interfaceConfiguration: InterfaceConfiguration?
var peerConfigurations = [PeerConfiguration]() var peerConfigurations = [PeerConfiguration]()
@@ -103,7 +102,6 @@ extension TunnelConfiguration {
return interface return interface
} }
//swiftlint:disable:next cyclomatic_complexity
private static func collate(peerAttributes attributes: [String: String]) throws -> PeerConfiguration { private static func collate(peerAttributes attributes: [String: String]) throws -> PeerConfiguration {
guard let publicKeyString = attributes["public_key"] else { guard let publicKeyString = attributes["public_key"] else {
throw ParseError.peerHasNoPublicKey throw ParseError.peerHasNoPublicKey
@@ -83,6 +83,11 @@ class TunnelsManager {
matchingTunnel.refreshStatus() matchingTunnel.refreshStatus()
} else { } else {
// Tunnel was added outside the app // 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) let tunnel = TunnelContainer(tunnel: loadedTunnelProvider)
self.tunnels.append(tunnel) self.tunnels.append(tunnel)
self.tunnels.sort { $0.name < $1.name } self.tunnels.sort { $0.name < $1.name }
@@ -313,11 +318,7 @@ class TunnelsManager {
guard let self = self, guard let self = self,
let session = statusChangeNotification.object as? NETunnelProviderSession, let session = statusChangeNotification.object as? NETunnelProviderSession,
let tunnelProvider = session.manager as? NETunnelProviderManager, let tunnelProvider = session.manager as? NETunnelProviderManager,
let tunnelConfiguration = tunnelProvider.tunnelConfiguration, let tunnel = self.tunnels.first(where: { $0.tunnelProvider == tunnelProvider }) else { return }
let tunnel = self.tunnels.first(where: { $0.tunnelConfiguration == tunnelConfiguration }) else { return }
if tunnel.tunnelProvider != tunnelProvider {
return
}
wg_log(.debug, message: "Tunnel '\(tunnel.name)' connection status changed to '\(tunnel.tunnelProvider.connection.status)'") 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 isActivateOnDemandEnabled = tunnelProvider.isOnDemandEnabled
} }
//swiftlint:disable:next function_body_length
fileprivate func startActivation(recursionCount: UInt = 0, lastError: Error? = nil, activationDelegate: TunnelsManagerActivationDelegate?) { fileprivate func startActivation(recursionCount: UInt = 0, lastError: Error? = nil, activationDelegate: TunnelsManagerActivationDelegate?) {
if recursionCount >= 8 { if recursionCount >= 8 {
wg_log(.error, message: "startActivation: Failed after 8 attempts. Giving up with \(lastError!)") wg_log(.error, message: "startActivation: Failed after 8 attempts. Giving up with \(lastError!)")
@@ -532,6 +532,7 @@ extension NETunnelProviderManager {
} }
return config return config
} }
func setTunnelConfiguration(_ tunnelConfiguration: TunnelConfiguration) { func setTunnelConfiguration(_ tunnelConfiguration: TunnelConfiguration) {
protocolConfiguration = NETunnelProviderProtocol(tunnelConfiguration: tunnelConfiguration, previouslyFrom: protocolConfiguration) protocolConfiguration = NETunnelProviderProtocol(tunnelConfiguration: tunnelConfiguration, previouslyFrom: protocolConfiguration)
localizedDescription = tunnelConfiguration.name localizedDescription = tunnelConfiguration.name
+26 -37
View File
@@ -3,7 +3,6 @@
import Foundation import Foundation
//swiftlint:disable:next type_body_length
class TunnelViewModel { class TunnelViewModel {
enum InterfaceField: CaseIterable { enum InterfaceField: CaseIterable {
@@ -68,16 +67,17 @@ class TunnelViewModel {
static let keyLengthInBase64 = 44 static let keyLengthInBase64 = 44
struct ChangeHandlers { struct Changes {
enum FieldChange { enum FieldChange: Equatable {
case added case added
case removed case removed
case modified case modified(newValue: String)
} }
var interfaceChanged: ([InterfaceField: FieldChange]) -> Void
var peerChangedAt: (Int, [PeerField: FieldChange]) -> Void var interfaceChanges: [InterfaceField: FieldChange]
var peersRemovedAt: ([Int]) -> Void var peerChanges: [(peerIndex: Int, changes: [PeerField: FieldChange])]
var peersInsertedAt: ([Int]) -> Void var peersRemovedIndices: [Int]
var peersInsertedIndices: [Int]
} }
class InterfaceData { class InterfaceData {
@@ -141,7 +141,6 @@ class TunnelViewModel {
return scratchpad return scratchpad
} }
//swiftlint:disable:next cyclomatic_complexity function_body_length
func save() -> SaveResult<(String, InterfaceConfiguration)> { func save() -> SaveResult<(String, InterfaceConfiguration)> {
if let config = validatedConfiguration, let name = validatedName { if let config = validatedConfiguration, let name = validatedName {
return .saved((name, config)) 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 { if scratchpad.isEmpty {
populateScratchpad() populateScratchpad()
} }
let otherScratchPad = InterfaceData.createScratchPad(from: other, name: otherName) let otherScratchPad = InterfaceData.createScratchPad(from: other, name: otherName)
var changes = [InterfaceField: ChangeHandlers.FieldChange]() var changes = [InterfaceField: Changes.FieldChange]()
for field in InterfaceField.allCases { for field in InterfaceField.allCases {
switch (scratchpad[field] ?? "", otherScratchPad[field] ?? "") { switch (scratchpad[field] ?? "", otherScratchPad[field] ?? "") {
case ("", ""): case ("", ""):
@@ -234,14 +233,12 @@ class TunnelViewModel {
changes[field] = .removed changes[field] = .removed
case (let this, let other): case (let this, let other):
if this != other { if this != other {
changes[field] = .modified changes[field] = .modified(newValue: other)
} }
} }
} }
scratchpad = otherScratchPad scratchpad = otherScratchPad
if !changes.isEmpty { return changes
changeHandler(changes)
}
} }
} }
@@ -327,7 +324,6 @@ class TunnelViewModel {
return scratchpad return scratchpad
} }
//swiftlint:disable:next cyclomatic_complexity
func save() -> SaveResult<PeerConfiguration> { func save() -> SaveResult<PeerConfiguration> {
if let validatedConfiguration = validatedConfiguration { if let validatedConfiguration = validatedConfiguration {
return .saved(validatedConfiguration) return .saved(validatedConfiguration)
@@ -443,12 +439,12 @@ class TunnelViewModel {
excludePrivateIPsValue = isOn excludePrivateIPsValue = isOn
} }
func applyConfiguration(other: PeerConfiguration, peerIndex: Int, changeHandler: (Int, [PeerField: ChangeHandlers.FieldChange]) -> Void) { func applyConfiguration(other: PeerConfiguration) -> [PeerField: Changes.FieldChange] {
if scratchpad.isEmpty { if scratchpad.isEmpty {
populateScratchpad() populateScratchpad()
} }
let otherScratchPad = PeerData.createScratchPad(from: other) let otherScratchPad = PeerData.createScratchPad(from: other)
var changes = [PeerField: ChangeHandlers.FieldChange]() var changes = [PeerField: Changes.FieldChange]()
for field in PeerField.allCases { for field in PeerField.allCases {
switch (scratchpad[field] ?? "", otherScratchPad[field] ?? "") { switch (scratchpad[field] ?? "", otherScratchPad[field] ?? "") {
case ("", ""): case ("", ""):
@@ -459,14 +455,12 @@ class TunnelViewModel {
changes[field] = .removed changes[field] = .removed
case (let this, let other): case (let this, let other):
if this != other { if this != other {
changes[field] = .modified changes[field] = .modified(newValue: other)
} }
} }
} }
scratchpad = otherScratchPad scratchpad = otherScratchPad
if !changes.isEmpty { return changes
changeHandler(peerIndex, 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. // 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 { for otherPeer in other.peers {
if let peersDataIndex = peersData.firstIndex(where: { $0.publicKey == otherPeer.publicKey }) { if let peersDataIndex = peersData.firstIndex(where: { $0.publicKey == otherPeer.publicKey }) {
let peerData = peersData[peersDataIndex] 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) peersData.remove(at: index)
} }
} }
if !removedPeerIndices.isEmpty {
changeHandlers.peersRemovedAt(removedPeerIndices)
}
var addedPeerIndices = [Int]() var addedPeerIndices = [Int]()
for otherPeer in other.peers { for otherPeer in other.peers {
@@ -588,15 +578,14 @@ class TunnelViewModel {
peersData.append(peerData) peersData.append(peerData)
} }
} }
if !addedPeerIndices.isEmpty {
changeHandlers.peersInsertedAt(addedPeerIndices)
}
for (index, peer) in peersData.enumerated() { for (index, peer) in peersData.enumerated() {
peer.index = index peer.index = index
peer.numberOfPeers = peersData.count peer.numberOfPeers = peersData.count
peer.updateExcludePrivateIPsFieldState() peer.updateExcludePrivateIPsFieldState()
} }
return Changes(interfaceChanges: interfaceChanges, peerChanges: peerChanges, peersRemovedIndices: removedPeerIndices, peersInsertedIndices: addedPeerIndices)
} }
} }
+2 -2
View File
@@ -77,7 +77,7 @@
<key>LSSupportsOpeningDocumentsInPlace</key> <key>LSSupportsOpeningDocumentsInPlace</key>
<false/> <false/>
<key>NSCameraUsageDescription</key> <key>NSCameraUsageDescription</key>
<string>Camera is used for scanning QR codes for importing WireGuard configurations</string> <string>Localized</string>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>LaunchScreen</string> <string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key> <key>UIRequiredDeviceCapabilities</key>
@@ -123,7 +123,7 @@
</dict> </dict>
</array> </array>
<key>NSFaceIDUsageDescription</key> <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> <key>com.wireguard.ios.app_group_id</key>
<string>group.$(APP_ID_IOS)</string> <string>group.$(APP_ID_IOS)</string>
</dict> </dict>
@@ -147,21 +147,32 @@ class TunnelDetailTableViewController: UITableViewController {
// Incorporates changes from tunnelConfiguation. Ignores any changes in peer ordering. // Incorporates changes from tunnelConfiguation. Ignores any changes in peer ordering.
guard let tableView = self.tableView else { return } guard let tableView = self.tableView else { return }
let sections = self.sections 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 let firstPeerSectionIndex = interfaceSectionIndex + 1
var interfaceFieldIsVisible = self.interfaceFieldIsVisible var interfaceFieldIsVisible = self.interfaceFieldIsVisible
var peerFieldIsVisible = self.peerFieldIsVisible 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 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]() var removedIndexPaths = [IndexPath]()
for (index, field) in fields.enumerated().reversed() where changes[field] == .removed { for (index, field) in fields.enumerated().reversed() where changes[field] == .removed {
@@ -184,30 +195,44 @@ class TunnelDetailTableViewController: UITableViewController {
} }
} }
let changeHandlers = TunnelViewModel.ChangeHandlers( let changes = self.tunnelViewModel.applyConfiguration(other: tunnelConfiguration)
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)
}
)
tableView.beginUpdates() if !changes.interfaceChanges.isEmpty {
self.tunnelViewModel.applyConfiguration(other: tunnelConfiguration, changeHandlers: changeHandlers) handleSectionFieldsModified(fields: TunnelDetailTableViewController.interfaceFields, fieldIsVisible: interfaceFieldIsVisible,
self.loadSections() section: interfaceSectionIndex, changes: changes.interfaceChanges)
self.loadVisibleFields() }
tableView.endUpdates() 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() { private func reloadRuntimeConfiguration() {
@@ -345,6 +370,8 @@ extension TunnelDetailTableViewController {
cell.key = field.localizedUIString cell.key = field.localizedUIString
if field == .persistentKeepAlive { if field == .persistentKeepAlive {
cell.value = tr(format: "tunnelPeerPersistentKeepaliveValue (%@)", peerData[field]) cell.value = tr(format: "tunnelPeerPersistentKeepaliveValue (%@)", peerData[field])
} else if field == .preSharedKey {
cell.value = tr("tunnelPeerPresharedKeyEnabled")
} else { } else {
cell.value = peerData[field] cell.value = peerData[field]
} }
@@ -302,6 +302,8 @@ extension TunnelEditTableViewController {
guard let self = self else { return } guard let self = self else { return }
let removedSectionIndices = self.deletePeer(peer: peerData) let removedSectionIndices = self.deletePeer(peer: peerData)
let shouldShowExcludePrivateIPs = (self.tunnelViewModel.peersData.count == 1 && self.tunnelViewModel.peersData[0].shouldAllowExcludePrivateIPsControl) let shouldShowExcludePrivateIPs = (self.tunnelViewModel.peersData.count == 1 && self.tunnelViewModel.peersData[0].shouldAllowExcludePrivateIPsControl)
//swiftlint:disable:next trailing_closure
tableView.performBatchUpdates({ tableView.performBatchUpdates({
self.tableView.deleteSections(removedSectionIndices, with: .fade) self.tableView.deleteSections(removedSectionIndices, with: .fade)
if shouldShowExcludePrivateIPs { if shouldShowExcludePrivateIPs {
@@ -309,7 +311,6 @@ extension TunnelEditTableViewController {
let rowIndexPath = IndexPath(row: row, section: self.interfaceFieldsBySection.count /* First peer section */) let rowIndexPath = IndexPath(row: row, section: self.interfaceFieldsBySection.count /* First peer section */)
self.tableView.insertRows(at: [rowIndexPath], with: .fade) self.tableView.insertRows(at: [rowIndexPath], with: .fade)
} }
} }
}) })
} }
@@ -359,9 +360,9 @@ extension TunnelEditTableViewController {
cell.value = peerData[field] cell.value = peerData[field]
if field == .allowedIPs { if field == .allowedIPs {
let firstInterfaceSection = sections.firstIndex(where: { $0 == .interface })! let firstInterfaceSection = sections.firstIndex { $0 == .interface }!
let interfaceSubSection = interfaceFieldsBySection.firstIndex(where: { $0.contains(.dns) })! let interfaceSubSection = interfaceFieldsBySection.firstIndex { $0.contains(.dns) }!
let dnsRow = interfaceFieldsBySection[interfaceSubSection].firstIndex(where: { $0 == .dns })! let dnsRow = interfaceFieldsBySection[interfaceSubSection].firstIndex { $0 == .dns }!
cell.onValueBeingEdited = { [weak self, weak peerData] value in cell.onValueBeingEdited = { [weak self, weak peerData] value in
guard let self = self, let peerData = peerData else { return } guard let self = self, let peerData = peerData else { return }
@@ -419,7 +420,7 @@ extension TunnelEditTableViewController {
self.activateOnDemandSetting.isActivateOnDemandEnabled = isOn self.activateOnDemandSetting.isActivateOnDemandEnabled = isOn
self.loadSections() 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) } let indexPaths = (1 ..< 4).map { IndexPath(row: $0, section: section) }
if isOn { if isOn {
if self.activateOnDemandSetting.activateOnDemandOption == .none { 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 let tunnelsManager = tunnelsManager else { return }
guard response == .OK else { return } guard response == .OK else { return }
guard let url = openPanel.url 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 self.networksMenuItem = networksMenuItem
} }
//swiftlint:disable:next cyclomatic_complexity
func updateStatusMenuItems(with tunnel: TunnelContainer?) { func updateStatusMenuItems(with tunnel: TunnelContainer?) {
guard let statusMenuItem = statusMenuItem, let networksMenuItem = networksMenuItem else { return } guard let statusMenuItem = statusMenuItem, let networksMenuItem = networksMenuItem else { return }
guard let tunnel = tunnel else { guard let tunnel = tunnel else {
@@ -102,7 +102,7 @@ extension ManageTunnelsRootViewController {
switch event.charactersIgnoringModifiers { switch event.charactersIgnoringModifiers {
case "n": case "n":
tunnelsListVC?.handleAddEmptyTunnelAction() tunnelsListVC?.handleAddEmptyTunnelAction()
case "i": case "o":
tunnelsListVC?.handleImportTunnelAction() tunnelsListVC?.handleImportTunnelAction()
case "t": case "t":
tunnelDetailVC?.handleToggleActiveStatusAction() tunnelDetailVC?.handleToggleActiveStatusAction()
@@ -263,7 +263,24 @@ class TunnelDetailTableViewController: NSViewController {
func applyTunnelConfiguration(tunnelConfiguration: TunnelConfiguration) { func applyTunnelConfiguration(tunnelConfiguration: TunnelConfiguration) {
// Incorporates changes from tunnelConfiguation. Ignores any changes in peer ordering. // 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() { for (index, field) in fields.enumerated() {
guard let change = changes[field] else { continue } guard let change = changes[field] else { continue }
let row = modelRowsInSection[0 ..< index].filter { $0.isVisible }.count 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) tableView.removeRows(at: IndexSet(integer: rowOffset + row), withAnimation: .effectFade)
modelRowsInSection[index].isVisible = false modelRowsInSection[index].isVisible = false
case .modified: case .modified:
tableView.removeRows(at: IndexSet(integer: rowOffset + row), withAnimation: []) break
tableView.insertRows(at: IndexSet(integer: rowOffset + row), withAnimation: [])
} }
} }
} }
var isChanged = false let changes = self.tunnelViewModel.applyConfiguration(other: tunnelConfiguration)
let changeHandlers = TunnelViewModel.ChangeHandlers(
interfaceChanged: { [weak self] changes in if !changes.interfaceChanges.isEmpty {
guard let self = self else { return } handleSectionFieldsModified(fields: TunnelDetailTableViewController.interfaceFields,
sectionChanged(fields: TunnelDetailTableViewController.interfaceFields, modelRowsInSection: &self.tableViewModelRowsBySection[0], modelRowsInSection: self.tableViewModelRowsBySection[0],
tableView: self.tableView, rowOffset: 0, changes: changes) rowOffset: 0, changes: changes.interfaceChanges)
isChanged = true }
}, for (peerIndex, peerChanges) in changes.peerChanges {
peerChangedAt: { [weak self] peerIndex, changes in let sectionIndex = 1 + peerIndex
guard let self = self else { return } let rowOffset = self.tableViewModelRowsBySection[0 ..< sectionIndex].flatMap { $0.filter { $0.isVisible } }.count
let sectionIndex = 1 + peerIndex handleSectionFieldsModified(fields: TunnelDetailTableViewController.peerFields,
let rowOffset = self.tableViewModelRowsBySection[0 ..< sectionIndex].flatMap { $0.filter { $0.isVisible } }.count modelRowsInSection: self.tableViewModelRowsBySection[sectionIndex],
sectionChanged(fields: TunnelDetailTableViewController.peerFields, modelRowsInSection: &self.tableViewModelRowsBySection[sectionIndex], rowOffset: rowOffset, changes: peerChanges)
tableView: self.tableView, rowOffset: rowOffset, changes: changes) }
isChanged = true
}, let isAnyInterfaceFieldAddedOrRemoved = changes.interfaceChanges.contains { $0.value == .added || $0.value == .removed }
peersRemovedAt: { [weak self] peerIndices in let isAnyPeerFieldAddedOrRemoved = changes.peerChanges.contains { $0.changes.contains { $0.value == .added || $0.value == .removed } }
guard let self = self else { return }
for peerIndex in peerIndices { 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 sectionIndex = 1 + peerIndex
let rowOffset = self.tableViewModelRowsBySection[0 ..< sectionIndex].flatMap { $0.filter { $0.isVisible } }.count let rowOffset = self.tableViewModelRowsBySection[0 ..< sectionIndex].flatMap { $0.filter { $0.isVisible } }.count
let count = self.tableViewModelRowsBySection[sectionIndex].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.tableView.removeRows(at: IndexSet(integersIn: rowOffset ..< rowOffset + count), withAnimation: .effectFade)
self.tableViewModelRowsBySection.remove(at: sectionIndex) self.tableViewModelRowsBySection.remove(at: sectionIndex)
} }
isChanged = true }
}, if !changes.peersInsertedIndices.isEmpty {
peersInsertedAt: { [weak self] peerIndices in for peerIndex in changes.peersInsertedIndices {
guard let self = self else { return }
for peerIndex in peerIndices {
let peerData = self.tunnelViewModel.peersData[peerIndex] let peerData = self.tunnelViewModel.peersData[peerIndex]
let sectionIndex = 1 + peerIndex let sectionIndex = 1 + peerIndex
let rowOffset = self.tableViewModelRowsBySection[0 ..< sectionIndex].flatMap { $0.filter { $0.isVisible } }.count 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.tableView.insertRows(at: IndexSet(integersIn: rowOffset ..< rowOffset + count), withAnimation: .effectFade)
self.tableViewModelRowsBySection.insert(modelRowsInSection, at: sectionIndex) self.tableViewModelRowsBySection.insert(modelRowsInSection, at: sectionIndex)
} }
isChanged = true
} }
)
tableView.beginUpdates()
self.tunnelViewModel.applyConfiguration(other: tunnelConfiguration, changeHandlers: changeHandlers)
if isChanged {
updateTableViewModelRows() updateTableViewModelRows()
tableView.endUpdates()
} }
tableView.endUpdates()
} }
private func reloadRuntimeConfiguration() { private func reloadRuntimeConfiguration() {
@@ -382,6 +405,8 @@ extension TunnelDetailTableViewController: NSTableViewDelegate {
cell.key = tr(format: "macFieldKey (%@)", localizedKeyString) cell.key = tr(format: "macFieldKey (%@)", localizedKeyString)
if field == .persistentKeepAlive { if field == .persistentKeepAlive {
cell.value = tr(format: "tunnelPeerPersistentKeepaliveValue (%@)", peerData[field]) cell.value = tr(format: "tunnelPeerPersistentKeepaliveValue (%@)", peerData[field])
} else if field == .preSharedKey {
cell.value = tr("tunnelPeerPresharedKeyEnabled")
} else { } else {
cell.value = peerData[field] cell.value = peerData[field]
} }
@@ -219,14 +219,16 @@ class TunnelEditViewController: NSViewController {
} }
} else { } else {
// We're creating a new tunnel // We're creating a new tunnel
tunnelsManager.add(tunnelConfiguration: tunnelConfiguration, activateOnDemandSetting: onDemandSetting) { [weak self] result in AppStorePrivacyNotice.show(from: self, into: tunnelsManager) { [weak self] in
if let error = result.error { self?.tunnelsManager.add(tunnelConfiguration: tunnelConfiguration, activateOnDemandSetting: onDemandSetting) { [weak self] result in
ErrorPresenter.showErrorAlert(error: error, from: self) if let error = result.error {
return 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 = {
let addMenu = NSMenu(title: "TunnelsListAdd") let addMenu = NSMenu(title: "TunnelsListAdd")
addMenu.addItem(withTitle: tr("macMenuAddEmptyTunnel"), action: #selector(handleAddEmptyTunnelAction), keyEquivalent: "n") 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 return addMenu
}() }()
@@ -42,6 +42,7 @@ class ZipArchive {
static func unarchive(url: URL, requiredFileExtensions: [String]) throws -> [(fileBaseName: String, contents: Data)] { static func unarchive(url: URL, requiredFileExtensions: [String]) throws -> [(fileBaseName: String, contents: Data)] {
var results = [(fileBaseName: String, contents: Data)]() var results = [(fileBaseName: String, contents: Data)]()
var requiredFileExtensionsLowercased = requiredFileExtensions.map { $0.lowercased() }
guard let zipFile = unzOpen64(url.path) else { guard let zipFile = unzOpen64(url.path) else {
throw ZipArchiveError.cantOpenInputZipFile throw ZipArchiveError.cantOpenInputZipFile
@@ -70,7 +71,7 @@ class ZipArchive {
let isDirectory = (lastChar == "/" || lastChar == "\\") let isDirectory = (lastChar == "/" || lastChar == "\\")
let fileURL = URL(fileURLWithFileSystemRepresentation: fileNameBuffer, isDirectory: isDirectory, relativeTo: nil) 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 unzippedData = Data()
var bytesRead: Int32 = 0 var bytesRead: Int32 = 0
repeat { repeat {
@@ -17,7 +17,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
networkMonitor?.cancel() networkMonitor?.cancel()
} }
//swiftlint:disable:next function_body_length
override func startTunnel(options: [String: NSObject]?, completionHandler startTunnelCompletionHandler: @escaping (Error?) -> Void) { override func startTunnel(options: [String: NSObject]?, completionHandler startTunnelCompletionHandler: @escaping (Error?) -> Void) {
let activationAttemptId = options?["activationAttemptId"] as? String let activationAttemptId = options?["activationAttemptId"] as? String
let errorNotifier = ErrorNotifier(activationAttemptId: activationAttemptId) let errorNotifier = ErrorNotifier(activationAttemptId: activationAttemptId)
+3
View File
@@ -0,0 +1,3 @@
.cache/
.tmp/
out/
+13 -5
View File
@@ -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 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) 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_arm64 := arm64
GOARCH_armv7 := arm GOARCH_armv7 := arm
GOARCH_x86_64 := amd64 GOARCH_x86_64 := amd64
@@ -29,7 +29,8 @@ version-header: $(DESTDIR)/wireguard-go-version.h
GOBUILDARCH := $(GOARCH_$(shell uname -m)) GOBUILDARCH := $(GOARCH_$(shell uname -m))
GOBUILDOS := $(shell uname -s | tr '[:upper:]' '[:lower:]') GOBUILDOS := $(shell uname -s | tr '[:upper:]' '[:lower:]')
GOBUILDVERSION := 1.11.5 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) GOBUILDVERSION_NEEDED := go version go$(GOBUILDVERSION) $(GOBUILDOS)/$(GOBUILDARCH)
export GOROOT := $(BUILDDIR)/goroot export GOROOT := $(BUILDDIR)/goroot
export GOPATH := $(BUILDDIR)/gopath export GOPATH := $(BUILDDIR)/gopath
@@ -38,10 +39,14 @@ GOBUILDVERSION_CURRENT := $(shell $(GOROOT)/bin/go version 2>/dev/null)
ifneq ($(GOBUILDVERSION_NEEDED),$(GOBUILDVERSION_CURRENT)) ifneq ($(GOBUILDVERSION_NEEDED),$(GOBUILDVERSION_CURRENT))
$(shell rm -f $(GOROOT)/bin/go) $(shell rm -f $(GOROOT)/bin/go)
endif endif
$(GOROOT)/bin/go: .cache/$(GOBUILDTARBALL):
mkdir -p $(dir $@)
curl -o $@ $(GOBUILDTARBALLURL) || { rm -f $@; exit 1; }
$(GOROOT)/bin/go: .cache/$(GOBUILDTARBALL)
rm -rf "$(GOROOT)" rm -rf "$(GOROOT)"
mkdir -p "$(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; } 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") $(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: clean:
rm -rf "$(BUILDDIR)" "$(DESTDIR)/libwg-go.a" "$(DESTDIR)/wireguard-go-version.h" rm -rf "$(BUILDDIR)" "$(DESTDIR)/libwg-go.a" "$(DESTDIR)/wireguard-go-version.h"
distclean: clean
rm -rf .cache
install: build install: build
.PHONY: clean build version-header install .PHONY: distclean clean build version-header install