Commit 86cf333c authored by Jose Blaya's avatar Jose Blaya
Browse files

Merge branch '173-implement-wireguard-protocol' into 'develop'

Resolve "Implement WireGuard protocol"

See merge request ios/client-library-apple!229
parents 7b70fcd7 bcceea42
Pod::Spec.new do |s|
s.name = "PIALibrary"
s.version = "2.2.4"
s.version = "2.3.0"
s.summary = "PIA client library in Swift."
s.homepage = "https://www.privateinternetaccess.com/"
......@@ -40,6 +40,7 @@ Pod::Spec.new do |s|
p.pod_target_xcconfig = { "APPLICATION_EXTENSION_API_ONLY" => "YES" }
p.dependency "TunnelKit"
p.dependency "PIAWireguard"
p.dependency "PIALibrary/Library"
end
......
......@@ -278,6 +278,7 @@
DD6DC5B921B6A83400F9D538 /* UIViewLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6DC5B821B6A83400F9D538 /* UIViewLoading.swift */; };
DD6DC5BC21B6A8FC00F9D538 /* pia-spinner.json in Resources */ = {isa = PBXBuildFile; fileRef = DD6DC5BB21B6A8FC00F9D538 /* pia-spinner.json */; };
DD6FB0372224355600A84F05 /* UIDevice+WiFi.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6FB0362224355600A84F05 /* UIDevice+WiFi.swift */; };
DD7411A923EC35B40058CEF3 /* PIAWGTunnelProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD7411A823EC35B40058CEF3 /* PIAWGTunnelProfile.swift */; };
DD76292821ECDFF80092DF50 /* Usage.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD76292721ECDFF80092DF50 /* Usage.swift */; };
DD76292921ECDFF80092DF50 /* Usage.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD76292721ECDFF80092DF50 /* Usage.swift */; };
DD76292E21ECEC3F0092DF50 /* DataManipulation.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD76292D21ECEC3F0092DF50 /* DataManipulation.swift */; };
......@@ -304,6 +305,7 @@
DDD824EA2189CD5700151709 /* NavigationLogoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD824E92189CD5700151709 /* NavigationLogoView.swift */; };
DDE27E0422E1B1A700503A89 /* ProductTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE27E0322E1B1A700503A89 /* ProductTests.swift */; };
DDE93C5722F9847E0054FE28 /* PurchaseTrialViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE93C5622F9847E0054FE28 /* PurchaseTrialViewController.swift */; };
DDF7F73F2405846800A671C7 /* PIAWGTunnelProvider+Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF7F73E2405846800A671C7 /* PIAWGTunnelProvider+Profile.swift */; };
DDFCFAA821E924A70081F235 /* TileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFCFAA721E924A70081F235 /* TileProvider.swift */; };
DDFCFAA921E924AD0081F235 /* TileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFCFAA721E924A70081F235 /* TileProvider.swift */; };
DDFCFAAB21E925160081F235 /* DefaultTileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFCFAAA21E925160081F235 /* DefaultTileProvider.swift */; };
......@@ -583,6 +585,7 @@
DD6DC5B821B6A83400F9D538 /* UIViewLoading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewLoading.swift; sourceTree = "<group>"; };
DD6DC5BB21B6A8FC00F9D538 /* pia-spinner.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "pia-spinner.json"; sourceTree = "<group>"; };
DD6FB0362224355600A84F05 /* UIDevice+WiFi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+WiFi.swift"; sourceTree = "<group>"; };
DD7411A823EC35B40058CEF3 /* PIAWGTunnelProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PIAWGTunnelProfile.swift; sourceTree = "<group>"; };
DD76292721ECDFF80092DF50 /* Usage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Usage.swift; sourceTree = "<group>"; };
DD76292D21ECEC3F0092DF50 /* DataManipulation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataManipulation.swift; sourceTree = "<group>"; };
DD86BAF021EF5B6D004A988F /* UIViewAutolayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewAutolayout.swift; sourceTree = "<group>"; };
......@@ -602,6 +605,7 @@
DDD824E92189CD5700151709 /* NavigationLogoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationLogoView.swift; sourceTree = "<group>"; };
DDE27E0322E1B1A700503A89 /* ProductTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ProductTests.swift; path = "../../../../../../System/Volumes/Data/Users/ueshiba/Projects/PIA/client-library-apple/PIALibraryTests/ProductTests.swift"; sourceTree = "<group>"; };
DDE93C5622F9847E0054FE28 /* PurchaseTrialViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PurchaseTrialViewController.swift; sourceTree = "<group>"; };
DDF7F73E2405846800A671C7 /* PIAWGTunnelProvider+Profile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PIAWGTunnelProvider+Profile.swift"; sourceTree = "<group>"; };
DDFCFAA721E924A70081F235 /* TileProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileProvider.swift; sourceTree = "<group>"; };
DDFCFAAA21E925160081F235 /* DefaultTileProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultTileProvider.swift; sourceTree = "<group>"; };
DDFCFAAC21E925B60081F235 /* TileableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TileableCell.swift; sourceTree = "<group>"; };
......@@ -1113,7 +1117,9 @@
isa = PBXGroup;
children = (
0EFEB4BF2007784A00F81029 /* PIATunnelProvider+Profile.swift */,
DDF7F73E2405846800A671C7 /* PIAWGTunnelProvider+Profile.swift */,
0EFEB4C02007784A00F81029 /* PIATunnelProfile.swift */,
DD7411A823EC35B40058CEF3 /* PIAWGTunnelProfile.swift */,
);
path = VPN;
sourceTree = "<group>";
......@@ -1502,6 +1508,7 @@
"${BUILT_PRODUCTS_DIR}/FXPageControl/FXPageControl.framework",
"${BUILT_PRODUCTS_DIR}/Gloss/Gloss.framework",
"${PODS_ROOT}/OpenSSL-Apple/frameworks/iPhone/openssl.framework",
"${BUILT_PRODUCTS_DIR}/PIAWireguard/PIAWireguard.framework",
"${BUILT_PRODUCTS_DIR}/PopupDialog/PopupDialog.framework",
"${BUILT_PRODUCTS_DIR}/QuickLayout/QuickLayout.framework",
"${BUILT_PRODUCTS_DIR}/ReachabilitySwift/Reachability.framework",
......@@ -1517,6 +1524,7 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FXPageControl.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Gloss.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PIAWireguard.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PopupDialog.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/QuickLayout.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework",
......@@ -1542,6 +1550,7 @@
"${BUILT_PRODUCTS_DIR}/FXPageControl/FXPageControl.framework",
"${BUILT_PRODUCTS_DIR}/Gloss/Gloss.framework",
"${PODS_ROOT}/OpenSSL-Apple/frameworks/iPhone/openssl.framework",
"${BUILT_PRODUCTS_DIR}/PIAWireguard/PIAWireguard.framework",
"${BUILT_PRODUCTS_DIR}/PopupDialog/PopupDialog.framework",
"${BUILT_PRODUCTS_DIR}/QuickLayout/QuickLayout.framework",
"${BUILT_PRODUCTS_DIR}/ReachabilitySwift/Reachability.framework",
......@@ -1557,6 +1566,7 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FXPageControl.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Gloss.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PIAWireguard.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PopupDialog.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/QuickLayout.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework",
......@@ -1815,6 +1825,7 @@
0EA8072F20A1E7C60033EC1A /* GlossRedeem.swift in Sources */,
0EA4C4311FDDD48F0041C3D8 /* Server.swift in Sources */,
DD56E3F4225F5D22002EDFB2 /* GlossProduct.swift in Sources */,
DD7411A923EC35B40058CEF3 /* PIAWGTunnelProfile.swift in Sources */,
84577FC5213D9B4D006DEC3D /* UILabel+LineHeight.swift in Sources */,
0EB9667E1FDF36490086ABC2 /* GlossParser.swift in Sources */,
DDA4A7BE21F5C31400A02ACD /* IKEv2Profile.swift in Sources */,
......@@ -1830,6 +1841,7 @@
DDD824E5218996CD00151709 /* Pages.swift in Sources */,
0E0E5B131F8297DE00022CD0 /* KeychainStore.swift in Sources */,
0E0E5B0D1F8297BD00022CD0 /* PlainStore.swift in Sources */,
DDF7F73F2405846800A671C7 /* PIAWGTunnelProvider+Profile.swift in Sources */,
0EE78AEE1F818720002E4CDD /* LibraryCallback.swift in Sources */,
0E53A8561FE5D770000C2A18 /* MockWebServices.swift in Sources */,
DDC0841322EB07FB00DA2701 /* GlossInvitesInformation.swift in Sources */,
......@@ -2264,10 +2276,12 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_BITCODE = YES;
INFOPLIST_FILE = PIALibrary/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 2.2.4;
MARKETING_VERSION = 2.3.0;
PRODUCT_BUNDLE_IDENTIFIER = com.privateinternetaccess.apple.PIALibrary;
PRODUCT_NAME = PIALibrary;
PROVISIONING_PROFILE_SPECIFIER = "";
......@@ -2290,10 +2304,12 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_BITCODE = YES;
INFOPLIST_FILE = PIALibrary/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 2.2.4;
MARKETING_VERSION = 2.3.0;
PRODUCT_BUNDLE_IDENTIFIER = com.privateinternetaccess.apple.PIALibrary;
PRODUCT_NAME = PIALibrary;
PROVISIONING_PROFILE_SPECIFIER = "";
......
......@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.2.4</string>
<string>2.3.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
......
......@@ -99,9 +99,10 @@ public protocol VPNProvider: class {
Reconnects to the VPN.
- Parameter delay: The delay in milliseconds after which the reconnection is issue.
- Parameter forceDisconnect: Boolean to indicate if we want to disconnect the VPN before reconnect..
- Parameter callback: Returns `nil` on success.
*/
func reconnect(after delay: Int?, _ callback: SuccessLibraryCallback?)
func reconnect(after delay: Int?, forceDisconnect: Bool, _ callback: SuccessLibraryCallback?)
/**
Submits the debug log associated with the current VPN connection.
......@@ -118,6 +119,12 @@ public protocol VPNProvider: class {
func dataUsage(_ callback: LibraryCallback<Usage>?)
}
public extension VPNProvider {
public func reconnect(after delay: Int?, forceDisconnect: Bool = false, _ callback: SuccessLibraryCallback?) {
return reconnect(after: delay, forceDisconnect: forceDisconnect, callback)
}
}
extension VPNProvider {
/// Shortcut for `(vpnStatus == .connected)`.
......
......@@ -32,9 +32,12 @@ public enum ServerError: Error {
/// Represents a VPN server.
public class Server: Hashable {
/// Serial host
public let serial: String
/// Represents a VPN server address endpoint.
public struct Address: CustomStringConvertible {
/// The endpoint hostname.
public let hostname: String
......@@ -99,6 +102,7 @@ public class Server: Hashable {
/// :nodoc:
public init(
serial: String,
name: String,
country: String,
hostname: String,
......@@ -106,6 +110,7 @@ public class Server: Hashable {
bestOpenVPNAddressForUDP: Address?,
pingAddress: Address?) {
self.serial = serial
self.name = name
self.country = country
self.hostname = hostname
......
......@@ -207,7 +207,7 @@ class DefaultVPNProvider: VPNProvider, ConfigurationAccess, DatabaseAccess, Pref
activeProfile.updatePreferences(callback)
}
func reconnect(after delay: Int?, _ callback: SuccessLibraryCallback?) {
func reconnect(after delay: Int?, forceDisconnect: Bool = false, _ callback: SuccessLibraryCallback?) {
guard accessedProviders.accountProvider.isLoggedIn else {
preconditionFailure()
}
......@@ -215,11 +215,18 @@ class DefaultVPNProvider: VPNProvider, ConfigurationAccess, DatabaseAccess, Pref
preconditionFailure()
}
let fallbackDelay = delay ?? accessedConfiguration.vpnReconnectionDelay
activeProfile.disconnect { (error) in
if let _ = error {
callback?(error)
return
if forceDisconnect {
activeProfile.disconnect { (error) in
if let _ = error {
callback?(error)
return
}
Macros.dispatch(after: .milliseconds(fallbackDelay)) {
activeProfile.connect(withConfiguration: self.vpnClientConfiguration(), callback)
}
}
} else {
Macros.dispatch(after: .milliseconds(fallbackDelay)) {
activeProfile.connect(withConfiguration: self.vpnClientConfiguration(), callback)
}
......
......@@ -27,6 +27,11 @@ class GlossServer: GlossParser {
let parsed: Server
required init?(json: JSON) {
guard let serial: String = "serial" <~~ json else {
return nil
}
guard let name: String = "name" <~~ json else {
return nil
}
......@@ -55,6 +60,7 @@ class GlossServer: GlossParser {
}
parsed = Server(
serial: serial,
name: name,
country: country,
hostname: hostname,
......@@ -69,6 +75,7 @@ class GlossServer: GlossParser {
extension Server: JSONEncodable {
public func toJSON() -> JSON? {
return jsonify([
"serial" ~~> serial,
"name" ~~> name,
"country" ~~> country,
"dns" ~~> hostname,
......
......@@ -28,7 +28,7 @@ import SwiftyBeaver
private let log = SwiftyBeaver.self
class PIAWebServices: WebServices, ConfigurationAccess {
private static let serversVersion = 60
private static let serversVersion = 1001
/***
Generates a new auth token for the specific user
......
......@@ -36,6 +36,7 @@ public class MockServerProvider: ServerProvider, DatabaseAccess, WebServicesCons
public init() {
mockServers = [
Server(
serial: "8a55f03812851897f6e43b2ae22b1234",
name: "France",
country: "fr",
hostname: "france.example.com",
......@@ -43,6 +44,7 @@ public class MockServerProvider: ServerProvider, DatabaseAccess, WebServicesCons
bestOpenVPNAddressForUDP: nil,
pingAddress: nil
), Server(
serial: "8a55f03812851897f6e43b2ae22b1234",
name: "Germany",
country: "de",
hostname: "germany.example.com",
......@@ -50,6 +52,7 @@ public class MockServerProvider: ServerProvider, DatabaseAccess, WebServicesCons
bestOpenVPNAddressForUDP: nil,
pingAddress: nil
), Server(
serial: "8a55f03812851897f6e43b2ae22b1234",
name: "Italy",
country: "it",
hostname: "italy.example.com",
......@@ -57,6 +60,7 @@ public class MockServerProvider: ServerProvider, DatabaseAccess, WebServicesCons
bestOpenVPNAddressForUDP: nil,
pingAddress: nil
), Server(
serial: "8a55f03812851897f6e43b2ae22b1234",
name: "US East",
country: "us",
hostname: "us-east.example.com",
......
......@@ -111,7 +111,7 @@ public class MockVPNProvider: VPNProvider, ConfigurationAccess, DatabaseAccess {
}
/// :nodoc:
public func reconnect(after delay: Int?, _ callback: SuccessLibraryCallback?) {
public func reconnect(after delay: Int?, forceDisconnect: Bool = false, _ callback: SuccessLibraryCallback?) {
let disconnectionDelay: Int
// if (vpnStatus == .changingServer) {
// disconnectionDelay = 1000
......
......@@ -80,6 +80,8 @@ public class GetStartedViewController: AutolayoutViewController, ConfigurationAc
image: Asset.imageWalkthrough3.image
)
]
private var tutorialViews: [WalkthroughPageView] = []
private var currentPageIndex = 0
......@@ -299,6 +301,7 @@ public class GetStartedViewController: AutolayoutViewController, ConfigurationAc
for (i, data) in allData.enumerated() {
let page = WalkthroughPageView(data: data)
tutorialViews.append(page)
page.translatesAutoresizingMaskIntoConstraints = false
parent.addSubview(page)
......@@ -362,6 +365,9 @@ public class GetStartedViewController: AutolayoutViewController, ConfigurationAc
Theme.current.applyPageControl(pageControl)
Theme.current.applyLinkAttributes(textAgreement)
Theme.current.applyActivityIndicator(spinner)
tutorialViews.forEach({
$0.applyStyles()
})
imvLogo.image = Theme.current.palette.logo
}
......
......@@ -34,6 +34,9 @@ class WalkthroughPageView: UIView {
}
private let data: PageData
private(set) var labelTitle = UILabel()
private(set) var labelDetail = UILabel()
required init?(coder aDecoder: NSCoder) {
data = PageData(title: "", detail: "", image: nil)
......@@ -49,8 +52,7 @@ class WalkthroughPageView: UIView {
private func configure() {
let imvImage = UIImageView()
let labelTitle = UILabel()
let labelDetail = UILabel()
addSubview(imvImage)
addSubview(labelTitle)
addSubview(labelDetail)
......@@ -94,11 +96,14 @@ class WalkthroughPageView: UIView {
labelDetail.text = data.detail
imvImage.image = data.image
Theme.current.applySubtitle(labelDetail)
Theme.current.applyTitle(labelTitle, appearance: .dark)
labelTitle.textAlignment = .center
labelDetail.textAlignment = .center
}
func applyStyles() {
Theme.current.applySubtitle(labelDetail)
Theme.current.applyTitle(labelTitle, appearance: .dark)
}
}
//
// PIAWGTunnelProfile.swift
// PIALibrary
//
// Created by Jose Antonio Blaya Garcia on 06/02/2020.
// Copyright © 2020 Private Internet Access, Inc.
//
// This file is part of the Private Internet Access iOS Client.
//
// The Private Internet Access iOS Client is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any later version.
//
// The Private Internet Access iOS Client is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with the Private
// Internet Access iOS Client. If not, see <https://www.gnu.org/licenses/>.
//
import Foundation
import PIAWireguard
import NetworkExtension
/// Implementation of `VPNProfile` providing OpenVPN connectivity.
public class PIAWGTunnelProfile: NetworkExtensionProfile {
public func parsedCustomConfiguration(from map: [String : Any]) -> VPNCustomConfiguration? {
let S = PIAWireguardConfiguration.Keys.self
if let dnsServers = map[S.dnsServers] as? [String] {
return PIAWireguardConfiguration(customDNSServers: dnsServers)
}
return PIAWireguardConfiguration(customDNSServers: [])
}
public func requestLog(withCustomConfiguration customConfiguration: VPNCustomConfiguration?, _ callback: LibraryCallback<String>?) {
find { (vpn, error) in
guard let vpn = vpn else {
callback?(nil, error)
return
}
do {
let session = vpn.connection as? NETunnelProviderSession
if #available(iOSApplicationExtension 12.0, *) {
try session?.sendProviderMessage(WGPacketTunnelProvider.Message.requestLog.data) { (data) in
guard let data = data, !data.isEmpty else {
callback?(nil, nil)
return
}
let log = String(data: data, encoding: .utf8)
callback?(log, nil)
}
} else {
// Fallback on earlier versions
}
} catch let e {
callback?(nil, e)
}
}
}
public func requestDataUsage(withCustomConfiguration customConfiguration: VPNCustomConfiguration?, _ callback: LibraryCallback<Usage>?) {
find { (vpn, error) in
guard let vpn = vpn else {
callback?(nil, error)
return
}
do {
let session = vpn.connection as? NETunnelProviderSession
if #available(iOSApplicationExtension 12.0, *) {
try session?.sendProviderMessage(WGPacketTunnelProvider.Message.dataCount.data) { (data) in
guard let data = data, !data.isEmpty else {
callback?(nil, ClientError.vpnProfileUnavailable)
return
}
let downloaded = data.getInt64(start: 0)
let uploaded = data.getInt64(start: 8)
let usage = Usage(uploaded: uploaded, downloaded: downloaded)
callback?(usage,
nil)
}
} else {
// Fallback on earlier versions
}
} catch let e {
callback?(nil, e)
}
}
}
private let bundleIdentifier: String
/**
Default initializer.
- Parameter bundleIdentifier: The bundle identifier of a Packet Tunnel Provider extension subclassing `PIATunnelProvider` from `PIATunnel`.
*/
public init(bundleIdentifier: String) {
self.bundleIdentifier = bundleIdentifier
}
// MARK: VPNProfile
/// :nodoc:
public static var vpnType: String {
return "PIAWG"
}
/// :nodoc:
public static var isTunnel: Bool {
return true
}
/// :nodoc:
public var native: Any?
/// :nodoc:
public func prepare() {
find(completionHandler: nil)
}
/// :nodoc:
public func save(withConfiguration configuration: VPNConfiguration, force: Bool, _ callback: SuccessLibraryCallback?) {
find { (vpn, error) in
guard let vpn = vpn else {
callback?(error)
return
}
self.doSave(vpn, withConfiguration: configuration, force: force, callback)
}
}
/// :nodoc:
public func connect(withConfiguration configuration: VPNConfiguration, _ callback: SuccessLibraryCallback?) {
find { (vpn, error) in
guard let vpn = vpn else {
callback?(error)
return
}
self.doSave(vpn, withConfiguration: configuration, force: true) { (error) in
if let _ = error {
callback?(error)
return
}
do {
let session = vpn.connection as? NETunnelProviderSession
try session?.startTunnel(options: nil)
callback?(nil)
} catch let e {
callback?(e)
}
}
}
}
/// :nodoc:
public func disconnect(_ callback: SuccessLibraryCallback?) {
find { (vpn, error) in
guard let vpn = vpn else {
callback?(error)
return
}
// prevent reconnection
vpn.isOnDemandEnabled = false
vpn.saveToPreferences { (error) in
if let error = error {
vpn.connection.stopVPNTunnel()
callback?(error)
return
}
vpn.connection.stopVPNTunnel()
callback?(nil)
}
}
}
/// :nodoc:
public func updatePreferences(_ callback: SuccessLibraryCallback?) {
find { (vpn, error) in
guard let vpn = vpn else {
callback?(error)
return
}
vpn.saveToPreferences { (error) in
if let error = error {
callback?(error)
return
}
callback?(nil)
}
}
}
/// :nodoc:
public func disable(_ callback: SuccessLibraryCallback?) {
find { (vpn, error) in
guard let vpn = vpn else {
return
}
vpn.isEnabled = false
vpn.isOnDemandEnabled = false
vpn.saveToPreferences(completionHandler: callback)
}