Compare commits
112 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 386fe4eb12 | |||
| 49b7d083f1 | |||
| db4e2915f3 | |||
| 20bdf46792 | |||
| 4ded3f6bfe | |||
| b51113f680 | |||
| be96dea04a | |||
| a786f5df60 | |||
| 9a483a46fa | |||
| 5d2a337332 | |||
| facf776602 | |||
| d3400e3a80 | |||
| 92517bd21e | |||
| 761f635e16 | |||
| 44704ba892 | |||
| 9231c03513 | |||
| 27b32e60b2 | |||
| 9d5b376dcf | |||
| 8fd4883d7e | |||
| d414cec9aa | |||
| 54e3333b72 | |||
| 9f8d0e24df | |||
| 3de7c99301 | |||
| d4fd17cd8f | |||
| d875266db5 | |||
| d696e31b6e | |||
| 90acf2b220 | |||
| 27ef0c6dba | |||
| 8f67435d4a | |||
| b4ebe2440f | |||
| d440a91b0e | |||
| 9e909a3294 | |||
| 75bcf97ab2 | |||
| 0edde8b46f | |||
| bcc34e0bb6 | |||
| 90b41aed89 | |||
| 7930b94981 | |||
| 54a89f6a0e | |||
| 8976a53b05 | |||
| 9849dedf1d | |||
| 547077a808 | |||
| 0b0898dc3c | |||
| 9f9d1ffed8 | |||
| 5a044e4129 | |||
| 35f0ada8a9 | |||
| 39e7ee07ac | |||
| 5a1c9598f1 | |||
| 101a45b6f1 | |||
| fd527f73e6 | |||
| de6aa3eb58 | |||
| c9eafd82ac | |||
| ec57408570 | |||
| 9c38a1b897 | |||
| b34625f511 | |||
| 2e356d3d8f | |||
| 697d449dc8 | |||
| 4f9f61f7a7 | |||
| bceb0a827d | |||
| 2329f712cf | |||
| d2c38702c8 | |||
| def921801f | |||
| 41e006a407 | |||
| 384b514290 | |||
| a6858bd126 | |||
| ef7de2500f | |||
| 6099975b71 | |||
| 828756e8ba | |||
| 4deaf905c1 | |||
| 76c8487a56 | |||
| a05f1233f9 | |||
| 95b833c754 | |||
| 8c057bf928 | |||
| ddf8ade9c6 | |||
| 4cb21b5eb0 | |||
| a03df7d8cc | |||
| 57f66f16f8 | |||
| 737f847c0d | |||
| 671a594945 | |||
| 3646430528 | |||
| e9bd6e576f | |||
| 35300d1c5f | |||
| 112545248e | |||
| 78e6ecc4bc | |||
| 174a6e8e32 | |||
| 20bcabbca4 | |||
| 0a3554cedd | |||
| 2acc7db63d | |||
| 31af7049fc | |||
| 52062a45c1 | |||
| 30406dec6d | |||
| edde27a0a0 | |||
| cfff596c30 | |||
| ba1c968cdf | |||
| c48406ac38 | |||
| 14437477e6 | |||
| 68d928192b | |||
| 028e76eb3f | |||
| cb0c965294 | |||
| d7ce621cb2 | |||
| a1ca4f6eb5 | |||
| 437f0dc46d | |||
| 547eabb4ae | |||
| bb16d3ebc8 | |||
| 1b6170cbc9 | |||
| 4c37a4b7a7 | |||
| 226166bdaf | |||
| 80fa72cabc | |||
| d976d159d0 | |||
| 84ca7fcf40 | |||
| f120a6aab0 | |||
| 0d8108d8da | |||
| e072ebee58 |
@@ -31,6 +31,10 @@ xcuserdata
|
|||||||
*.hmap
|
*.hmap
|
||||||
*.ipa
|
*.ipa
|
||||||
|
|
||||||
|
# Swift Package Manager
|
||||||
|
.swiftpm
|
||||||
|
.build/
|
||||||
|
|
||||||
# Fastlane
|
# Fastlane
|
||||||
*.app.dSYM.zip
|
*.app.dSYM.zip
|
||||||
*.mobileprovision
|
*.mobileprovision
|
||||||
@@ -41,7 +45,7 @@ Preview.html
|
|||||||
output
|
output
|
||||||
|
|
||||||
# Wireguard specific
|
# Wireguard specific
|
||||||
WireGuard/WireGuard/Config/Developer.xcconfig
|
Sources/WireGuardApp/Config/Developer.xcconfig
|
||||||
|
|
||||||
# Vim
|
# Vim
|
||||||
.*.sw*
|
.*.sw*
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ disabled_rules:
|
|||||||
- type_body_length
|
- type_body_length
|
||||||
- function_body_length
|
- function_body_length
|
||||||
- nesting
|
- nesting
|
||||||
|
- inclusive_language
|
||||||
opt_in_rules:
|
opt_in_rules:
|
||||||
- empty_count
|
- empty_count
|
||||||
- empty_string
|
- empty_string
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
|||||||
@@ -136,5 +136,5 @@ Here's an example WireGuard configuration payload dictionary:
|
|||||||
|
|
||||||
Configurations added via .mobileconfig will not be migrated into keychain until the WireGuard application is opened once.
|
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-quick(8)]: https://git.zx2c4.com/wireguard-tools/about/src/man/wg-quick.8
|
||||||
[wg(8)]: https://git.zx2c4.com/WireGuard/about/src/tools/man/wg.8
|
[wg(8)]: https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
// swift-tools-version:5.3
|
||||||
|
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||||
|
|
||||||
|
import PackageDescription
|
||||||
|
|
||||||
|
let package = Package(
|
||||||
|
name: "WireGuardKit",
|
||||||
|
platforms: [
|
||||||
|
.macOS(.v10_14),
|
||||||
|
.iOS(.v12)
|
||||||
|
],
|
||||||
|
products: [
|
||||||
|
.library(name: "WireGuardKit", targets: ["WireGuardKit"])
|
||||||
|
],
|
||||||
|
dependencies: [],
|
||||||
|
targets: [
|
||||||
|
.target(
|
||||||
|
name: "WireGuardKit",
|
||||||
|
dependencies: ["WireGuardKitGo", "WireGuardKitC"]
|
||||||
|
),
|
||||||
|
.target(
|
||||||
|
name: "WireGuardKitC",
|
||||||
|
dependencies: [],
|
||||||
|
publicHeadersPath: "."
|
||||||
|
),
|
||||||
|
.target(
|
||||||
|
name: "WireGuardKitGo",
|
||||||
|
dependencies: [],
|
||||||
|
exclude: [
|
||||||
|
"goruntime-boottime-over-monotonic.diff",
|
||||||
|
"go.mod",
|
||||||
|
"go.sum",
|
||||||
|
"api-ios.go",
|
||||||
|
"Makefile"
|
||||||
|
],
|
||||||
|
publicHeadersPath: ".",
|
||||||
|
linkerSettings: [.linkedLibrary("wg-go")]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
@@ -14,11 +14,11 @@ $ cd wireguard-apple
|
|||||||
- Rename and populate developer team ID file:
|
- Rename and populate developer team ID file:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ cp WireGuard/WireGuard/Config/Developer.xcconfig.template WireGuard/WireGuard/Config/Developer.xcconfig
|
$ cp Sources/WireGuardApp/Config/Developer.xcconfig.template Sources/WireGuardApp/Config/Developer.xcconfig
|
||||||
$ vim WireGuard/WireGuard/Config/Developer.xcconfig
|
$ vim Sources/WireGuardApp/Config/Developer.xcconfig
|
||||||
```
|
```
|
||||||
|
|
||||||
- Install swiftlint and go:
|
- Install swiftlint and go 1.15:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ brew install swiftlint go
|
$ brew install swiftlint go
|
||||||
@@ -27,11 +27,57 @@ $ brew install swiftlint go
|
|||||||
- Open project in Xcode:
|
- Open project in Xcode:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ open ./WireGuard/WireGuard.xcodeproj
|
$ open WireGuard.xcodeproj
|
||||||
```
|
```
|
||||||
|
|
||||||
- Flip switches, press buttons, and make whirling noises until Xcode builds it.
|
- Flip switches, press buttons, and make whirling noises until Xcode builds it.
|
||||||
|
|
||||||
|
## WireGuardKit integration
|
||||||
|
|
||||||
|
1. Open your Xcode project and add the Swift package with the following URL:
|
||||||
|
|
||||||
|
```
|
||||||
|
https://git.zx2c4.com/wireguard-apple
|
||||||
|
```
|
||||||
|
|
||||||
|
2. `WireGuardKit` links against `wireguard-go-bridge` library, but it cannot build it automatically
|
||||||
|
due to Swift package manager limitations. So it needs a little help from a developer.
|
||||||
|
Please follow the instructions below to create a build target(s) for `wireguard-go-bridge`.
|
||||||
|
|
||||||
|
- In Xcode, click File -> New -> Target. Switch to "Other" tab and choose "External Build
|
||||||
|
System".
|
||||||
|
- Type in `WireGuardGoBridge<PLATFORM>` under the "Product name", replacing the `<PLATFORM>`
|
||||||
|
placeholder with the name of the platform. For example, when targeting macOS use `macOS`, or
|
||||||
|
when targeting iOS use `iOS`.
|
||||||
|
Make sure the build tool is set to: `/usr/bin/make` (default).
|
||||||
|
- In the appeared "Info" tab of a newly created target, type in the "Directory" path under
|
||||||
|
the "External Build Tool Configuration":
|
||||||
|
|
||||||
|
```
|
||||||
|
$BUILD_DIR/../../SourcePackages/checkouts/wireguard-apple/Sources/WireGuardKitGo
|
||||||
|
```
|
||||||
|
|
||||||
|
- Switch to "Build Settings" and find `SDKROOT`.
|
||||||
|
Type in `macosx` if you target macOS, or type in `iphoneos` if you target iOS.
|
||||||
|
|
||||||
|
3. Go to Xcode project settings and locate your network extension target and switch to
|
||||||
|
"Build Phases" tab.
|
||||||
|
|
||||||
|
- Locate "Dependencies" section and hit "+" to add `WireGuardGoBridge<PLATFORM>` replacing
|
||||||
|
the `<PLATFORM>` placeholder with the name of platform matching the network extension
|
||||||
|
deployment target (i.e macOS or iOS).
|
||||||
|
|
||||||
|
- Locate the "Link with binary libraries" section and hit "+" to add `WireGuardKit`.
|
||||||
|
|
||||||
|
4. In Xcode project settings, locate your main bundle app and switch to "Build Phases" tab.
|
||||||
|
Locate the "Link with binary libraries" section and hit "+" to add `WireGuardKit`.
|
||||||
|
|
||||||
|
5. iOS only: Locate Bitcode settings under your application target, Build settings -> Enable Bitcode,
|
||||||
|
change the corresponding value to "No".
|
||||||
|
|
||||||
|
Note that if you ship your app for both iOS and macOS, make sure to repeat the steps 2-4 twice,
|
||||||
|
once per platform.
|
||||||
|
|
||||||
## MIT License
|
## MIT License
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import os.log
|
import os.log
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import Security
|
import Security
|
||||||
@@ -7,9 +7,9 @@ import Security
|
|||||||
class Keychain {
|
class Keychain {
|
||||||
static func openReference(called ref: Data) -> String? {
|
static func openReference(called ref: Data) -> String? {
|
||||||
var result: CFTypeRef?
|
var result: CFTypeRef?
|
||||||
let ret = SecItemCopyMatching([kSecClass as String: kSecClassGenericPassword,
|
let ret = SecItemCopyMatching([kSecClass: kSecClassGenericPassword,
|
||||||
kSecValuePersistentRef as String: ref,
|
kSecValuePersistentRef: ref,
|
||||||
kSecReturnData as String: true] as CFDictionary,
|
kSecReturnData: true] as CFDictionary,
|
||||||
&result)
|
&result)
|
||||||
if ret != errSecSuccess || result == nil {
|
if ret != errSecSuccess || result == nil {
|
||||||
wg_log(.error, message: "Unable to open config from keychain: \(ret)")
|
wg_log(.error, message: "Unable to open config from keychain: \(ret)")
|
||||||
@@ -21,27 +21,28 @@ class Keychain {
|
|||||||
|
|
||||||
static func makeReference(containing value: String, called name: String, previouslyReferencedBy oldRef: Data? = nil) -> Data? {
|
static func makeReference(containing value: String, called name: String, previouslyReferencedBy oldRef: Data? = nil) -> Data? {
|
||||||
var ret: OSStatus
|
var ret: OSStatus
|
||||||
guard var id = Bundle.main.bundleIdentifier else {
|
guard var bundleIdentifier = Bundle.main.bundleIdentifier else {
|
||||||
wg_log(.error, staticMessage: "Unable to determine bundle identifier")
|
wg_log(.error, staticMessage: "Unable to determine bundle identifier")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if id.hasSuffix(".network-extension") {
|
if bundleIdentifier.hasSuffix(".network-extension") {
|
||||||
id.removeLast(".network-extension".count)
|
bundleIdentifier.removeLast(".network-extension".count)
|
||||||
}
|
}
|
||||||
var items: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
|
let itemLabel = "WireGuard Tunnel: \(name)"
|
||||||
kSecAttrLabel as String: "WireGuard Tunnel: " + name,
|
var items: [CFString: Any] = [kSecClass: kSecClassGenericPassword,
|
||||||
kSecAttrAccount as String: name + ": " + UUID().uuidString,
|
kSecAttrLabel: itemLabel,
|
||||||
kSecAttrDescription as String: "wg-quick(8) config",
|
kSecAttrAccount: name + ": " + UUID().uuidString,
|
||||||
kSecAttrService as String: id,
|
kSecAttrDescription: "wg-quick(8) config",
|
||||||
kSecValueData as String: value.data(using: .utf8) as Any,
|
kSecAttrService: bundleIdentifier,
|
||||||
kSecReturnPersistentRef as String: true]
|
kSecValueData: value.data(using: .utf8) as Any,
|
||||||
|
kSecReturnPersistentRef: true]
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
items[kSecAttrAccessGroup as String] = FileManager.appGroupId
|
items[kSecAttrAccessGroup] = FileManager.appGroupId
|
||||||
items[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock
|
items[kSecAttrAccessible] = kSecAttrAccessibleAfterFirstUnlock
|
||||||
#elseif os(macOS)
|
#elseif os(macOS)
|
||||||
items[kSecAttrSynchronizable as String] = false
|
items[kSecAttrSynchronizable] = false
|
||||||
items[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
|
items[kSecAttrAccessible] = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
|
||||||
|
|
||||||
guard let extensionPath = Bundle.main.builtInPlugInsURL?.appendingPathComponent("WireGuardNetworkExtension.appex").path else {
|
guard let extensionPath = Bundle.main.builtInPlugInsURL?.appendingPathComponent("WireGuardNetworkExtension.appex").path else {
|
||||||
wg_log(.error, staticMessage: "Unable to determine app extension path")
|
wg_log(.error, staticMessage: "Unable to determine app extension path")
|
||||||
@@ -60,14 +61,12 @@ class Keychain {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var access: SecAccess?
|
var access: SecAccess?
|
||||||
ret = SecAccessCreate((items[kSecAttrLabel as String] as? String)! as CFString,
|
ret = SecAccessCreate(itemLabel as CFString, [extensionApp!, mainApp!] as CFArray, &access)
|
||||||
[extensionApp!, mainApp!] as CFArray,
|
|
||||||
&access)
|
|
||||||
if ret != errSecSuccess || access == nil {
|
if ret != errSecSuccess || access == nil {
|
||||||
wg_log(.error, message: "Unable to create keychain ACL object: \(ret)")
|
wg_log(.error, message: "Unable to create keychain ACL object: \(ret)")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
items[kSecAttrAccess as String] = access!
|
items[kSecAttrAccess] = access!
|
||||||
#else
|
#else
|
||||||
#error("Unimplemented")
|
#error("Unimplemented")
|
||||||
#endif
|
#endif
|
||||||
@@ -85,7 +84,7 @@ class Keychain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static func deleteReference(called ref: Data) {
|
static func deleteReference(called ref: Data) {
|
||||||
let ret = SecItemDelete([kSecValuePersistentRef as String: ref] as CFDictionary)
|
let ret = SecItemDelete([kSecValuePersistentRef: ref] as CFDictionary)
|
||||||
if ret != errSecSuccess {
|
if ret != errSecSuccess {
|
||||||
wg_log(.error, message: "Unable to delete config from keychain: \(ret)")
|
wg_log(.error, message: "Unable to delete config from keychain: \(ret)")
|
||||||
}
|
}
|
||||||
@@ -93,10 +92,10 @@ class Keychain {
|
|||||||
|
|
||||||
static func deleteReferences(except whitelist: Set<Data>) {
|
static func deleteReferences(except whitelist: Set<Data>) {
|
||||||
var result: CFTypeRef?
|
var result: CFTypeRef?
|
||||||
let ret = SecItemCopyMatching([kSecClass as String: kSecClassGenericPassword,
|
let ret = SecItemCopyMatching([kSecClass: kSecClassGenericPassword,
|
||||||
kSecAttrService as String: Bundle.main.bundleIdentifier as Any,
|
kSecAttrService: Bundle.main.bundleIdentifier as Any,
|
||||||
kSecMatchLimit as String: kSecMatchLimitAll,
|
kSecMatchLimit: kSecMatchLimitAll,
|
||||||
kSecReturnPersistentRef as String: true] as CFDictionary,
|
kSecReturnPersistentRef: true] as CFDictionary,
|
||||||
&result)
|
&result)
|
||||||
if ret != errSecSuccess || result == nil {
|
if ret != errSecSuccess || result == nil {
|
||||||
return
|
return
|
||||||
@@ -110,8 +109,8 @@ class Keychain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static func verifyReference(called ref: Data) -> Bool {
|
static func verifyReference(called ref: Data) -> Bool {
|
||||||
return SecItemCopyMatching([kSecClass as String: kSecClassGenericPassword,
|
return SecItemCopyMatching([kSecClass: kSecClassGenericPassword,
|
||||||
kSecValuePersistentRef as String: ref] as CFDictionary,
|
kSecValuePersistentRef: ref] as CFDictionary,
|
||||||
nil) == errSecSuccess
|
nil) != errSecItemNotFound
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import os.log
|
import os.log
|
||||||
@@ -49,8 +49,8 @@ public class Logger {
|
|||||||
if let appBuild = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
|
if let appBuild = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
|
||||||
appVersion += " (\(appBuild))"
|
appVersion += " (\(appBuild))"
|
||||||
}
|
}
|
||||||
let goBackendVersion = WIREGUARD_GO_VERSION
|
|
||||||
Logger.global?.log(message: "App version: \(appVersion); Go backend version: \(goBackendVersion)")
|
Logger.global?.log(message: "App version: \(appVersion)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* SPDX-License-Identifier: MIT
|
/* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
* Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
* Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* SPDX-License-Identifier: MIT
|
/* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
* Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
* Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RINGLOGGER_H
|
#ifndef RINGLOGGER_H
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import NetworkExtension
|
import NetworkExtension
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ extension TunnelConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let peerPublicKeysArray = peerConfigurations.map { $0.publicKey }
|
let peerPublicKeysArray = peerConfigurations.map { $0.publicKey }
|
||||||
let peerPublicKeysSet = Set<Data>(peerPublicKeysArray)
|
let peerPublicKeysSet = Set<PublicKey>(peerPublicKeysArray)
|
||||||
if peerPublicKeysArray.count != peerPublicKeysSet.count {
|
if peerPublicKeysArray.count != peerPublicKeysSet.count {
|
||||||
throw ParseError.multiplePeersWithSamePublicKey
|
throw ParseError.multiplePeersWithSamePublicKey
|
||||||
}
|
}
|
||||||
@@ -125,9 +125,7 @@ extension TunnelConfiguration {
|
|||||||
|
|
||||||
func asWgQuickConfig() -> String {
|
func asWgQuickConfig() -> String {
|
||||||
var output = "[Interface]\n"
|
var output = "[Interface]\n"
|
||||||
if let privateKey = interface.privateKey.base64Key() {
|
output.append("PrivateKey = \(interface.privateKey.base64Key)\n")
|
||||||
output.append("PrivateKey = \(privateKey)\n")
|
|
||||||
}
|
|
||||||
if let listenPort = interface.listenPort {
|
if let listenPort = interface.listenPort {
|
||||||
output.append("ListenPort = \(listenPort)\n")
|
output.append("ListenPort = \(listenPort)\n")
|
||||||
}
|
}
|
||||||
@@ -135,8 +133,10 @@ extension TunnelConfiguration {
|
|||||||
let addressString = interface.addresses.map { $0.stringRepresentation }.joined(separator: ", ")
|
let addressString = interface.addresses.map { $0.stringRepresentation }.joined(separator: ", ")
|
||||||
output.append("Address = \(addressString)\n")
|
output.append("Address = \(addressString)\n")
|
||||||
}
|
}
|
||||||
if !interface.dns.isEmpty {
|
if !interface.dns.isEmpty || !interface.dnsSearch.isEmpty {
|
||||||
let dnsString = interface.dns.map { $0.stringRepresentation }.joined(separator: ", ")
|
var dnsLine = interface.dns.map { $0.stringRepresentation }
|
||||||
|
dnsLine.append(contentsOf: interface.dnsSearch)
|
||||||
|
let dnsString = dnsLine.joined(separator: ", ")
|
||||||
output.append("DNS = \(dnsString)\n")
|
output.append("DNS = \(dnsString)\n")
|
||||||
}
|
}
|
||||||
if let mtu = interface.mtu {
|
if let mtu = interface.mtu {
|
||||||
@@ -145,10 +145,8 @@ extension TunnelConfiguration {
|
|||||||
|
|
||||||
for peer in peers {
|
for peer in peers {
|
||||||
output.append("\n[Peer]\n")
|
output.append("\n[Peer]\n")
|
||||||
if let publicKey = peer.publicKey.base64Key() {
|
output.append("PublicKey = \(peer.publicKey.base64Key)\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 {
|
||||||
@@ -170,7 +168,7 @@ extension TunnelConfiguration {
|
|||||||
guard let privateKeyString = attributes["privatekey"] else {
|
guard let privateKeyString = attributes["privatekey"] else {
|
||||||
throw ParseError.interfaceHasNoPrivateKey
|
throw ParseError.interfaceHasNoPrivateKey
|
||||||
}
|
}
|
||||||
guard let privateKey = Data(base64Key: privateKeyString), privateKey.count == TunnelConfiguration.keyLength else {
|
guard let privateKey = PrivateKey(base64Key: privateKeyString) else {
|
||||||
throw ParseError.interfaceHasInvalidPrivateKey(privateKeyString)
|
throw ParseError.interfaceHasInvalidPrivateKey(privateKeyString)
|
||||||
}
|
}
|
||||||
var interface = InterfaceConfiguration(privateKey: privateKey)
|
var interface = InterfaceConfiguration(privateKey: privateKey)
|
||||||
@@ -192,13 +190,16 @@ extension TunnelConfiguration {
|
|||||||
}
|
}
|
||||||
if let dnsString = attributes["dns"] {
|
if let dnsString = attributes["dns"] {
|
||||||
var dnsServers = [DNSServer]()
|
var dnsServers = [DNSServer]()
|
||||||
|
var dnsSearch = [String]()
|
||||||
for dnsServerString in dnsString.splitToArray(trimmingCharacters: .whitespacesAndNewlines) {
|
for dnsServerString in dnsString.splitToArray(trimmingCharacters: .whitespacesAndNewlines) {
|
||||||
guard let dnsServer = DNSServer(from: dnsServerString) else {
|
if let dnsServer = DNSServer(from: dnsServerString) {
|
||||||
throw ParseError.interfaceHasInvalidDNS(dnsServerString)
|
dnsServers.append(dnsServer)
|
||||||
|
} else {
|
||||||
|
dnsSearch.append(dnsServerString)
|
||||||
}
|
}
|
||||||
dnsServers.append(dnsServer)
|
|
||||||
}
|
}
|
||||||
interface.dns = dnsServers
|
interface.dns = dnsServers
|
||||||
|
interface.dnsSearch = dnsSearch
|
||||||
}
|
}
|
||||||
if let mtuString = attributes["mtu"] {
|
if let mtuString = attributes["mtu"] {
|
||||||
guard let mtu = UInt16(mtuString) else {
|
guard let mtu = UInt16(mtuString) else {
|
||||||
@@ -213,12 +214,12 @@ extension TunnelConfiguration {
|
|||||||
guard let publicKeyString = attributes["publickey"] else {
|
guard let publicKeyString = attributes["publickey"] else {
|
||||||
throw ParseError.peerHasNoPublicKey
|
throw ParseError.peerHasNoPublicKey
|
||||||
}
|
}
|
||||||
guard let publicKey = Data(base64Key: publicKeyString), publicKey.count == TunnelConfiguration.keyLength else {
|
guard let publicKey = PublicKey(base64Key: publicKeyString) else {
|
||||||
throw ParseError.peerHasInvalidPublicKey(publicKeyString)
|
throw ParseError.peerHasInvalidPublicKey(publicKeyString)
|
||||||
}
|
}
|
||||||
var peer = PeerConfiguration(publicKey: publicKey)
|
var peer = PeerConfiguration(publicKey: publicKey)
|
||||||
if let preSharedKeyString = attributes["presharedkey"] {
|
if let preSharedKeyString = attributes["presharedkey"] {
|
||||||
guard let preSharedKey = Data(base64Key: preSharedKeyString), preSharedKey.count == TunnelConfiguration.keyLength else {
|
guard let preSharedKey = PreSharedKey(base64Key: preSharedKeyString) else {
|
||||||
throw ParseError.peerHasInvalidPreSharedKey(preSharedKeyString)
|
throw ParseError.peerHasInvalidPreSharedKey(preSharedKeyString)
|
||||||
}
|
}
|
||||||
peer.preSharedKey = preSharedKey
|
peer.preSharedKey = preSharedKey
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
// iOS permission prompts
|
// iOS permission prompts
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
// Generic alert action names
|
// Generic alert action names
|
||||||
|
|
||||||
@@ -349,6 +349,8 @@
|
|||||||
|
|
||||||
"macButtonDeleteTunnels (%d)" = "Delete %d tunnels";
|
"macButtonDeleteTunnels (%d)" = "Delete %d tunnels";
|
||||||
|
|
||||||
|
"macButtonEdit" = "Edit";
|
||||||
|
|
||||||
// Mac detail/edit view fields
|
// Mac detail/edit view fields
|
||||||
|
|
||||||
"macFieldKey (%@)" = "%@:";
|
"macFieldKey (%@)" = "%@:";
|
||||||
@@ -437,3 +439,7 @@
|
|||||||
"macAppStoreUpdatingAlertMessage" = "App Store would like to update WireGuard";
|
"macAppStoreUpdatingAlertMessage" = "App Store would like to update WireGuard";
|
||||||
"macAppStoreUpdatingAlertInfoWithOnDemand (%@)" = "Please disable on-demand for tunnel ‘%@’, deactivate it, and then continue updating in App Store.";
|
"macAppStoreUpdatingAlertInfoWithOnDemand (%@)" = "Please disable on-demand for tunnel ‘%@’, deactivate it, and then continue updating in App Store.";
|
||||||
"macAppStoreUpdatingAlertInfoWithoutOnDemand (%@)" = "Please deactivate tunnel ‘%@’ and then continue updating in App Store.";
|
"macAppStoreUpdatingAlertInfoWithoutOnDemand (%@)" = "Please deactivate tunnel ‘%@’ and then continue updating in App Store.";
|
||||||
|
|
||||||
|
// Donation
|
||||||
|
|
||||||
|
"donateLink" = "♥ Donate to the WireGuard Project";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
VERSION_NAME = 1.0.11
|
||||||
|
VERSION_ID = 20
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 953 B After Width: | Height: | Size: 953 B |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import NetworkExtension
|
import NetworkExtension
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import NetworkExtension
|
import NetworkExtension
|
||||||
|
|
||||||
@@ -26,11 +26,11 @@ class MockTunnels {
|
|||||||
static func createMockTunnels() -> [NETunnelProviderManager] {
|
static func createMockTunnels() -> [NETunnelProviderManager] {
|
||||||
return tunnelNames.map { tunnelName -> NETunnelProviderManager in
|
return tunnelNames.map { tunnelName -> NETunnelProviderManager in
|
||||||
|
|
||||||
var interface = InterfaceConfiguration(privateKey: Curve25519.generatePrivateKey())
|
var interface = InterfaceConfiguration(privateKey: PrivateKey())
|
||||||
interface.addresses = [IPAddressRange(from: String(format: address, Int.random(in: 1 ... 10), Int.random(in: 1 ... 254)))!]
|
interface.addresses = [IPAddressRange(from: String(format: address, Int.random(in: 1 ... 10), Int.random(in: 1 ... 254)))!]
|
||||||
interface.dns = dnsServers.map { DNSServer(from: $0)! }
|
interface.dns = dnsServers.map { DNSServer(from: $0)! }
|
||||||
|
|
||||||
var peer = PeerConfiguration(publicKey: Curve25519.generatePublicKey(fromPrivateKey: Curve25519.generatePrivateKey()))
|
var peer = PeerConfiguration(publicKey: PrivateKey().publicKey)
|
||||||
peer.endpoint = Endpoint(from: endpoint)
|
peer.endpoint = Endpoint(from: endpoint)
|
||||||
peer.allowedIPs = [IPAddressRange(from: allowedIPs)!]
|
peer.allowedIPs = [IPAddressRange(from: allowedIPs)!]
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@@ -67,13 +67,14 @@ extension TunnelConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let peerPublicKeysArray = peerConfigurations.map { $0.publicKey }
|
let peerPublicKeysArray = peerConfigurations.map { $0.publicKey }
|
||||||
let peerPublicKeysSet = Set<Data>(peerPublicKeysArray)
|
let peerPublicKeysSet = Set<PublicKey>(peerPublicKeysArray)
|
||||||
if peerPublicKeysArray.count != peerPublicKeysSet.count {
|
if peerPublicKeysArray.count != peerPublicKeysSet.count {
|
||||||
throw ParseError.multiplePeersWithSamePublicKey
|
throw ParseError.multiplePeersWithSamePublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
interfaceConfiguration?.addresses = base?.interface.addresses ?? []
|
interfaceConfiguration?.addresses = base?.interface.addresses ?? []
|
||||||
interfaceConfiguration?.dns = base?.interface.dns ?? []
|
interfaceConfiguration?.dns = base?.interface.dns ?? []
|
||||||
|
interfaceConfiguration?.dnsSearch = base?.interface.dnsSearch ?? []
|
||||||
interfaceConfiguration?.mtu = base?.interface.mtu
|
interfaceConfiguration?.mtu = base?.interface.mtu
|
||||||
|
|
||||||
if let interfaceConfiguration = interfaceConfiguration {
|
if let interfaceConfiguration = interfaceConfiguration {
|
||||||
@@ -87,7 +88,7 @@ extension TunnelConfiguration {
|
|||||||
guard let privateKeyString = attributes["private_key"] else {
|
guard let privateKeyString = attributes["private_key"] else {
|
||||||
throw ParseError.interfaceHasNoPrivateKey
|
throw ParseError.interfaceHasNoPrivateKey
|
||||||
}
|
}
|
||||||
guard let privateKey = Data(hexKey: privateKeyString), privateKey.count == TunnelConfiguration.keyLength else {
|
guard let privateKey = PrivateKey(hexKey: privateKeyString) else {
|
||||||
throw ParseError.interfaceHasInvalidPrivateKey(privateKeyString)
|
throw ParseError.interfaceHasInvalidPrivateKey(privateKeyString)
|
||||||
}
|
}
|
||||||
var interface = InterfaceConfiguration(privateKey: privateKey)
|
var interface = InterfaceConfiguration(privateKey: privateKey)
|
||||||
@@ -106,18 +107,18 @@ extension TunnelConfiguration {
|
|||||||
guard let publicKeyString = attributes["public_key"] else {
|
guard let publicKeyString = attributes["public_key"] else {
|
||||||
throw ParseError.peerHasNoPublicKey
|
throw ParseError.peerHasNoPublicKey
|
||||||
}
|
}
|
||||||
guard let publicKey = Data(hexKey: publicKeyString), publicKey.count == TunnelConfiguration.keyLength else {
|
guard let publicKey = PublicKey(hexKey: publicKeyString) else {
|
||||||
throw ParseError.peerHasInvalidPublicKey(publicKeyString)
|
throw ParseError.peerHasInvalidPublicKey(publicKeyString)
|
||||||
}
|
}
|
||||||
var peer = PeerConfiguration(publicKey: publicKey)
|
var peer = PeerConfiguration(publicKey: publicKey)
|
||||||
if let preSharedKeyString = attributes["preshared_key"] {
|
if let preSharedKeyString = attributes["preshared_key"] {
|
||||||
guard let preSharedKey = Data(hexKey: preSharedKeyString), preSharedKey.count == TunnelConfiguration.keyLength else {
|
guard let preSharedKey = PreSharedKey(hexKey: preSharedKeyString) else {
|
||||||
throw ParseError.peerHasInvalidPreSharedKey(preSharedKeyString)
|
throw ParseError.peerHasInvalidPreSharedKey(preSharedKeyString)
|
||||||
}
|
}
|
||||||
// TODO(zx2c4): does the compiler optimize this away?
|
// TODO(zx2c4): does the compiler optimize this away?
|
||||||
var accumulator: UInt8 = 0
|
var accumulator: UInt8 = 0
|
||||||
for index in 0..<preSharedKey.count {
|
for index in 0..<preSharedKey.rawValue.count {
|
||||||
accumulator |= preSharedKey[index]
|
accumulator |= preSharedKey.rawValue[index]
|
||||||
}
|
}
|
||||||
if accumulator != 0 {
|
if accumulator != 0 {
|
||||||
peer.preSharedKey = preSharedKey
|
peer.preSharedKey = preSharedKey
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import NetworkExtension
|
import NetworkExtension
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import NetworkExtension
|
import NetworkExtension
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import NetworkExtension
|
import NetworkExtension
|
||||||
@@ -70,6 +70,7 @@ class TunnelsManager {
|
|||||||
if let ref = passwordRef {
|
if let ref = passwordRef {
|
||||||
refs.insert(ref)
|
refs.insert(ref)
|
||||||
} else {
|
} else {
|
||||||
|
wg_log(.info, message: "Removing orphaned tunnel with non-verifying keychain entry: \(tunnelManager.localizedDescription ?? "<unknown>")")
|
||||||
tunnelManager.removeFromPreferences { _ in }
|
tunnelManager.removeFromPreferences { _ in }
|
||||||
tunnelManagers.remove(at: index)
|
tunnelManagers.remove(at: index)
|
||||||
}
|
}
|
||||||
@@ -448,8 +449,8 @@ class TunnelsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func tunnelNameIsLessThan(_ a: String, _ b: String) -> Bool {
|
static func tunnelNameIsLessThan(_ lhs: String, _ rhs: String) -> Bool {
|
||||||
return a.compare(b, options: [.caseInsensitive, .diacriticInsensitive, .widthInsensitive, .numeric]) == .orderedAscending
|
return lhs.compare(rhs, options: [.caseInsensitive, .diacriticInsensitive, .widthInsensitive, .numeric]) == .orderedAscending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
protocol ErrorPresenterProtocol {
|
protocol ErrorPresenterProtocol {
|
||||||
static func showErrorAlert(title: String, message: String, from sourceVC: AnyObject?, onPresented: (() -> Void)?, onDismissal: (() -> Void)?)
|
static func showErrorAlert(title: String, message: String, from sourceVC: AnyObject?, onPresented: (() -> Void)?, onDismissal: (() -> Void)?)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import LocalAuthentication
|
import LocalAuthentication
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@@ -109,9 +109,9 @@ class TunnelViewModel {
|
|||||||
scratchpad[field] = stringValue
|
scratchpad[field] = stringValue
|
||||||
}
|
}
|
||||||
if field == .privateKey {
|
if field == .privateKey {
|
||||||
if stringValue.count == TunnelViewModel.keyLengthInBase64, let privateKey = Data(base64Key: stringValue), privateKey.count == TunnelConfiguration.keyLength {
|
if stringValue.count == TunnelViewModel.keyLengthInBase64,
|
||||||
let publicKey = Curve25519.generatePublicKey(fromPrivateKey: privateKey).base64Key() ?? ""
|
let privateKey = PrivateKey(base64Key: stringValue) {
|
||||||
scratchpad[.publicKey] = publicKey
|
scratchpad[.publicKey] = privateKey.publicKey.base64Key
|
||||||
} else {
|
} else {
|
||||||
scratchpad.removeValue(forKey: .publicKey)
|
scratchpad.removeValue(forKey: .publicKey)
|
||||||
}
|
}
|
||||||
@@ -128,8 +128,8 @@ class TunnelViewModel {
|
|||||||
private static func createScratchPad(from config: InterfaceConfiguration, name: String) -> [InterfaceField: String] {
|
private static func createScratchPad(from config: InterfaceConfiguration, name: String) -> [InterfaceField: String] {
|
||||||
var scratchpad = [InterfaceField: String]()
|
var scratchpad = [InterfaceField: String]()
|
||||||
scratchpad[.name] = name
|
scratchpad[.name] = name
|
||||||
scratchpad[.privateKey] = config.privateKey.base64Key() ?? ""
|
scratchpad[.privateKey] = config.privateKey.base64Key
|
||||||
scratchpad[.publicKey] = config.publicKey.base64Key() ?? ""
|
scratchpad[.publicKey] = config.privateKey.publicKey.base64Key
|
||||||
if !config.addresses.isEmpty {
|
if !config.addresses.isEmpty {
|
||||||
scratchpad[.addresses] = config.addresses.map { $0.stringRepresentation }.joined(separator: ", ")
|
scratchpad[.addresses] = config.addresses.map { $0.stringRepresentation }.joined(separator: ", ")
|
||||||
}
|
}
|
||||||
@@ -139,8 +139,10 @@ class TunnelViewModel {
|
|||||||
if let mtu = config.mtu {
|
if let mtu = config.mtu {
|
||||||
scratchpad[.mtu] = String(mtu)
|
scratchpad[.mtu] = String(mtu)
|
||||||
}
|
}
|
||||||
if !config.dns.isEmpty {
|
if !config.dns.isEmpty || !config.dnsSearch.isEmpty {
|
||||||
scratchpad[.dns] = config.dns.map { $0.stringRepresentation }.joined(separator: ", ")
|
var dns = config.dns.map { $0.stringRepresentation }
|
||||||
|
dns.append(contentsOf: config.dnsSearch)
|
||||||
|
scratchpad[.dns] = dns.joined(separator: ", ")
|
||||||
}
|
}
|
||||||
return scratchpad
|
return scratchpad
|
||||||
}
|
}
|
||||||
@@ -158,7 +160,7 @@ class TunnelViewModel {
|
|||||||
fieldsWithError.insert(.privateKey)
|
fieldsWithError.insert(.privateKey)
|
||||||
return .error(tr("alertInvalidInterfaceMessagePrivateKeyRequired"))
|
return .error(tr("alertInvalidInterfaceMessagePrivateKeyRequired"))
|
||||||
}
|
}
|
||||||
guard let privateKey = Data(base64Key: privateKeyString), privateKey.count == TunnelConfiguration.keyLength else {
|
guard let privateKey = PrivateKey(base64Key: privateKeyString) else {
|
||||||
fieldsWithError.insert(.privateKey)
|
fieldsWithError.insert(.privateKey)
|
||||||
return .error(tr("alertInvalidInterfaceMessagePrivateKeyInvalid"))
|
return .error(tr("alertInvalidInterfaceMessagePrivateKeyInvalid"))
|
||||||
}
|
}
|
||||||
@@ -194,15 +196,16 @@ class TunnelViewModel {
|
|||||||
}
|
}
|
||||||
if let dnsString = scratchpad[.dns] {
|
if let dnsString = scratchpad[.dns] {
|
||||||
var dnsServers = [DNSServer]()
|
var dnsServers = [DNSServer]()
|
||||||
|
var dnsSearch = [String]()
|
||||||
for dnsServerString in dnsString.splitToArray(trimmingCharacters: .whitespacesAndNewlines) {
|
for dnsServerString in dnsString.splitToArray(trimmingCharacters: .whitespacesAndNewlines) {
|
||||||
if let dnsServer = DNSServer(from: dnsServerString) {
|
if let dnsServer = DNSServer(from: dnsServerString) {
|
||||||
dnsServers.append(dnsServer)
|
dnsServers.append(dnsServer)
|
||||||
} else {
|
} else {
|
||||||
fieldsWithError.insert(.dns)
|
dnsSearch.append(dnsServerString)
|
||||||
errorMessages.append(tr("alertInvalidInterfaceMessageDNSInvalid"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
config.dns = dnsServers
|
config.dns = dnsServers
|
||||||
|
config.dnsSearch = dnsSearch
|
||||||
}
|
}
|
||||||
|
|
||||||
guard errorMessages.isEmpty else { return .error(errorMessages.first!) }
|
guard errorMessages.isEmpty else { return .error(errorMessages.first!) }
|
||||||
@@ -251,12 +254,12 @@ class TunnelViewModel {
|
|||||||
var scratchpad = [PeerField: String]()
|
var scratchpad = [PeerField: String]()
|
||||||
var fieldsWithError = Set<PeerField>()
|
var fieldsWithError = Set<PeerField>()
|
||||||
var validatedConfiguration: PeerConfiguration?
|
var validatedConfiguration: PeerConfiguration?
|
||||||
var publicKey: Data? {
|
var publicKey: PublicKey? {
|
||||||
if let validatedConfiguration = validatedConfiguration {
|
if let validatedConfiguration = validatedConfiguration {
|
||||||
return validatedConfiguration.publicKey
|
return validatedConfiguration.publicKey
|
||||||
}
|
}
|
||||||
if let scratchPadPublicKey = scratchpad[.publicKey] {
|
if let scratchPadPublicKey = scratchpad[.publicKey] {
|
||||||
return Data(base64Key: scratchPadPublicKey)
|
return PublicKey(base64Key: scratchPadPublicKey)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -301,10 +304,8 @@ class TunnelViewModel {
|
|||||||
|
|
||||||
private static func createScratchPad(from config: PeerConfiguration) -> [PeerField: String] {
|
private static func createScratchPad(from config: PeerConfiguration) -> [PeerField: String] {
|
||||||
var scratchpad = [PeerField: String]()
|
var scratchpad = [PeerField: String]()
|
||||||
if let publicKey = config.publicKey.base64Key() {
|
scratchpad[.publicKey] = config.publicKey.base64Key
|
||||||
scratchpad[.publicKey] = publicKey
|
if let preSharedKey = config.preSharedKey?.base64Key {
|
||||||
}
|
|
||||||
if let preSharedKey = config.preSharedKey?.base64Key() {
|
|
||||||
scratchpad[.preSharedKey] = preSharedKey
|
scratchpad[.preSharedKey] = preSharedKey
|
||||||
}
|
}
|
||||||
if !config.allowedIPs.isEmpty {
|
if !config.allowedIPs.isEmpty {
|
||||||
@@ -337,14 +338,14 @@ class TunnelViewModel {
|
|||||||
fieldsWithError.insert(.publicKey)
|
fieldsWithError.insert(.publicKey)
|
||||||
return .error(tr("alertInvalidPeerMessagePublicKeyRequired"))
|
return .error(tr("alertInvalidPeerMessagePublicKeyRequired"))
|
||||||
}
|
}
|
||||||
guard let publicKey = Data(base64Key: publicKeyString), publicKey.count == TunnelConfiguration.keyLength else {
|
guard let publicKey = PublicKey(base64Key: publicKeyString) else {
|
||||||
fieldsWithError.insert(.publicKey)
|
fieldsWithError.insert(.publicKey)
|
||||||
return .error(tr("alertInvalidPeerMessagePublicKeyInvalid"))
|
return .error(tr("alertInvalidPeerMessagePublicKeyInvalid"))
|
||||||
}
|
}
|
||||||
var config = PeerConfiguration(publicKey: publicKey)
|
var config = PeerConfiguration(publicKey: publicKey)
|
||||||
var errorMessages = [String]()
|
var errorMessages = [String]()
|
||||||
if let preSharedKeyString = scratchpad[.preSharedKey] {
|
if let preSharedKeyString = scratchpad[.preSharedKey] {
|
||||||
if let preSharedKey = Data(base64Key: preSharedKeyString), preSharedKey.count == TunnelConfiguration.keyLength {
|
if let preSharedKey = PreSharedKey(base64Key: preSharedKeyString) {
|
||||||
config.preSharedKey = preSharedKey
|
config.preSharedKey = preSharedKey
|
||||||
} else {
|
} else {
|
||||||
fieldsWithError.insert(.preSharedKey)
|
fieldsWithError.insert(.preSharedKey)
|
||||||
@@ -559,7 +560,7 @@ class TunnelViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let peerPublicKeysArray = peerConfigurations.map { $0.publicKey }
|
let peerPublicKeysArray = peerConfigurations.map { $0.publicKey }
|
||||||
let peerPublicKeysSet = Set<Data>(peerPublicKeysArray)
|
let peerPublicKeysSet = Set<PublicKey>(peerPublicKeysArray)
|
||||||
if peerPublicKeysArray.count != peerPublicKeysSet.count {
|
if peerPublicKeysArray.count != peerPublicKeysSet.count {
|
||||||
return .error(tr("alertInvalidPeerMessagePublicKeyDuplicated"))
|
return .error(tr("alertInvalidPeerMessagePublicKeyDuplicated"))
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import os.log
|
import os.log
|
||||||
@@ -21,7 +21,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let window = UIWindow(frame: UIScreen.main.bounds)
|
let window = UIWindow(frame: UIScreen.main.bounds)
|
||||||
window.backgroundColor = .white
|
|
||||||
self.window = window
|
self.window = window
|
||||||
|
|
||||||
let mainVC = MainViewController()
|
let mainVC = MainViewController()
|
||||||
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 865 B After Width: | Height: | Size: 865 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import os.log
|
import os.log
|
||||||
@@ -64,6 +64,8 @@
|
|||||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>$(PRODUCT_NAME)</string>
|
<string>$(PRODUCT_NAME)</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@@ -9,8 +9,8 @@ class ButtonCell: UITableViewCell {
|
|||||||
set(value) { button.setTitle(value, for: .normal) }
|
set(value) { button.setTitle(value, for: .normal) }
|
||||||
}
|
}
|
||||||
var hasDestructiveAction: Bool {
|
var hasDestructiveAction: Bool {
|
||||||
get { return button.tintColor == .red }
|
get { return button.tintColor == .systemRed }
|
||||||
set(value) { button.tintColor = value ? .red : buttonStandardTintColor }
|
set(value) { button.tintColor = value ? .systemRed : buttonStandardTintColor }
|
||||||
}
|
}
|
||||||
var onTapped: (() -> Void)?
|
var onTapped: (() -> Void)?
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@@ -9,7 +9,11 @@ class KeyValueCell: UITableViewCell {
|
|||||||
let keyLabel = UILabel()
|
let keyLabel = UILabel()
|
||||||
keyLabel.font = UIFont.preferredFont(forTextStyle: .body)
|
keyLabel.font = UIFont.preferredFont(forTextStyle: .body)
|
||||||
keyLabel.adjustsFontForContentSizeCategory = true
|
keyLabel.adjustsFontForContentSizeCategory = true
|
||||||
keyLabel.textColor = .black
|
if #available(iOS 13.0, *) {
|
||||||
|
keyLabel.textColor = .label
|
||||||
|
} else {
|
||||||
|
keyLabel.textColor = .black
|
||||||
|
}
|
||||||
keyLabel.textAlignment = .left
|
keyLabel.textAlignment = .left
|
||||||
return keyLabel
|
return keyLabel
|
||||||
}()
|
}()
|
||||||
@@ -31,7 +35,11 @@ class KeyValueCell: UITableViewCell {
|
|||||||
valueTextField.autocapitalizationType = .none
|
valueTextField.autocapitalizationType = .none
|
||||||
valueTextField.autocorrectionType = .no
|
valueTextField.autocorrectionType = .no
|
||||||
valueTextField.spellCheckingType = .no
|
valueTextField.spellCheckingType = .no
|
||||||
valueTextField.textColor = .gray
|
if #available(iOS 13.0, *) {
|
||||||
|
valueTextField.textColor = .secondaryLabel
|
||||||
|
} else {
|
||||||
|
valueTextField.textColor = .gray
|
||||||
|
}
|
||||||
return valueTextField
|
return valueTextField
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -56,10 +64,18 @@ class KeyValueCell: UITableViewCell {
|
|||||||
|
|
||||||
var isValueValid = true {
|
var isValueValid = true {
|
||||||
didSet {
|
didSet {
|
||||||
if isValueValid {
|
if #available(iOS 13.0, *) {
|
||||||
keyLabel.textColor = .black
|
if isValueValid {
|
||||||
|
keyLabel.textColor = .label
|
||||||
|
} else {
|
||||||
|
keyLabel.textColor = .systemRed
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
keyLabel.textColor = .red
|
if isValueValid {
|
||||||
|
keyLabel.textColor = .black
|
||||||
|
} else {
|
||||||
|
keyLabel.textColor = .red
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@@ -16,7 +16,11 @@ class SwitchCell: UITableViewCell {
|
|||||||
get { return switchView.isEnabled }
|
get { return switchView.isEnabled }
|
||||||
set(value) {
|
set(value) {
|
||||||
switchView.isEnabled = value
|
switchView.isEnabled = value
|
||||||
textLabel?.textColor = value ? .black : .gray
|
if #available(iOS 13.0, *) {
|
||||||
|
textLabel?.textColor = value ? .label : .secondaryLabel
|
||||||
|
} else {
|
||||||
|
textLabel?.textColor = value ? .black : .gray
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@@ -28,7 +28,11 @@ class TextCell: UITableViewCell {
|
|||||||
override func prepareForReuse() {
|
override func prepareForReuse() {
|
||||||
super.prepareForReuse()
|
super.prepareForReuse()
|
||||||
message = ""
|
message = ""
|
||||||
setTextColor(.black)
|
if #available(iOS 13.0, *) {
|
||||||
|
setTextColor(.label)
|
||||||
|
} else {
|
||||||
|
setTextColor(.black)
|
||||||
|
}
|
||||||
setTextAlignment(.left)
|
setTextAlignment(.left)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@@ -30,7 +30,11 @@ class TunnelEditEditableKeyValueCell: TunnelEditKeyValueCell {
|
|||||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||||
|
|
||||||
copyableGesture = false
|
copyableGesture = false
|
||||||
valueTextField.textColor = .black
|
if #available(iOS 13.0, *) {
|
||||||
|
valueTextField.textColor = .label
|
||||||
|
} else {
|
||||||
|
valueTextField.textColor = .black
|
||||||
|
}
|
||||||
valueTextField.isEnabled = true
|
valueTextField.isEnabled = true
|
||||||
valueLabelScrollView.isScrollEnabled = false
|
valueLabelScrollView.isScrollEnabled = false
|
||||||
valueTextField.widthAnchor.constraint(equalTo: valueLabelScrollView.widthAnchor).isActive = true
|
valueTextField.widthAnchor.constraint(equalTo: valueLabelScrollView.widthAnchor).isActive = true
|
||||||
@@ -1,20 +1,20 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
class TunnelListCell: UITableViewCell {
|
class TunnelListCell: UITableViewCell {
|
||||||
var tunnel: TunnelContainer? {
|
var tunnel: TunnelContainer? {
|
||||||
didSet(value) {
|
didSet {
|
||||||
// Bind to the tunnel's name
|
// Bind to the tunnel's name
|
||||||
nameLabel.text = tunnel?.name ?? ""
|
nameLabel.text = tunnel?.name ?? ""
|
||||||
nameObservationToken = tunnel?.observe(\.name) { [weak self] tunnel, _ in
|
nameObservationToken = tunnel?.observe(\.name) { [weak self] tunnel, _ in
|
||||||
self?.nameLabel.text = tunnel.name
|
self?.nameLabel.text = tunnel.name
|
||||||
}
|
}
|
||||||
// Bind to the tunnel's status
|
// Bind to the tunnel's status
|
||||||
update(from: tunnel?.status)
|
update(from: tunnel?.status, animated: false)
|
||||||
statusObservationToken = tunnel?.observe(\.status) { [weak self] tunnel, _ in
|
statusObservationToken = tunnel?.observe(\.status) { [weak self] tunnel, _ in
|
||||||
self?.update(from: tunnel.status)
|
self?.update(from: tunnel.status, animated: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,88 +29,88 @@ class TunnelListCell: UITableViewCell {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
let busyIndicator: UIActivityIndicatorView = {
|
let busyIndicator: UIActivityIndicatorView = {
|
||||||
let busyIndicator = UIActivityIndicatorView(style: .gray)
|
let busyIndicator: UIActivityIndicatorView
|
||||||
|
if #available(iOS 13.0, *) {
|
||||||
|
busyIndicator = UIActivityIndicatorView(style: .medium)
|
||||||
|
} else {
|
||||||
|
busyIndicator = UIActivityIndicatorView(style: .gray)
|
||||||
|
}
|
||||||
busyIndicator.hidesWhenStopped = true
|
busyIndicator.hidesWhenStopped = true
|
||||||
return busyIndicator
|
return busyIndicator
|
||||||
}()
|
}()
|
||||||
|
|
||||||
let statusSwitch = UISwitch()
|
let statusSwitch = UISwitch()
|
||||||
|
|
||||||
private var statusObservationToken: AnyObject?
|
private var statusObservationToken: NSKeyValueObservation?
|
||||||
private var nameObservationToken: AnyObject?
|
private var nameObservationToken: NSKeyValueObservation?
|
||||||
|
|
||||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||||
|
|
||||||
contentView.addSubview(statusSwitch)
|
accessoryType = .disclosureIndicator
|
||||||
statusSwitch.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
|
for subview in [statusSwitch, busyIndicator, nameLabel] {
|
||||||
|
subview.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
contentView.addSubview(subview)
|
||||||
|
}
|
||||||
|
|
||||||
|
nameLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
||||||
|
|
||||||
|
let nameLabelBottomConstraint =
|
||||||
|
contentView.layoutMarginsGuide.bottomAnchor.constraint(equalToSystemSpacingBelow: nameLabel.bottomAnchor, multiplier: 1)
|
||||||
|
nameLabelBottomConstraint.priority = .defaultLow
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
statusSwitch.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
|
statusSwitch.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
|
||||||
contentView.trailingAnchor.constraint(equalTo: statusSwitch.trailingAnchor)
|
statusSwitch.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor),
|
||||||
])
|
statusSwitch.leadingAnchor.constraint(equalToSystemSpacingAfter: busyIndicator.trailingAnchor, multiplier: 1),
|
||||||
|
|
||||||
contentView.addSubview(busyIndicator)
|
|
||||||
busyIndicator.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
busyIndicator.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
|
|
||||||
statusSwitch.leadingAnchor.constraint(equalToSystemSpacingAfter: busyIndicator.trailingAnchor, multiplier: 1)
|
|
||||||
])
|
|
||||||
|
|
||||||
contentView.addSubview(nameLabel)
|
|
||||||
nameLabel.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
nameLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
|
||||||
let bottomAnchorConstraint = contentView.layoutMarginsGuide.bottomAnchor.constraint(equalToSystemSpacingBelow: nameLabel.bottomAnchor, multiplier: 1)
|
|
||||||
bottomAnchorConstraint.priority = .defaultLow
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
nameLabel.topAnchor.constraint(equalToSystemSpacingBelow: contentView.layoutMarginsGuide.topAnchor, multiplier: 1),
|
nameLabel.topAnchor.constraint(equalToSystemSpacingBelow: contentView.layoutMarginsGuide.topAnchor, multiplier: 1),
|
||||||
|
nameLabelBottomConstraint,
|
||||||
nameLabel.leadingAnchor.constraint(equalToSystemSpacingAfter: contentView.layoutMarginsGuide.leadingAnchor, multiplier: 1),
|
nameLabel.leadingAnchor.constraint(equalToSystemSpacingAfter: contentView.layoutMarginsGuide.leadingAnchor, multiplier: 1),
|
||||||
busyIndicator.leadingAnchor.constraint(equalToSystemSpacingAfter: nameLabel.trailingAnchor, multiplier: 1),
|
|
||||||
bottomAnchorConstraint
|
|
||||||
])
|
|
||||||
|
|
||||||
accessoryType = .disclosureIndicator
|
busyIndicator.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
|
||||||
|
busyIndicator.leadingAnchor.constraint(equalToSystemSpacingAfter: nameLabel.trailingAnchor, multiplier: 1)
|
||||||
|
])
|
||||||
|
|
||||||
statusSwitch.addTarget(self, action: #selector(switchToggled), for: .valueChanged)
|
statusSwitch.addTarget(self, action: #selector(switchToggled), for: .valueChanged)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func switchToggled() {
|
|
||||||
onSwitchToggled?(statusSwitch.isOn)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func update(from status: TunnelStatus?) {
|
|
||||||
guard let status = status else {
|
|
||||||
reset()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(200)) { [weak statusSwitch, weak busyIndicator] in
|
|
||||||
guard let statusSwitch = statusSwitch, let busyIndicator = busyIndicator else { return }
|
|
||||||
statusSwitch.isOn = !(status == .deactivating || status == .inactive)
|
|
||||||
statusSwitch.isUserInteractionEnabled = (status == .inactive || status == .active)
|
|
||||||
if status == .inactive || status == .active {
|
|
||||||
busyIndicator.stopAnimating()
|
|
||||||
} else {
|
|
||||||
busyIndicator.startAnimating()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder aDecoder: NSCoder) {
|
required init?(coder aDecoder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func prepareForReuse() {
|
||||||
|
super.prepareForReuse()
|
||||||
|
reset(animated: false)
|
||||||
|
}
|
||||||
|
|
||||||
override func setEditing(_ editing: Bool, animated: Bool) {
|
override func setEditing(_ editing: Bool, animated: Bool) {
|
||||||
super.setEditing(editing, animated: animated)
|
super.setEditing(editing, animated: animated)
|
||||||
statusSwitch.isEnabled = !editing
|
statusSwitch.isEnabled = !editing
|
||||||
}
|
}
|
||||||
|
|
||||||
private func reset() {
|
@objc private func switchToggled() {
|
||||||
statusSwitch.isOn = false
|
onSwitchToggled?(statusSwitch.isOn)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func update(from status: TunnelStatus?, animated: Bool) {
|
||||||
|
guard let status = status else {
|
||||||
|
reset(animated: animated)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
statusSwitch.setOn(!(status == .deactivating || status == .inactive), animated: animated)
|
||||||
|
statusSwitch.isUserInteractionEnabled = (status == .inactive || status == .active)
|
||||||
|
if status == .inactive || status == .active {
|
||||||
|
busyIndicator.stopAnimating()
|
||||||
|
} else {
|
||||||
|
busyIndicator.startAnimating()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func reset(animated: Bool) {
|
||||||
|
statusSwitch.setOn(false, animated: animated)
|
||||||
statusSwitch.isUserInteractionEnabled = false
|
statusSwitch.isUserInteractionEnabled = false
|
||||||
busyIndicator.stopAnimating()
|
busyIndicator.stopAnimating()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func prepareForReuse() {
|
|
||||||
super.prepareForReuse()
|
|
||||||
reset()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@@ -15,9 +15,15 @@ class LogViewController: UIViewController {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
let busyIndicator: UIActivityIndicatorView = {
|
let busyIndicator: UIActivityIndicatorView = {
|
||||||
let busyIndicator = UIActivityIndicatorView(style: .gray)
|
if #available(iOS 13.0, *) {
|
||||||
busyIndicator.hidesWhenStopped = true
|
let busyIndicator = UIActivityIndicatorView(style: .medium)
|
||||||
return busyIndicator
|
busyIndicator.hidesWhenStopped = true
|
||||||
|
return busyIndicator
|
||||||
|
} else {
|
||||||
|
let busyIndicator = UIActivityIndicatorView(style: .gray)
|
||||||
|
busyIndicator.hidesWhenStopped = true
|
||||||
|
return busyIndicator
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
let paragraphStyle: NSParagraphStyle = {
|
let paragraphStyle: NSParagraphStyle = {
|
||||||
@@ -35,7 +41,11 @@ class LogViewController: UIViewController {
|
|||||||
|
|
||||||
override func loadView() {
|
override func loadView() {
|
||||||
view = UIView()
|
view = UIView()
|
||||||
view.backgroundColor = .white
|
if #available(iOS 13.0, *) {
|
||||||
|
view.backgroundColor = .systemBackground
|
||||||
|
} else {
|
||||||
|
view.backgroundColor = .white
|
||||||
|
}
|
||||||
|
|
||||||
view.addSubview(textView)
|
view.addSubview(textView)
|
||||||
textView.translatesAutoresizingMaskIntoConstraints = false
|
textView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
@@ -81,12 +91,18 @@ class LogViewController: UIViewController {
|
|||||||
let richText = NSMutableAttributedString()
|
let richText = NSMutableAttributedString()
|
||||||
let bodyFont = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.body)
|
let bodyFont = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.body)
|
||||||
let captionFont = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.caption1)
|
let captionFont = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.caption1)
|
||||||
let lightGrayColor = UIColor(white: 0.88, alpha: 1.0)
|
|
||||||
|
|
||||||
for logEntry in fetchedLogEntries {
|
for logEntry in fetchedLogEntries {
|
||||||
let bgColor = self.isNextLineHighlighted ? lightGrayColor : UIColor.white
|
var bgColor: UIColor
|
||||||
let timestampText = NSAttributedString(string: logEntry.timestamp + "\n", attributes: [.font: captionFont, .backgroundColor: bgColor, .paragraphStyle: self.paragraphStyle])
|
var fgColor: UIColor
|
||||||
let messageText = NSAttributedString(string: logEntry.message + "\n", attributes: [.font: bodyFont, .backgroundColor: bgColor, .paragraphStyle: self.paragraphStyle])
|
if #available(iOS 13.0, *) {
|
||||||
|
bgColor = self.isNextLineHighlighted ? .systemGray3 : .systemBackground
|
||||||
|
fgColor = .label
|
||||||
|
} else {
|
||||||
|
bgColor = self.isNextLineHighlighted ? UIColor(white: 0.88, alpha: 1.0) : UIColor.white
|
||||||
|
fgColor = .black
|
||||||
|
}
|
||||||
|
let timestampText = NSAttributedString(string: logEntry.timestamp + "\n", attributes: [.font: captionFont, .backgroundColor: bgColor, .foregroundColor: fgColor, .paragraphStyle: self.paragraphStyle])
|
||||||
|
let messageText = NSAttributedString(string: logEntry.message + "\n", attributes: [.font: bodyFont, .backgroundColor: bgColor, .foregroundColor: fgColor, .paragraphStyle: self.paragraphStyle])
|
||||||
richText.append(timestampText)
|
richText.append(timestampText)
|
||||||
richText.append(messageText)
|
richText.append(messageText)
|
||||||
self.isNextLineHighlighted.toggle()
|
self.isNextLineHighlighted.toggle()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@@ -11,7 +11,11 @@ class MainViewController: UISplitViewController {
|
|||||||
|
|
||||||
init() {
|
init() {
|
||||||
let detailVC = UIViewController()
|
let detailVC = UIViewController()
|
||||||
detailVC.view.backgroundColor = .white
|
if #available(iOS 13.0, *) {
|
||||||
|
detailVC.view.backgroundColor = .systemBackground
|
||||||
|
} else {
|
||||||
|
detailVC.view.backgroundColor = .white
|
||||||
|
}
|
||||||
let detailNC = UINavigationController(rootViewController: detailVC)
|
let detailNC = UINavigationController(rootViewController: detailVC)
|
||||||
|
|
||||||
let masterVC = TunnelsListTableViewController()
|
let masterVC = TunnelsListTableViewController()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import AVFoundation
|
import AVFoundation
|
||||||
import UIKit
|
import UIKit
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import SystemConfiguration.CaptiveNetwork
|
import SystemConfiguration.CaptiveNetwork
|
||||||
@@ -176,7 +176,11 @@ extension SSIDOptionEditTableViewController {
|
|||||||
private func noSSIDsCell(for tableView: UITableView, at indexPath: IndexPath) -> UITableViewCell {
|
private func noSSIDsCell(for tableView: UITableView, at indexPath: IndexPath) -> UITableViewCell {
|
||||||
let cell: TextCell = tableView.dequeueReusableCell(for: indexPath)
|
let cell: TextCell = tableView.dequeueReusableCell(for: indexPath)
|
||||||
cell.message = tr("tunnelOnDemandNoSSIDs")
|
cell.message = tr("tunnelOnDemandNoSSIDs")
|
||||||
cell.setTextColor(.gray)
|
if #available(iOS 13.0, *) {
|
||||||
|
cell.setTextColor(.secondaryLabel)
|
||||||
|
} else {
|
||||||
|
cell.setTextColor(.gray)
|
||||||
|
}
|
||||||
cell.setTextAlignment(.center)
|
cell.setTextAlignment(.center)
|
||||||
return cell
|
return cell
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import os.log
|
import os.log
|
||||||
@@ -11,6 +11,7 @@ class SettingsTableViewController: UITableViewController {
|
|||||||
case goBackendVersion
|
case goBackendVersion
|
||||||
case exportZipArchive
|
case exportZipArchive
|
||||||
case viewLog
|
case viewLog
|
||||||
|
case donateLink
|
||||||
|
|
||||||
var localizedUIString: String {
|
var localizedUIString: String {
|
||||||
switch self {
|
switch self {
|
||||||
@@ -18,12 +19,13 @@ class SettingsTableViewController: UITableViewController {
|
|||||||
case .goBackendVersion: return tr("settingsVersionKeyWireGuardGoBackend")
|
case .goBackendVersion: return tr("settingsVersionKeyWireGuardGoBackend")
|
||||||
case .exportZipArchive: return tr("settingsExportZipButtonTitle")
|
case .exportZipArchive: return tr("settingsExportZipButtonTitle")
|
||||||
case .viewLog: return tr("settingsViewLogButtonTitle")
|
case .viewLog: return tr("settingsViewLogButtonTitle")
|
||||||
|
case .donateLink: return tr("donateLink")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let settingsFieldsBySection: [[SettingsFields]] = [
|
let settingsFieldsBySection: [[SettingsFields]] = [
|
||||||
[.iosAppVersion, .goBackendVersion],
|
[.iosAppVersion, .goBackendVersion, .donateLink],
|
||||||
[.exportZipArchive],
|
[.exportZipArchive],
|
||||||
[.viewLog]
|
[.viewLog]
|
||||||
]
|
]
|
||||||
@@ -144,8 +146,8 @@ extension SettingsTableViewController {
|
|||||||
cell.copyableGesture = false
|
cell.copyableGesture = false
|
||||||
cell.key = field.localizedUIString
|
cell.key = field.localizedUIString
|
||||||
if field == .iosAppVersion {
|
if field == .iosAppVersion {
|
||||||
var appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown version"
|
var appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "Unknown version"
|
||||||
if let appBuild = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
|
if let appBuild = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String {
|
||||||
appVersion += " (\(appBuild))"
|
appVersion += " (\(appBuild))"
|
||||||
}
|
}
|
||||||
cell.value = appVersion
|
cell.value = appVersion
|
||||||
@@ -160,14 +162,23 @@ extension SettingsTableViewController {
|
|||||||
self?.exportConfigurationsAsZipFile(sourceView: cell.button)
|
self?.exportConfigurationsAsZipFile(sourceView: cell.button)
|
||||||
}
|
}
|
||||||
return cell
|
return cell
|
||||||
} else {
|
} else if field == .viewLog {
|
||||||
assert(field == .viewLog)
|
|
||||||
let cell: ButtonCell = tableView.dequeueReusableCell(for: indexPath)
|
let cell: ButtonCell = tableView.dequeueReusableCell(for: indexPath)
|
||||||
cell.buttonText = field.localizedUIString
|
cell.buttonText = field.localizedUIString
|
||||||
cell.onTapped = { [weak self] in
|
cell.onTapped = { [weak self] in
|
||||||
self?.presentLogView()
|
self?.presentLogView()
|
||||||
}
|
}
|
||||||
return cell
|
return cell
|
||||||
|
} else if field == .donateLink {
|
||||||
|
let cell: ButtonCell = tableView.dequeueReusableCell(for: indexPath)
|
||||||
|
cell.buttonText = field.localizedUIString
|
||||||
|
cell.onTapped = {
|
||||||
|
if let url = URL(string: "https://www.wireguard.com/donations/"), UIApplication.shared.canOpenURL(url) {
|
||||||
|
UIApplication.shared.open(url, options: [:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cell
|
||||||
}
|
}
|
||||||
|
fatalError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ class TunnelDetailTableViewController: UITableViewController {
|
|||||||
let editVC = TunnelEditTableViewController(tunnelsManager: self.tunnelsManager, tunnel: self.tunnel)
|
let editVC = TunnelEditTableViewController(tunnelsManager: self.tunnelsManager, tunnel: self.tunnel)
|
||||||
editVC.delegate = self
|
editVC.delegate = self
|
||||||
let editNC = UINavigationController(rootViewController: editVC)
|
let editNC = UINavigationController(rootViewController: editVC)
|
||||||
editNC.modalPresentationStyle = .formSheet
|
editNC.modalPresentationStyle = .fullScreen
|
||||||
self.present(editNC, animated: true)
|
self.present(editNC, animated: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,8 +152,8 @@ class TunnelDetailTableViewController: UITableViewController {
|
|||||||
}
|
}
|
||||||
}!
|
}!
|
||||||
let firstPeerSectionIndex = interfaceSectionIndex + 1
|
let firstPeerSectionIndex = interfaceSectionIndex + 1
|
||||||
var interfaceFieldIsVisible = self.interfaceFieldIsVisible
|
let interfaceFieldIsVisible = self.interfaceFieldIsVisible
|
||||||
var peerFieldIsVisible = self.peerFieldIsVisible
|
let peerFieldIsVisible = self.peerFieldIsVisible
|
||||||
|
|
||||||
func handleSectionFieldsModified<T>(fields: [T], fieldIsVisible: [Bool], section: Int, changes: [T: TunnelViewModel.Changes.FieldChange]) {
|
func handleSectionFieldsModified<T>(fields: [T], fieldIsVisible: [Bool], section: Int, changes: [T: TunnelViewModel.Changes.FieldChange]) {
|
||||||
for (index, field) in fields.enumerated() {
|
for (index, field) in fields.enumerated() {
|
||||||
@@ -343,10 +343,8 @@ extension TunnelDetailTableViewController {
|
|||||||
text = tr("tunnelStatusWaiting")
|
text = tr("tunnelStatusWaiting")
|
||||||
}
|
}
|
||||||
cell.textLabel?.text = text
|
cell.textLabel?.text = text
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(200)) { [weak cell] in
|
cell.switchView.isOn = !(status == .deactivating || status == .inactive)
|
||||||
cell?.switchView.isOn = !(status == .deactivating || status == .inactive)
|
cell.switchView.isUserInteractionEnabled = (status == .inactive || status == .active)
|
||||||
cell?.switchView.isUserInteractionEnabled = (status == .inactive || status == .active)
|
|
||||||
}
|
|
||||||
cell.isEnabled = status == .active || status == .inactive
|
cell.isEnabled = status == .active || status == .inactive
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@@ -214,7 +214,7 @@ extension TunnelEditTableViewController {
|
|||||||
cell.onTapped = { [weak self] in
|
cell.onTapped = { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
||||||
self.tunnelViewModel.interfaceData[.privateKey] = Curve25519.generatePrivateKey().base64Key() ?? ""
|
self.tunnelViewModel.interfaceData[.privateKey] = PrivateKey().base64Key
|
||||||
if let privateKeyRow = self.interfaceFieldsBySection[indexPath.section].firstIndex(of: .privateKey),
|
if let privateKeyRow = self.interfaceFieldsBySection[indexPath.section].firstIndex(of: .privateKey),
|
||||||
let publicKeyRow = self.interfaceFieldsBySection[indexPath.section].firstIndex(of: .publicKey) {
|
let publicKeyRow = self.interfaceFieldsBySection[indexPath.section].firstIndex(of: .publicKey) {
|
||||||
let privateKeyIndex = IndexPath(row: privateKeyRow, section: indexPath.section)
|
let privateKeyIndex = IndexPath(row: privateKeyRow, section: indexPath.section)
|
||||||
@@ -266,7 +266,7 @@ extension TunnelEditTableViewController {
|
|||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
let isAllowedIPsChanged = self.tunnelViewModel.updateDNSServersInAllowedIPsIfRequired(oldDNSServers: oldValue, newDNSServers: newValue)
|
let isAllowedIPsChanged = self.tunnelViewModel.updateDNSServersInAllowedIPsIfRequired(oldDNSServers: oldValue, newDNSServers: newValue)
|
||||||
if isAllowedIPsChanged {
|
if isAllowedIPsChanged {
|
||||||
let section = self.sections.firstIndex { if case .peer(_) = $0 { return true } else { return false } }
|
let section = self.sections.firstIndex { if case .peer = $0 { return true } else { return false } }
|
||||||
if let section = section, let row = self.peerFields.firstIndex(of: .allowedIPs) {
|
if let section = section, let row = self.peerFields.firstIndex(of: .allowedIPs) {
|
||||||
self.tableView.reloadRows(at: [IndexPath(row: row, section: section)], with: .none)
|
self.tableView.reloadRows(at: [IndexPath(row: row, section: section)], with: .none)
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import MobileCoreServices
|
import MobileCoreServices
|
||||||
@@ -32,7 +32,12 @@ class TunnelsListTableViewController: UIViewController {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
let busyIndicator: UIActivityIndicatorView = {
|
let busyIndicator: UIActivityIndicatorView = {
|
||||||
let busyIndicator = UIActivityIndicatorView(style: .gray)
|
let busyIndicator: UIActivityIndicatorView
|
||||||
|
if #available(iOS 13.0, *) {
|
||||||
|
busyIndicator = UIActivityIndicatorView(style: .medium)
|
||||||
|
} else {
|
||||||
|
busyIndicator = UIActivityIndicatorView(style: .gray)
|
||||||
|
}
|
||||||
busyIndicator.hidesWhenStopped = true
|
busyIndicator.hidesWhenStopped = true
|
||||||
return busyIndicator
|
return busyIndicator
|
||||||
}()
|
}()
|
||||||
@@ -46,7 +51,11 @@ class TunnelsListTableViewController: UIViewController {
|
|||||||
|
|
||||||
override func loadView() {
|
override func loadView() {
|
||||||
view = UIView()
|
view = UIView()
|
||||||
view.backgroundColor = .white
|
if #available(iOS 13.0, *) {
|
||||||
|
view.backgroundColor = .systemBackground
|
||||||
|
} else {
|
||||||
|
view.backgroundColor = .white
|
||||||
|
}
|
||||||
|
|
||||||
tableView.dataSource = self
|
tableView.dataSource = self
|
||||||
tableView.delegate = self
|
tableView.delegate = self
|
||||||
@@ -178,7 +187,7 @@ class TunnelsListTableViewController: UIViewController {
|
|||||||
func presentViewControllerForTunnelCreation(tunnelsManager: TunnelsManager) {
|
func presentViewControllerForTunnelCreation(tunnelsManager: TunnelsManager) {
|
||||||
let editVC = TunnelEditTableViewController(tunnelsManager: tunnelsManager)
|
let editVC = TunnelEditTableViewController(tunnelsManager: tunnelsManager)
|
||||||
let editNC = UINavigationController(rootViewController: editVC)
|
let editNC = UINavigationController(rootViewController: editVC)
|
||||||
editNC.modalPresentationStyle = .formSheet
|
editNC.modalPresentationStyle = .fullScreen
|
||||||
present(editNC, animated: true)
|
present(editNC, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,7 +398,11 @@ extension TunnelsListTableViewController: TunnelsManagerListDelegate {
|
|||||||
(splitViewController.viewControllers[0] as? UINavigationController)?.popToRootViewController(animated: false)
|
(splitViewController.viewControllers[0] as? UINavigationController)?.popToRootViewController(animated: false)
|
||||||
} else {
|
} else {
|
||||||
let detailVC = UIViewController()
|
let detailVC = UIViewController()
|
||||||
detailVC.view.backgroundColor = .white
|
if #available(iOS 13.0, *) {
|
||||||
|
detailVC.view.backgroundColor = .systemBackground
|
||||||
|
} else {
|
||||||
|
detailVC.view.backgroundColor = .white
|
||||||
|
}
|
||||||
let detailNC = UINavigationController(rootViewController: detailVC)
|
let detailNC = UINavigationController(rootViewController: detailVC)
|
||||||
splitViewController.showDetailViewController(detailNC, sender: self)
|
splitViewController.showDetailViewController(detailNC, sender: self)
|
||||||
}
|
}
|
||||||
@@ -402,12 +415,12 @@ extension TunnelsListTableViewController: TunnelsManagerListDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension UISplitViewController {
|
extension UISplitViewController {
|
||||||
func showDetailViewController(_ vc: UIViewController, sender: Any?, animated: Bool) {
|
func showDetailViewController(_ viewController: UIViewController, sender: Any?, animated: Bool) {
|
||||||
if animated {
|
if animated {
|
||||||
showDetailViewController(vc, sender: sender)
|
showDetailViewController(viewController, sender: sender)
|
||||||
} else {
|
} else {
|
||||||
UIView.performWithoutAnimation {
|
UIView.performWithoutAnimation {
|
||||||
showDetailViewController(vc, sender: sender)
|
showDetailViewController(viewController, sender: sender)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import Cocoa
|
import Cocoa
|
||||||
import ServiceManagement
|
import ServiceManagement
|
||||||
@@ -213,7 +213,8 @@ extension AppDelegate {
|
|||||||
NSApp.activate(ignoringOtherApps: true)
|
NSApp.activate(ignoringOtherApps: true)
|
||||||
NSApp.orderFrontStandardAboutPanel(options: [
|
NSApp.orderFrontStandardAboutPanel(options: [
|
||||||
.applicationVersion: appVersionString,
|
.applicationVersion: appVersionString,
|
||||||
.version: ""
|
.version: "",
|
||||||
|
.credits: ""
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
// Copyright © 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |