Make framework internal components public

This commit is contained in:
Davide De Rosa 2019-03-18 11:29:28 +01:00
parent cf499739f7
commit f661008679
33 changed files with 351 additions and 349 deletions

View File

@ -27,27 +27,27 @@ import Foundation
import TunnelKit
import SwiftyBeaver
class AppConstants {
class Flags {
static let isBeta = false
public class AppConstants {
public class Flags {
public static let isBeta = false
}
class Domain {
static let name = "passepartoutvpn.app"
public class Domain {
public static let name = "passepartoutvpn.app"
}
class Store {
static let serviceFilename = "ConnectionService.json"
public class Store {
public static let serviceFilename = "ConnectionService.json"
static let webCacheDirectory = "Web"
public static let webCacheDirectory = "Web"
static let providersDirectory = "Providers"
public static let providersDirectory = "Providers"
static let hostsDirectory = "Hosts"
public static let hostsDirectory = "Hosts"
}
class VPN {
static func baseConfiguration() -> TunnelKitProvider.Configuration {
public class VPN {
public static func baseConfiguration() -> TunnelKitProvider.Configuration {
let sessionBuilder = SessionProxy.ConfigurationBuilder(ca: CryptoContainer(pem: ""))
var builder = TunnelKitProvider.ConfigurationBuilder(sessionConfiguration: sessionBuilder.build())
builder.mtu = 1250
@ -66,37 +66,37 @@ class AppConstants {
"https://www.instagram.com"
]
static let connectivityURL = URL(string: connectivityStrings.customRandomElement())!
public static let connectivityURL = URL(string: connectivityStrings.customRandomElement())!
static let connectivityTimeout: TimeInterval = 10.0
public static let connectivityTimeout: TimeInterval = 10.0
}
class Web {
public class Web {
private static let version = "v1"
private static let baseURL = Repos.api.appendingPathComponent(version)
static func url(path: String) -> URL {
public static func url(path: String) -> URL {
return baseURL.appendingPathComponent(path)
}
static let timeout: TimeInterval = 3.0
public static let timeout: TimeInterval = 3.0
static let minimumUpdateInterval: TimeInterval = 600.0 // 10 minutes
public static let minimumUpdateInterval: TimeInterval = 600.0 // 10 minutes
}
class Log {
static let level: SwiftyBeaver.Level = .debug
public class Log {
public static let level: SwiftyBeaver.Level = .debug
static let debugFormat = "$DHH:mm:ss$d - $M"
public static let debugFormat = "$DHH:mm:ss$d - $M"
static var debugSnapshot: () -> String = { TransientStore.shared.service.vpnLog }
public static var debugSnapshot: () -> String = { TransientStore.shared.service.vpnLog }
static let viewerRefreshInterval: TimeInterval = 3.0
public static let viewerRefreshInterval: TimeInterval = 3.0
private static let fileName = "Debug.log"
static var fileURL: URL {
public static var fileURL: URL {
return GroupConstants.App.cachesURL.appendingPathComponent(fileName)
}
@ -115,51 +115,51 @@ class AppConstants {
return dest
}()
static func configure() {
public static func configure() {
SwiftyBeaver.addDestination(console)
SwiftyBeaver.addDestination(file)
}
}
class IssueReporter {
static let recipient = "issues@\(Domain.name)"
public class IssueReporter {
public static let recipient = "issues@\(Domain.name)"
class Filenames {
static var debugLog: String {
public class Filenames {
public static var debugLog: String {
let fmt = DateFormatter()
fmt.dateFormat = "yyyyMMdd-HHmmss"
let iso = fmt.string(from: Date())
return "debug-\(iso).txt"
}
static let configuration = "profile.ovpn"
// static let configuration = "profile.ovpn.txt"
public static let configuration = "profile.ovpn"
// public static let configuration = "profile.ovpn.txt"
}
class MIME {
static let debugLog = "text/plain"
public class MIME {
public static let debugLog = "text/plain"
// static let configuration = "application/x-openvpn-profile"
static let configuration = "text/plain"
// public static let configuration = "application/x-openvpn-profile"
public static let configuration = "text/plain"
}
}
class URLs {
static let website = URL(string: "https://\(Domain.name)")!
public class URLs {
public static let website = URL(string: "https://\(Domain.name)")!
static let faq = website.appendingPathComponent("faq")
public static let faq = website.appendingPathComponent("faq")
static let disclaimer = website.appendingPathComponent("disclaimer")
public static let disclaimer = website.appendingPathComponent("disclaimer")
static let privacyPolicy = website.appendingPathComponent("privacy")
public static let privacyPolicy = website.appendingPathComponent("privacy")
static let changelog = Repos.ios.appendingPathComponent("blob/master/CHANGELOG.md")
public static let changelog = Repos.ios.appendingPathComponent("blob/master/CHANGELOG.md")
static let subreddit = URL(string: "https://www.reddit.com/r/passepartout")!
public static let subreddit = URL(string: "https://www.reddit.com/r/passepartout")!
private static let twitterHashtags = ["OpenVPN", "iOS", "macOS"]
static var twitterIntent: URL {
public static var twitterIntent: URL {
var text = L10n.Share.message
for ht in twitterHashtags {
text = text.replacingOccurrences(of: ht, with: "#\(ht)")
@ -173,17 +173,17 @@ class AppConstants {
return comps.url!
}
static func review(withId id: String) -> URL {
public static func review(withId id: String) -> URL {
return URL(string: "https://itunes.apple.com/app/id\(id)?action=write-review")!
}
static let referrals: [Infrastructure.Name: String] = [
public static let referrals: [Infrastructure.Name: String] = [
.pia: "https://www.privateinternetaccess.com/pages/buy-vpn/",
.tunnelBear: "https://click.tunnelbear.com/aff_c?offer_id=2&aff_id=7464"
]
}
class Repos {
public class Repos {
private static let githubRoot = URL(string: "https://github.com/passepartoutvpn/")!
private static let githubRawRoot = URL(string: "https://\(Domain.name)/")!
@ -196,25 +196,25 @@ class AppConstants {
return githubRawRoot.appendingPathComponent(repo)
}
static let ios = github(repo: "passepartout-ios")
public static let ios = github(repo: "passepartout-ios")
static let api = githubRaw(repo: "api")
public static let api = githubRaw(repo: "api")
}
struct License {
let name: String
public struct License {
public let name: String
let type: String
public let type: String
let url: URL
public let url: URL
init(_ name: String, _ type: String, _ urlString: String) {
public init(_ name: String, _ type: String, _ urlString: String) {
self.name = name
self.type = type
url = URL(string: urlString)!
}
static let all: [License] = [
public static let all: [License] = [
License(
"MBProgressHUD",
"MIT",
@ -242,20 +242,20 @@ class AppConstants {
)
]
static var cachedContent: [String: String] = [:]
public static var cachedContent: [String: String] = [:]
}
struct Notice {
let name: String
public struct Notice {
public let name: String
let statement: String
public let statement: String
init(_ name: String, _ statement: String) {
public init(_ name: String, _ statement: String) {
self.name = name
self.statement = statement
}
static let all: [Notice] = [
public static let all: [Notice] = [
Notice(
"Circle Icons",
"The logo is taken from the awesome Circle Icons set by Nick Roach."
@ -267,7 +267,7 @@ class AppConstants {
]
}
struct Rating {
static let eventCount = 3
public struct Rating {
public static let eventCount = 3
}
}

View File

@ -25,7 +25,7 @@
import Foundation
enum ApplicationError: String, Error {
public enum ApplicationError: String, Error {
case missingProfile
case missingCredentials

View File

@ -25,33 +25,33 @@
import Foundation
class GroupConstants {
class App {
static let name = "Passepartout"
public class GroupConstants {
public class App {
public static let name = "Passepartout"
static let tunnelKitName = "TunnelKit"
public static let tunnelKitName = "TunnelKit"
static let title = name
// static let title = "\u{1F511}"
public static let title = name
// public static let title = "\u{1F511}"
static let versionNumber = Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String
public static let versionNumber = Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String
static let buildNumber = Int(Bundle.main.infoDictionary![kCFBundleVersionKey as String] as! String)!
public static let buildNumber = Int(Bundle.main.infoDictionary![kCFBundleVersionKey as String] as! String)!
static let versionString = "\(versionNumber) (\(buildNumber))"
public static let versionString = "\(versionNumber) (\(buildNumber))"
static let teamId = "DTDYD63ZX9"
public static let teamId = "DTDYD63ZX9"
static let appId = "1433648537"
public static let appId = "1433648537"
#if os(iOS)
static let appGroup = "group.com.algoritmico.Passepartout"
public static let appGroup = "group.com.algoritmico.Passepartout"
static let tunnelIdentifier = "com.algoritmico.ios.Passepartout.Tunnel"
public static let tunnelIdentifier = "com.algoritmico.ios.Passepartout.Tunnel"
#else
static let appGroup = "\(teamId).group.com.algoritmico.Passepartout"
public static let appGroup = "\(teamId).group.com.algoritmico.Passepartout"
static let tunnelIdentifier = "com.algoritmico.macos.Passepartout.Tunnel"
public static let tunnelIdentifier = "com.algoritmico.macos.Passepartout.Tunnel"
#endif
private static var containerURL: URL {
@ -62,22 +62,22 @@ class GroupConstants {
return url
}
static let documentsURL: URL = {
public static let documentsURL: URL = {
let url = containerURL.appendingPathComponent("Documents", isDirectory: true)
try? FileManager.default.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil)
return url
}()
static let cachesURL: URL = {
public static let cachesURL: URL = {
let url = containerURL.appendingPathComponent("Library/Caches", isDirectory: true)
try? FileManager.default.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil)
return url
}()
}
class VPN {
static let dnsTimeout = 5000
public class VPN {
public static let dnsTimeout = 5000
static let sessionMarker = "--- EOF ---"
public static let sessionMarker = "--- EOF ---"
}
}

View File

@ -27,13 +27,13 @@ import Foundation
import TunnelKit
import NetworkExtension
enum Context: String, Codable {
public enum Context: String, Codable {
case provider
case host
}
protocol ConnectionProfile: class, EndpointDataSource, CustomStringConvertible {
public protocol ConnectionProfile: class, EndpointDataSource, CustomStringConvertible {
var context: Context { get }
var id: String { get }
@ -47,7 +47,7 @@ protocol ConnectionProfile: class, EndpointDataSource, CustomStringConvertible {
func with(newId: String) -> ConnectionProfile
}
extension ConnectionProfile {
public extension ConnectionProfile {
var passwordKey: String? {
guard let username = username else {
return nil
@ -81,7 +81,7 @@ extension ConnectionProfile {
}
}
extension ConnectionProfile {
public extension ConnectionProfile {
var description: String {
return "(\(context):\(id))"
}

View File

@ -28,7 +28,7 @@ import SwiftyBeaver
private let log = SwiftyBeaver.self
extension ConnectionService {
public extension ConnectionService {
func save(configurationURL: URL, for key: ProfileKey) throws -> URL {
let destinationURL = targetConfigurationURL(for: key)
let fm = FileManager.default

View File

@ -28,7 +28,7 @@ import SwiftyBeaver
private let log = SwiftyBeaver.self
extension ConnectionService {
public extension ConnectionService {
static func migrateJSON(from: URL, to: URL) {
do {
let newData = try migrateJSON(at: from)

View File

@ -30,7 +30,7 @@ import SwiftyBeaver
private let log = SwiftyBeaver.self
protocol ConnectionServiceDelegate: class {
public protocol ConnectionServiceDelegate: class {
func connectionService(didAdd profile: ConnectionProfile)
func connectionService(didRename oldProfile: ConnectionProfile, to newProfile: ConnectionProfile)
@ -42,8 +42,8 @@ protocol ConnectionServiceDelegate: class {
func connectionService(didActivate profile: ConnectionProfile)
}
class ConnectionService: Codable {
enum CodingKeys: String, CodingKey {
public class ConnectionService: Codable {
public enum CodingKeys: String, CodingKey {
case build
case appGroup
@ -55,9 +55,9 @@ class ConnectionService: Codable {
case preferences
}
var directory: String? = nil
public var directory: String? = nil
var rootURL: URL {
public var rootURL: URL {
var url = GroupConstants.App.documentsURL
if let directory = directory {
url.appendPathComponent(directory)
@ -81,11 +81,11 @@ class ConnectionService: Codable {
private let keychain: Keychain
var baseConfiguration: TunnelKitProvider.Configuration
public var baseConfiguration: TunnelKitProvider.Configuration
private var cache: [ProfileKey: ConnectionProfile]
private(set) var activeProfileKey: ProfileKey? {
public private(set) var activeProfileKey: ProfileKey? {
willSet {
if let oldProfile = activeProfile {
delegate?.connectionService(willDeactivate: oldProfile)
@ -98,7 +98,7 @@ class ConnectionService: Codable {
}
}
var activeProfile: ConnectionProfile? {
public var activeProfile: ConnectionProfile? {
guard let id = activeProfileKey else {
return nil
}
@ -110,11 +110,11 @@ class ConnectionService: Codable {
return hit
}
let preferences: EditablePreferences
public let preferences: EditablePreferences
weak var delegate: ConnectionServiceDelegate?
public weak var delegate: ConnectionServiceDelegate?
init(withAppGroup appGroup: String, baseConfiguration: TunnelKitProvider.Configuration) {
public init(withAppGroup appGroup: String, baseConfiguration: TunnelKitProvider.Configuration) {
guard let defaults = UserDefaults(suiteName: appGroup) else {
fatalError("No entitlements for group '\(appGroup)'")
}
@ -132,7 +132,7 @@ class ConnectionService: Codable {
// MARK: Codable
required init(from decoder: Decoder) throws {
public required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let appGroup = try container.decode(String.self, forKey: .appGroup)
guard let defaults = UserDefaults(suiteName: appGroup) else {
@ -150,7 +150,7 @@ class ConnectionService: Codable {
cache = [:]
}
func encode(to encoder: Encoder) throws {
public func encode(to encoder: Encoder) throws {
build = GroupConstants.App.buildNumber
var container = encoder.container(keyedBy: CodingKeys.self)
@ -163,7 +163,7 @@ class ConnectionService: Codable {
// MARK: Serialization
func loadProfiles() {
public func loadProfiles() {
let fm = FileManager.default
try? fm.createDirectory(at: providersURL, withIntermediateDirectories: false, attributes: nil)
try? fm.createDirectory(at: hostsURL, withIntermediateDirectories: false, attributes: nil)
@ -196,7 +196,7 @@ class ConnectionService: Codable {
}
}
func saveProfiles() {
public func saveProfiles() {
let encoder = JSONEncoder()
ensureDirectoriesExistence()
@ -237,7 +237,7 @@ class ConnectionService: Codable {
}
}
func profile(withContext context: Context, id: String) -> ConnectionProfile? {
public func profile(withContext context: Context, id: String) -> ConnectionProfile? {
let key = ProfileKey(context, id)
var profile = cache[key]
if let _ = profile as? PlaceholderConnectionProfile {
@ -260,11 +260,11 @@ class ConnectionService: Codable {
return profile
}
func ids(forContext context: Context) -> [String] {
public func ids(forContext context: Context) -> [String] {
return cache.keys.filter { $0.context == context }.map { $0.id }
}
func contextURL(_ key: ProfileKey) -> URL {
public func contextURL(_ key: ProfileKey) -> URL {
switch key.context {
case .provider:
return providersURL
@ -274,11 +274,11 @@ class ConnectionService: Codable {
}
}
func profileURL(_ key: ProfileKey) -> URL {
public func profileURL(_ key: ProfileKey) -> URL {
return contextURL(key).appendingPathComponent(key.id).appendingPathExtension("json")
}
func profileData(_ key: ProfileKey) throws -> Data {
public func profileData(_ key: ProfileKey) throws -> Data {
return try Data(contentsOf: profileURL(key))
}
@ -291,7 +291,7 @@ class ConnectionService: Codable {
// MARK: Profiles
func addProfile(_ profile: ConnectionProfile, credentials: Credentials?) -> Bool {
public func addProfile(_ profile: ConnectionProfile, credentials: Credentials?) -> Bool {
guard cache.index(forKey: ProfileKey(profile)) == nil else {
return false
}
@ -299,7 +299,7 @@ class ConnectionService: Codable {
return true
}
func addOrReplaceProfile(_ profile: ConnectionProfile, credentials: Credentials?) {
public func addOrReplaceProfile(_ profile: ConnectionProfile, credentials: Credentials?) {
let key = ProfileKey(profile)
cache[key] = profile
try? setCredentials(credentials, for: profile)
@ -312,7 +312,8 @@ class ConnectionService: Codable {
saveProfile(profile, withEncoder: JSONEncoder(), checkDirectories: true)
}
@discardableResult func renameProfile(_ key: ProfileKey, to newId: String) -> ConnectionProfile? {
@discardableResult
public func renameProfile(_ key: ProfileKey, to newId: String) -> ConnectionProfile? {
precondition(newId != key.id)
// WARNING: can be a placeholder
@ -351,11 +352,12 @@ class ConnectionService: Codable {
return newProfile
}
@discardableResult func renameProfile(_ profile: ConnectionProfile, to id: String) -> ConnectionProfile? {
@discardableResult
public func renameProfile(_ profile: ConnectionProfile, to id: String) -> ConnectionProfile? {
return renameProfile(ProfileKey(profile), to: id)
}
func removeProfile(_ key: ProfileKey) {
public func removeProfile(_ key: ProfileKey) {
guard let profile = cache[key] else {
return
}
@ -382,33 +384,33 @@ class ConnectionService: Codable {
}
}
func containsProfile(_ key: ProfileKey) -> Bool {
public func containsProfile(_ key: ProfileKey) -> Bool {
return cache.index(forKey: key) != nil
}
func containsProfile(_ profile: ConnectionProfile) -> Bool {
public func containsProfile(_ profile: ConnectionProfile) -> Bool {
return containsProfile(ProfileKey(profile))
}
func hasActiveProfile() -> Bool {
public func hasActiveProfile() -> Bool {
return activeProfileKey != nil
}
func isActiveProfile(_ key: ProfileKey) -> Bool {
public func isActiveProfile(_ key: ProfileKey) -> Bool {
return key == activeProfileKey
}
func isActiveProfile(_ profile: ConnectionProfile) -> Bool {
public func isActiveProfile(_ profile: ConnectionProfile) -> Bool {
return isActiveProfile(ProfileKey(profile))
}
func activateProfile(_ profile: ConnectionProfile) {
public func activateProfile(_ profile: ConnectionProfile) {
activeProfileKey = ProfileKey(profile)
}
// MARK: Credentials
func needsCredentials(for profile: ConnectionProfile) -> Bool {
public func needsCredentials(for profile: ConnectionProfile) -> Bool {
guard profile.requiresCredentials else {
return false
}
@ -418,7 +420,7 @@ class ConnectionService: Codable {
return creds.isEmpty
}
func credentials(for profile: ConnectionProfile) -> Credentials? {
public func credentials(for profile: ConnectionProfile) -> Credentials? {
guard let username = profile.username, let key = profile.passwordKey else {
return nil
}
@ -428,18 +430,18 @@ class ConnectionService: Codable {
return Credentials(username, password)
}
func setCredentials(_ credentials: Credentials?, for profile: ConnectionProfile) throws {
public func setCredentials(_ credentials: Credentials?, for profile: ConnectionProfile) throws {
profile.username = credentials?.username
try profile.setPassword(credentials?.password, in: keychain)
}
func removeCredentials(for profile: ConnectionProfile) {
public func removeCredentials(for profile: ConnectionProfile) {
profile.removePassword(in: keychain)
}
// MARK: VPN
func vpnConfiguration() throws -> NetworkExtensionVPNConfiguration {
public func vpnConfiguration() throws -> NetworkExtensionVPNConfiguration {
guard let profile = activeProfile else {
throw ApplicationError.missingProfile
}
@ -492,19 +494,19 @@ class ConnectionService: Codable {
}
}
var vpnLog: String {
public var vpnLog: String {
return baseConfiguration.existingLog(in: appGroup) ?? ""
}
var vpnLastError: TunnelKitProvider.ProviderError? {
public var vpnLastError: TunnelKitProvider.ProviderError? {
return baseConfiguration.lastError(in: appGroup)
}
func clearVpnLastError() {
public func clearVpnLastError() {
baseConfiguration.clearLastError(in: appGroup)
}
// func eraseVpnLog() {
// public func eraseVpnLog() {
// defaults.removeObject(forKey: Keys.vpnLog)
// }
}

View File

@ -26,9 +26,9 @@
import Foundation
import TunnelKit
typealias Credentials = SessionProxy.Credentials
public typealias Credentials = SessionProxy.Credentials
extension Credentials {
public extension Credentials {
var isEmpty: Bool {
return username.isEmpty || password.isEmpty
}

View File

@ -30,22 +30,22 @@ import UIKit
import Cocoa
#endif
struct DebugLog {
public struct DebugLog {
private let raw: String
init(raw: String) {
public init(raw: String) {
self.raw = raw
}
func string() -> String {
public func string() -> String {
return raw
}
func data() -> Data? {
public func data() -> Data? {
return raw.data(using: .utf8)
}
func decoratedString() -> String {
public func decoratedString() -> String {
let appName = GroupConstants.App.name
let appVersion = GroupConstants.App.versionString
@ -75,7 +75,7 @@ struct DebugLog {
return fullText
}
func decoratedData() -> Data {
public func decoratedData() -> Data {
guard let data = decoratedString().data(using: .utf8) else {
fatalError("Could not encode log metadata to UTF8?")
}

View File

@ -26,7 +26,7 @@
import Foundation
import TunnelKit
protocol EndpointDataSource {
public protocol EndpointDataSource {
var mainAddress: String { get }
var addresses: [String] { get }

View File

@ -25,7 +25,7 @@
import Foundation
protocol Preferences {
public protocol Preferences {
var resolvesHostname: Bool { get }
var disconnectsOnSleep: Bool { get }
@ -39,16 +39,16 @@ protocol Preferences {
var trustPolicy: TrustPolicy { get }
}
class EditablePreferences: Preferences, Codable {
var resolvesHostname: Bool = true
public class EditablePreferences: Preferences, Codable {
public var resolvesHostname: Bool = true
var disconnectsOnSleep: Bool = false
public var disconnectsOnSleep: Bool = false
#if os(iOS)
var trustsMobileNetwork: Bool = false
public var trustsMobileNetwork: Bool = false
#endif
var trustedWifis: [String: Bool] = [:]
public var trustedWifis: [String: Bool] = [:]
var trustPolicy: TrustPolicy = .disconnect
public var trustPolicy: TrustPolicy = .disconnect
}

View File

@ -26,14 +26,14 @@
import Foundation
import TunnelKit
class HostConnectionProfile: ConnectionProfile, Codable, Equatable {
var title: String
public class HostConnectionProfile: ConnectionProfile, Codable, Equatable {
public var title: String
let hostname: String
public let hostname: String
var parameters: TunnelKitProvider.Configuration
public var parameters: TunnelKitProvider.Configuration
init(title: String, hostname: String) {
public init(title: String, hostname: String) {
self.title = title
self.hostname = hostname
let sessionConfiguration = SessionProxy.ConfigurationBuilder(ca: CryptoContainer(pem: "")).build()
@ -42,19 +42,19 @@ class HostConnectionProfile: ConnectionProfile, Codable, Equatable {
// MARK: ConnectionProfile
let context: Context = .host
public let context: Context = .host
var id: String {
public var id: String {
return title
}
var username: String?
public var username: String?
var requiresCredentials: Bool {
public var requiresCredentials: Bool {
return false
}
func generate(from configuration: TunnelKitProvider.Configuration, preferences: Preferences) throws -> TunnelKitProvider.Configuration {
public func generate(from configuration: TunnelKitProvider.Configuration, preferences: Preferences) throws -> TunnelKitProvider.Configuration {
precondition(!parameters.endpointProtocols.isEmpty)
// XXX: copy paste, error prone
@ -66,7 +66,7 @@ class HostConnectionProfile: ConnectionProfile, Codable, Equatable {
return builder.build()
}
func with(newId: String) -> ConnectionProfile {
public func with(newId: String) -> ConnectionProfile {
let profile = HostConnectionProfile(title: newId, hostname: hostname)
profile.username = username
profile.parameters = parameters
@ -74,13 +74,13 @@ class HostConnectionProfile: ConnectionProfile, Codable, Equatable {
}
}
extension HostConnectionProfile {
public extension HostConnectionProfile {
static func ==(lhs: HostConnectionProfile, rhs: HostConnectionProfile) -> Bool {
return lhs.id == rhs.id
}
}
extension HostConnectionProfile {
public extension HostConnectionProfile {
var mainAddress: String {
return hostname
}

View File

@ -26,41 +26,41 @@
import Foundation
import TunnelKit
class PlaceholderConnectionProfile: ConnectionProfile {
let context: Context
public class PlaceholderConnectionProfile: ConnectionProfile {
public let context: Context
let id: String
public let id: String
var username: String? = nil
public var username: String? = nil
var requiresCredentials: Bool = false
public var requiresCredentials: Bool = false
func generate(from configuration: TunnelKitProvider.Configuration, preferences: Preferences) throws -> TunnelKitProvider.Configuration {
public func generate(from configuration: TunnelKitProvider.Configuration, preferences: Preferences) throws -> TunnelKitProvider.Configuration {
fatalError("Generating configuration from a PlaceholderConnectionProfile")
}
func with(newId: String) -> ConnectionProfile {
public func with(newId: String) -> ConnectionProfile {
return PlaceholderConnectionProfile(context, newId)
}
var mainAddress: String = ""
public var mainAddress: String = ""
var addresses: [String] = []
public var addresses: [String] = []
var protocols: [EndpointProtocol] = []
public var protocols: [EndpointProtocol] = []
var canCustomizeEndpoint: Bool = false
public var canCustomizeEndpoint: Bool = false
var customAddress: String?
public var customAddress: String?
var customProtocol: EndpointProtocol?
public var customProtocol: EndpointProtocol?
init(_ context: Context, _ id: String) {
public init(_ context: Context, _ id: String) {
self.context = context
self.id = id
}
init(_ key: ProfileKey) {
public init(_ key: ProfileKey) {
context = key.context
id = key.id
}

View File

@ -25,30 +25,30 @@
import Foundation
struct ProfileKey: RawRepresentable, Hashable, Codable, CustomStringConvertible {
public struct ProfileKey: RawRepresentable, Hashable, Codable, CustomStringConvertible {
private static let separator: Character = "."
let context: Context
public let context: Context
let id: String
public let id: String
init(_ context: Context, _ id: String) {
public init(_ context: Context, _ id: String) {
self.context = context
self.id = id
}
init(_ profile: ConnectionProfile) {
public init(_ profile: ConnectionProfile) {
context = profile.context
id = profile.id
}
// MARK: RawRepresentable
var rawValue: String {
public var rawValue: String {
return "\(context)\(ProfileKey.separator)\(id)"
}
init?(rawValue: String) {
public init?(rawValue: String) {
guard let separatorIndex = rawValue.firstIndex(of: ProfileKey.separator) else {
return nil
}
@ -66,7 +66,7 @@ struct ProfileKey: RawRepresentable, Hashable, Codable, CustomStringConvertible
// MARK: CustomStringConvertible
var description: String {
public var description: String {
return "{context=\(context), id=\(id)}"
}
}

View File

@ -26,42 +26,42 @@
import Foundation
import TunnelKit
class ProviderConnectionProfile: ConnectionProfile, Codable, Equatable {
let name: Infrastructure.Name
public class ProviderConnectionProfile: ConnectionProfile, Codable, Equatable {
public let name: Infrastructure.Name
var infrastructure: Infrastructure {
public var infrastructure: Infrastructure {
return InfrastructureFactory.shared.get(name)
}
var poolId: String {
public var poolId: String {
didSet {
validateEndpoint()
}
}
var pool: Pool? {
public var pool: Pool? {
return infrastructure.pool(for: poolId) ?? infrastructure.pool(for: infrastructure.defaults.pool)
}
var presetId: String {
public var presetId: String {
didSet {
validateEndpoint()
}
}
var preset: InfrastructurePreset? {
public var preset: InfrastructurePreset? {
return infrastructure.preset(for: presetId)
}
var manualAddress: String?
public var manualAddress: String?
var manualProtocol: EndpointProtocol?
public var manualProtocol: EndpointProtocol?
var usesProviderEndpoint: Bool {
public var usesProviderEndpoint: Bool {
return (manualAddress != nil) || (manualProtocol != nil)
}
init(name: Infrastructure.Name) {
public init(name: Infrastructure.Name) {
self.name = name
poolId = ""
presetId = ""
@ -72,7 +72,7 @@ class ProviderConnectionProfile: ConnectionProfile, Codable, Equatable {
presetId = infrastructure.defaults.preset
}
func sortedPools() -> [Pool] {
public func sortedPools() -> [Pool] {
return infrastructure.pools.sorted()
}
@ -92,19 +92,19 @@ class ProviderConnectionProfile: ConnectionProfile, Codable, Equatable {
// MARK: ConnectionProfile
let context: Context = .provider
public let context: Context = .provider
var id: String {
public var id: String {
return name.rawValue
}
var username: String?
public var username: String?
var requiresCredentials: Bool {
public var requiresCredentials: Bool {
return true
}
func generate(from configuration: TunnelKitProvider.Configuration, preferences: Preferences) throws -> TunnelKitProvider.Configuration {
public func generate(from configuration: TunnelKitProvider.Configuration, preferences: Preferences) throws -> TunnelKitProvider.Configuration {
guard let pool = pool else {
preconditionFailure("Nil pool?")
}
@ -140,18 +140,18 @@ class ProviderConnectionProfile: ConnectionProfile, Codable, Equatable {
return builder.build()
}
func with(newId: String) -> ConnectionProfile {
public func with(newId: String) -> ConnectionProfile {
fatalError("Cannot rename a ProviderConnectionProfile")
}
}
extension ProviderConnectionProfile {
public extension ProviderConnectionProfile {
static func ==(lhs: ProviderConnectionProfile, rhs: ProviderConnectionProfile) -> Bool {
return lhs.id == rhs.id
}
}
extension ProviderConnectionProfile {
public extension ProviderConnectionProfile {
var mainAddress: String {
assert(pool != nil, "Getting provider main address but no pool set")
return pool?.hostname ?? ""

View File

@ -26,7 +26,7 @@
import Foundation
import TunnelKit
extension SessionProxy.ConfigurationBuilder {
public extension SessionProxy.ConfigurationBuilder {
// mutating func copyCommunication(from other: SessionProxy.ConfigurationBuilder) {
// cipher = other.cipher
// digest = other.digest

View File

@ -28,20 +28,20 @@ import SwiftyBeaver
private let log = SwiftyBeaver.self
class TransientStore {
public class TransientStore {
private struct Keys {
static let didHandleSubreddit = "DidHandleSubreddit"
}
static let shared = TransientStore()
public static let shared = TransientStore()
private static var serviceURL: URL {
return GroupConstants.App.documentsURL.appendingPathComponent(AppConstants.Store.serviceFilename)
}
let service: ConnectionService
public let service: ConnectionService
var didHandleSubreddit: Bool {
public var didHandleSubreddit: Bool {
get {
return UserDefaults.standard.bool(forKey: Keys.didHandleSubreddit)
}
@ -80,7 +80,7 @@ class TransientStore {
}
}
func serialize(withProfiles: Bool) {
public func serialize(withProfiles: Bool) {
try? JSONEncoder().encode(service).write(to: TransientStore.serviceURL)
if withProfiles {
service.saveProfiles()

View File

@ -25,7 +25,7 @@
import Foundation
enum TrustPolicy: String, Codable {
public enum TrustPolicy: String, Codable {
case ignore
case disconnect

View File

@ -25,7 +25,7 @@
import Foundation
protocol TrustedNetworksModelDelegate: class {
public protocol TrustedNetworksModelDelegate: class {
func trustedNetworksCouldDisconnect(_: TrustedNetworksModel) -> Bool
func trustedNetworksShouldConfirmDisconnection(_: TrustedNetworksModel, triggeredAt rowIndex: Int, completionHandler: @escaping () -> Void)
@ -39,24 +39,24 @@ protocol TrustedNetworksModelDelegate: class {
func trustedNetworksShouldReinstall(_: TrustedNetworksModel)
}
class TrustedNetworksModel {
private(set) var trustedWifis: [String: Bool]
public class TrustedNetworksModel {
public private(set) var trustedWifis: [String: Bool]
private(set) var sortedWifis: [String]
public private(set) var sortedWifis: [String]
#if os(iOS)
private let hasMobileNetwork: Bool
private(set) var trustsMobileNetwork: Bool
public private(set) var trustsMobileNetwork: Bool
// FIXME
// private(set) var rows: [ServiceViewController.RowType]
private(set) var rows: [Int]
// public private(set) var rows: [ServiceViewController.RowType]
public private(set) var rows: [Int]
#endif
weak var delegate: TrustedNetworksModelDelegate?
public weak var delegate: TrustedNetworksModelDelegate?
init() {
public init() {
trustedWifis = [:]
sortedWifis = []
@ -67,7 +67,7 @@ class TrustedNetworksModel {
#endif
}
func load(from preferences: Preferences) {
public func load(from preferences: Preferences) {
trustedWifis = preferences.trustedWifis
sortedWifis = trustedWifis.keys.sorted()
@ -86,7 +86,7 @@ class TrustedNetworksModel {
}
#if os(iOS)
func setMobile(_ isTrusted: Bool) {
public func setMobile(_ isTrusted: Bool) {
let completionHandler: () -> Void = {
self.trustsMobileNetwork = isTrusted
self.delegate?.trustedNetworksShouldReinstall(self)
@ -99,14 +99,14 @@ class TrustedNetworksModel {
}
#endif
func wifi(at rowIndex: Int) -> (String, Bool) {
public func wifi(at rowIndex: Int) -> (String, Bool) {
let index = indexForWifi(at: rowIndex)
let wifiName = sortedWifis[index]
let isTrusted = trustedWifis[wifiName] ?? false
return (wifiName, isTrusted)
}
func addCurrentWifi() -> Bool {
public func addCurrentWifi() -> Bool {
guard let currentWifi = Utils.currentWifiNetworkName() else {
return false
}
@ -114,7 +114,7 @@ class TrustedNetworksModel {
return true
}
func addWifi(_ wifiToAdd: String) {
public func addWifi(_ wifiToAdd: String) {
var index = 0
var isDuplicate = false
for wifi in sortedWifis {
@ -150,7 +150,7 @@ class TrustedNetworksModel {
delegate?.trustedNetworksShouldReinstall(self)
}
func removeWifi(at rowIndex: Int) {
public func removeWifi(at rowIndex: Int) {
let index = indexForWifi(at: rowIndex)
let removedWifi = sortedWifis.remove(at: index)
trustedWifis.removeValue(forKey: removedWifi)
@ -162,7 +162,7 @@ class TrustedNetworksModel {
delegate?.trustedNetworksShouldReinstall(self)
}
func enableWifi(at rowIndex: Int) {
public func enableWifi(at rowIndex: Int) {
let index = indexForWifi(at: rowIndex)
let wifi = sortedWifis[index]
@ -179,7 +179,7 @@ class TrustedNetworksModel {
completionHandler()
}
func disableWifi(at rowIndex: Int) {
public func disableWifi(at rowIndex: Int) {
let index = indexForWifi(at: rowIndex)
let wifi = sortedWifis[index]
@ -189,7 +189,7 @@ class TrustedNetworksModel {
delegate?.trustedNetworksShouldReinstall(self)
}
func isTrusted(wifi: String) -> Bool {
public func isTrusted(wifi: String) -> Bool {
return trustedWifis[wifi] ?? false
}

View File

@ -28,24 +28,24 @@ import SwiftyBeaver
private let log = SwiftyBeaver.self
class Reviewer {
public class Reviewer {
private struct Keys {
static let eventCount = "ReviewerEventCount"
static let lastVersion = "ReviewerLastVersion"
}
static let shared = Reviewer()
public static let shared = Reviewer()
private let defaults: UserDefaults
var eventCountBeforeRating = 3
public var eventCountBeforeRating = 3
private init() {
defaults = .standard
}
func reportEvent() {
public func reportEvent() {
let currentVersion = GroupConstants.App.buildNumber
let lastVersion = defaults.integer(forKey: Keys.lastVersion)
if lastVersion > 0 {

View File

@ -26,49 +26,49 @@
import Foundation
import TunnelKit
struct Infrastructure: Codable {
enum Name: String, Codable, Comparable {
public struct Infrastructure: Codable {
public enum Name: String, Codable, Comparable {
case pia = "PIA"
case tunnelBear = "TunnelBear"
var webName: String {
public var webName: String {
return rawValue.lowercased()
}
static func <(lhs: Name, rhs: Name) -> Bool {
public static func <(lhs: Name, rhs: Name) -> Bool {
return lhs.webName < rhs.webName
}
}
struct Defaults: Codable {
let username: String?
public struct Defaults: Codable {
public let username: String?
let pool: String
public let pool: String
let preset: String
public let preset: String
}
let build: Int
public let build: Int
let name: Name
public let name: Name
let pools: [Pool]
public let pools: [Pool]
let presets: [InfrastructurePreset]
public let presets: [InfrastructurePreset]
let defaults: Defaults
public let defaults: Defaults
static func loaded(from url: URL) throws -> Infrastructure {
public static func loaded(from url: URL) throws -> Infrastructure {
let json = try Data(contentsOf: url)
return try JSONDecoder().decode(Infrastructure.self, from: json)
}
func pool(for identifier: String) -> Pool? {
public func pool(for identifier: String) -> Pool? {
return pools.first { $0.id == identifier }
}
func preset(for identifier: String) -> InfrastructurePreset? {
public func preset(for identifier: String) -> InfrastructurePreset? {
return presets.first { $0.id == identifier }
}
}

View File

@ -28,7 +28,7 @@ import SwiftyBeaver
private let log = SwiftyBeaver.self
class InfrastructureFactory {
public class InfrastructureFactory {
private static func embedded(withName name: Infrastructure.Name) -> Infrastructure {
guard let url = name.bundleURL else {
fatalError("Cannot find JSON for infrastructure '\(name)'")
@ -53,9 +53,9 @@ class InfrastructureFactory {
return cacheDate > bundleDate
}
static let shared = InfrastructureFactory()
public static let shared = InfrastructureFactory()
let allNames: [Infrastructure.Name] = [
public let allNames: [Infrastructure.Name] = [
.pia,
.tunnelBear
]
@ -80,7 +80,7 @@ class InfrastructureFactory {
lastUpdate = [:]
}
func loadCache() {
public func loadCache() {
let cacheEntries: [URL]
do {
cacheEntries = try FileManager.default.contentsOfDirectory(at: cachePath, includingPropertiesForKeys: nil)
@ -110,14 +110,14 @@ class InfrastructureFactory {
}
}
func get(_ name: Infrastructure.Name) -> Infrastructure {
public func get(_ name: Infrastructure.Name) -> Infrastructure {
guard let infra = cache[name] ?? bundle[name] else {
fatalError("No infrastructure embedded nor cached for '\(name)'")
}
return infra
}
func update(_ name: Infrastructure.Name, notBeforeInterval minInterval: TimeInterval?, completionHandler: @escaping ((Infrastructure, Date)?, Error?) -> Void) -> Bool {
public func update(_ name: Infrastructure.Name, notBeforeInterval minInterval: TimeInterval?, completionHandler: @escaping ((Infrastructure, Date)?, Error?) -> Void) -> Bool {
let ifModifiedSince = modificationDate(for: name)
if let lastInfrastructureUpdate = lastUpdate[name] {
@ -191,7 +191,7 @@ class InfrastructureFactory {
return true
}
func modificationDate(for name: Infrastructure.Name) -> Date? {
public func modificationDate(for name: Infrastructure.Name) -> Date? {
let optBundleDate = bundleModificationDate(for: name)
guard let cacheDate = cacheModificationDate(for: name) else {
return optBundleDate

View File

@ -29,8 +29,8 @@ import TunnelKit
// supports a subset of TunnelKitProvider.Configuration
// ignores new JSON keys
struct InfrastructurePreset: Codable {
enum PresetKeys: String, CodingKey {
public struct InfrastructurePreset: Codable {
public enum PresetKeys: String, CodingKey {
case id
case name
@ -40,7 +40,7 @@ struct InfrastructurePreset: Codable {
case configuration = "cfg"
}
enum ConfigurationKeys: String, CodingKey {
public enum ConfigurationKeys: String, CodingKey {
case endpointProtocols = "ep"
case cipher
@ -62,21 +62,21 @@ struct InfrastructurePreset: Codable {
case usesPIAPatches = "pia"
}
let id: String
public let id: String
let name: String
public let name: String
let comment: String
public let comment: String
let configuration: TunnelKitProvider.Configuration
public let configuration: TunnelKitProvider.Configuration
func hasProtocol(_ proto: EndpointProtocol) -> Bool {
public func hasProtocol(_ proto: EndpointProtocol) -> Bool {
return configuration.endpointProtocols.index(of: proto) != nil
}
// MARK: Codable
init(from decoder: Decoder) throws {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: PresetKeys.self)
id = try container.decode(String.self, forKey: .id)
name = try container.decode(String.self, forKey: .name)
@ -102,7 +102,7 @@ struct InfrastructurePreset: Codable {
configuration = builder.build()
}
func encode(to encoder: Encoder) throws {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: PresetKeys.self)
try container.encode(id, forKey: .id)
try container.encode(name, forKey: .name)

View File

@ -26,8 +26,8 @@
import Foundation
import TunnelKit
struct Pool: Codable, Comparable, CustomStringConvertible {
enum CodingKeys: String, CodingKey {
public struct Pool: Codable, Comparable, CustomStringConvertible {
public enum CodingKeys: String, CodingKey {
case id
case name
@ -41,19 +41,19 @@ struct Pool: Codable, Comparable, CustomStringConvertible {
case numericAddresses = "addrs"
}
let id: String
public let id: String
let name: String
public let name: String
let country: String
public let country: String
// let location: (Double, Double)
// public let location: (Double, Double)
let hostname: String
public let hostname: String
let numericAddresses: [UInt32]
public let numericAddresses: [UInt32]
func hasAddress(_ address: String) -> Bool {
public func hasAddress(_ address: String) -> Bool {
guard let ipv4 = DNSResolver.ipv4(fromString: address) else {
return false
}
@ -61,7 +61,7 @@ struct Pool: Codable, Comparable, CustomStringConvertible {
}
// XXX: inefficient, can't easily use lazy on struct
func addresses() -> [String] {
public func addresses() -> [String] {
var addrs = numericAddresses.map { DNSResolver.string(fromIPv4: $0) }
addrs.insert(hostname, at: 0)
return addrs
@ -69,13 +69,13 @@ struct Pool: Codable, Comparable, CustomStringConvertible {
// MARK: Comparable
static func <(lhs: Pool, rhs: Pool) -> Bool {
public static func <(lhs: Pool, rhs: Pool) -> Bool {
return lhs.name < rhs.name
}
// MARK: CustomStringConvertible
var description: String {
public var description: String {
return "{[\(id)] \"\(name)\"}"
}
}

View File

@ -28,8 +28,8 @@ import SwiftyBeaver
private let log = SwiftyBeaver.self
class WebServices {
enum Endpoint {
public class WebServices {
public enum Endpoint {
case network(Infrastructure.Name)
var path: String {
@ -40,22 +40,22 @@ class WebServices {
}
}
struct Response<T> {
let value: T?
public struct Response<T> {
public let value: T?
let lastModifiedString: String?
public let lastModifiedString: String?
var lastModified: Date? {
public var lastModified: Date? {
guard let string = lastModifiedString else {
return nil
}
return lmFormatter.date(from: string)
}
let isCached: Bool
public let isCached: Bool
}
static let shared = WebServices()
public static let shared = WebServices()
private static let lmFormatter: DateFormatter = {
let fmt = DateFormatter()
@ -64,7 +64,7 @@ class WebServices {
return fmt
}()
func network(with name: Infrastructure.Name, ifModifiedSince lastModified: Date?, completionHandler: @escaping (Response<Infrastructure>?, Error?) -> Void) {
public func network(with name: Infrastructure.Name, ifModifiedSince lastModified: Date?, completionHandler: @escaping (Response<Infrastructure>?, Error?) -> Void) {
var request = get(.network(name))
if let lastModified = lastModified {
request.addValue(WebServices.lmFormatter.string(from: lastModified), forHTTPHeaderField: "If-Modified-Since")

View File

@ -33,7 +33,7 @@ import SwiftyBeaver
private let log = SwiftyBeaver.self
class Utils {
public class Utils {
fileprivate static let timestampFormatter: DateFormatter = {
let fmt = DateFormatter()
fmt.dateStyle = .medium
@ -47,7 +47,7 @@ class Utils {
return fmt
}()
static func versionString() -> String {
public static func versionString() -> String {
let info = Bundle.main.infoDictionary
guard let version = info?["CFBundleShortVersionString"] else {
fatalError("No bundle version?")
@ -59,11 +59,11 @@ class Utils {
}
#if targetEnvironment(simulator)
static func hasCellularData() -> Bool {
public static func hasCellularData() -> Bool {
return true
}
#else
static func hasCellularData() -> Bool {
public static func hasCellularData() -> Bool {
var addrs: UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&addrs) == 0 else {
return false
@ -84,12 +84,12 @@ class Utils {
#endif
#if targetEnvironment(simulator)
static func currentWifiNetworkName() -> String? {
public static func currentWifiNetworkName() -> String? {
// return nil
return ["FOO", "BAR", "WIFI"].customRandomElement()
}
#else
static func currentWifiNetworkName() -> String? {
public static func currentWifiNetworkName() -> String? {
#if os(iOS)
guard let interfaceNames = CNCopySupportedInterfaces() as? [CFString] else {
return nil
@ -109,11 +109,11 @@ class Utils {
}
#endif
static func regex(_ pattern: String) -> NSRegularExpression {
public static func regex(_ pattern: String) -> NSRegularExpression {
return try! NSRegularExpression(pattern: pattern, options: [])
}
static func checkConnectivityURL(_ url: URL, timeout: TimeInterval, completionHandler: @escaping (Bool) -> Void) {
public static func checkConnectivityURL(_ url: URL, timeout: TimeInterval, completionHandler: @escaping (Bool) -> Void) {
let session = URLSession(configuration: .ephemeral)
let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: timeout)
@ -137,7 +137,7 @@ class Utils {
}
}
extension FileManager {
public extension FileManager {
func userURL(for searchPath: SearchPathDirectory, appending: String?) -> URL {
let paths = urls(for: .documentDirectory, in: .userDomainMask)
var directory = paths[0]
@ -155,13 +155,13 @@ extension FileManager {
}
}
extension Date {
public extension Date {
var timestamp: String {
return Utils.timestampFormatter.string(from: self)
}
}
extension TimeInterval {
public extension TimeInterval {
var localized: String {
guard let str = Utils.componentsFormatter.string(from: self) else {
fatalError("Could not format a TimeInterval?")
@ -170,7 +170,7 @@ extension TimeInterval {
}
}
extension Sequence {
public extension Sequence {
func stableSorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> [Element] {
return try enumerated().sorted {
return try areInIncreasingOrder($0.element, $1.element) ||
@ -179,20 +179,20 @@ extension Sequence {
}
}
extension Array {
public extension Array {
func customRandomElement() -> Element {
let i = Int(arc4random() % UInt32(count))
return self[i]
}
}
extension StringProtocol where Index == String.Index {
public extension StringProtocol where Index == String.Index {
func nsRange(from range: Range<Index>) -> NSRange {
return NSRange(range, in: self)
}
}
extension CharacterSet {
public extension CharacterSet {
static let filename: CharacterSet = {
var chars: CharacterSet = .decimalDigits
let english = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@ -204,7 +204,7 @@ extension CharacterSet {
}()
}
extension URL {
public extension URL {
private static let illegalCharacterFallback = "_"
var normalizedFilename: String {
@ -213,8 +213,8 @@ extension URL {
}
}
extension Array where Element: CustomStringConvertible {
public func sortedCaseInsensitive() -> [Element] {
public extension Array where Element: CustomStringConvertible {
func sortedCaseInsensitive() -> [Element] {
return sorted { $0.description.lowercased() < $1.description.lowercased() }
}
}

View File

@ -28,10 +28,10 @@ import SwiftyBeaver
private let log = SwiftyBeaver.self
class GracefulVPN {
public class GracefulVPN {
private let service: ConnectionService
var profile: ConnectionProfile?
public var profile: ConnectionProfile?
private var vpn: VPNProvider? {
guard let profile = profile else {
@ -43,19 +43,19 @@ class GracefulVPN {
return VPN.shared
}
var isEnabled: Bool {
public var isEnabled: Bool {
return vpn?.isEnabled ?? false
}
var status: VPNStatus? {
public var status: VPNStatus? {
return vpn?.status
}
init(service: ConnectionService) {
public init(service: ConnectionService) {
self.service = service
}
func prepare(completionHandler: (() -> Void)?) {
public func prepare(completionHandler: (() -> Void)?) {
service.clearVpnLastError()
guard let vpn = vpn else {
completionHandler?()
@ -65,7 +65,7 @@ class GracefulVPN {
vpn.prepare(completionHandler: completionHandler)
}
func reconnect(completionHandler: ((Error?) -> Void)?) {
public func reconnect(completionHandler: ((Error?) -> Void)?) {
service.clearVpnLastError()
guard let vpn = vpn else {
completionHandler?(ApplicationError.inactiveProfile)
@ -79,7 +79,7 @@ class GracefulVPN {
}
}
func reinstall(completionHandler: ((Error?) -> Void)?) {
public func reinstall(completionHandler: ((Error?) -> Void)?) {
service.clearVpnLastError()
guard let vpn = vpn else {
completionHandler?(ApplicationError.inactiveProfile)
@ -93,7 +93,7 @@ class GracefulVPN {
}
}
func reinstallIfEnabled() {
public func reinstallIfEnabled() {
guard isEnabled else {
log.warning("Not reinstalling (VPN is disabled)")
return
@ -105,7 +105,7 @@ class GracefulVPN {
}
}
func disconnect(completionHandler: ((Error?) -> Void)?) {
public func disconnect(completionHandler: ((Error?) -> Void)?) {
guard let vpn = vpn else {
completionHandler?(ApplicationError.inactiveProfile)
return
@ -113,7 +113,7 @@ class GracefulVPN {
vpn.disconnect(completionHandler: completionHandler)
}
func uninstall(completionHandler: (() -> Void)?) {
public func uninstall(completionHandler: (() -> Void)?) {
guard let vpn = vpn else {
completionHandler?()
return
@ -121,7 +121,7 @@ class GracefulVPN {
vpn.uninstall(completionHandler: completionHandler)
}
func requestBytesCount(completionHandler: @escaping ((UInt, UInt)?) -> Void) {
public func requestBytesCount(completionHandler: @escaping ((UInt, UInt)?) -> Void) {
guard let vpn = vpn else {
completionHandler(nil)
return

View File

@ -25,57 +25,57 @@
import Foundation
class MockVPNProvider: VPNProvider {
let isPrepared: Bool = true
public class MockVPNProvider: VPNProvider {
public let isPrepared: Bool = true
private(set) var isEnabled: Bool = false
public private(set) var isEnabled: Bool = false
private(set) var status: VPNStatus = .disconnected
public private(set) var status: VPNStatus = .disconnected
func prepare(completionHandler: (() -> Void)?) {
public func prepare(completionHandler: (() -> Void)?) {
NotificationCenter.default.post(name: .VPNDidPrepare, object: nil)
completionHandler?()
}
func install(configuration: VPNConfiguration, completionHandler: ((Error?) -> Void)?) {
public func install(configuration: VPNConfiguration, completionHandler: ((Error?) -> Void)?) {
isEnabled = true
completionHandler?(nil)
}
func connect(completionHandler: ((Error?) -> Void)?) {
public func connect(completionHandler: ((Error?) -> Void)?) {
isEnabled = true
status = .connected
NotificationCenter.default.post(name: .VPNDidChangeStatus, object: self)
completionHandler?(nil)
}
func disconnect(completionHandler: ((Error?) -> Void)?) {
public func disconnect(completionHandler: ((Error?) -> Void)?) {
isEnabled = false
status = .disconnected
NotificationCenter.default.post(name: .VPNDidChangeStatus, object: self)
completionHandler?(nil)
}
func reconnect(configuration: VPNConfiguration, completionHandler: ((Error?) -> Void)?) {
public func reconnect(configuration: VPNConfiguration, completionHandler: ((Error?) -> Void)?) {
isEnabled = true
status = .connected
NotificationCenter.default.post(name: .VPNDidChangeStatus, object: self)
completionHandler?(nil)
}
func uninstall(completionHandler: (() -> Void)?) {
public func uninstall(completionHandler: (() -> Void)?) {
isEnabled = false
status = .disconnected
NotificationCenter.default.post(name: .VPNDidChangeStatus, object: self)
completionHandler?()
}
func requestDebugLog(fallback: (() -> String)?, completionHandler: @escaping (String) -> Void) {
public func requestDebugLog(fallback: (() -> String)?, completionHandler: @escaping (String) -> Void) {
let log = [String](repeating: "lorem ipsum", count: 1000).joined(separator: " ")
completionHandler(log)
}
func requestBytesCount(completionHandler: @escaping ((UInt, UInt)?) -> Void) {
public func requestBytesCount(completionHandler: @escaping ((UInt, UInt)?) -> Void) {
completionHandler((0, 0))
}
}

View File

@ -27,14 +27,14 @@ import Foundation
import NetworkExtension
import TunnelKit
class StandardVPNProvider: VPNProvider {
public class StandardVPNProvider: VPNProvider {
private let bundleIdentifier: String
private var manager: NETunnelProviderManager?
private var lastNotifiedStatus: VPNStatus?
init(bundleIdentifier: String) {
public init(bundleIdentifier: String) {
self.bundleIdentifier = bundleIdentifier
let nc = NotificationCenter.default
@ -48,18 +48,18 @@ class StandardVPNProvider: VPNProvider {
// MARK: VPNProvider
var isPrepared: Bool {
public var isPrepared: Bool {
return manager != nil
}
var isEnabled: Bool {
public var isEnabled: Bool {
guard let manager = manager else {
return false
}
return manager.isEnabled && manager.isOnDemandEnabled
}
var status: VPNStatus {
public var status: VPNStatus {
guard let neStatus = manager?.connection.status else {
return .disconnected
}
@ -78,7 +78,7 @@ class StandardVPNProvider: VPNProvider {
}
}
func prepare(completionHandler: (() -> Void)?) {
public func prepare(completionHandler: (() -> Void)?) {
find(with: bundleIdentifier) {
self.manager = $0
NotificationCenter.default.post(name: .VPNDidPrepare, object: nil)
@ -86,7 +86,7 @@ class StandardVPNProvider: VPNProvider {
}
}
func install(configuration: VPNConfiguration, completionHandler: ((Error?) -> Void)?) {
public func install(configuration: VPNConfiguration, completionHandler: ((Error?) -> Void)?) {
guard let configuration = configuration as? NetworkExtensionVPNConfiguration else {
fatalError("Not a NetworkExtensionVPNConfiguration")
}
@ -110,7 +110,7 @@ class StandardVPNProvider: VPNProvider {
}
}
func connect(completionHandler: ((Error?) -> Void)?) {
public func connect(completionHandler: ((Error?) -> Void)?) {
do {
try manager?.connection.startVPNTunnel()
completionHandler?(nil)
@ -119,14 +119,14 @@ class StandardVPNProvider: VPNProvider {
}
}
func disconnect(completionHandler: ((Error?) -> Void)?) {
public func disconnect(completionHandler: ((Error?) -> Void)?) {
manager?.connection.stopVPNTunnel()
manager?.isOnDemandEnabled = false
manager?.isEnabled = false
manager?.saveToPreferences(completionHandler: completionHandler)
}
func reconnect(configuration: VPNConfiguration, completionHandler: ((Error?) -> Void)?) {
public func reconnect(configuration: VPNConfiguration, completionHandler: ((Error?) -> Void)?) {
guard let configuration = configuration as? NetworkExtensionVPNConfiguration else {
fatalError("Not a NetworkExtensionVPNConfiguration")
}
@ -147,7 +147,7 @@ class StandardVPNProvider: VPNProvider {
}
}
func uninstall(completionHandler: (() -> Void)?) {
public func uninstall(completionHandler: (() -> Void)?) {
find(with: bundleIdentifier) { (manager) in
manager?.connection.stopVPNTunnel()
manager?.removeFromPreferences { (error) in
@ -157,7 +157,7 @@ class StandardVPNProvider: VPNProvider {
}
}
func requestDebugLog(fallback: (() -> String)?, completionHandler: @escaping (String) -> Void) {
public func requestDebugLog(fallback: (() -> String)?, completionHandler: @escaping (String) -> Void) {
guard status != .disconnected else {
completionHandler(fallback?() ?? "")
return
@ -173,7 +173,7 @@ class StandardVPNProvider: VPNProvider {
}
}
func requestBytesCount(completionHandler: @escaping ((UInt, UInt)?) -> Void) {
public func requestBytesCount(completionHandler: @escaping ((UInt, UInt)?) -> Void) {
find(with: bundleIdentifier) {
self.manager = $0
guard let session = self.manager?.connection as? NETunnelProviderSession else {

View File

@ -25,10 +25,10 @@
import Foundation
class VPN {
public class VPN {
#if targetEnvironment(simulator)
static let shared = MockVPNProvider()
public static let shared = MockVPNProvider()
#else
static let shared = StandardVPNProvider(bundleIdentifier: GroupConstants.App.tunnelIdentifier)
public static let shared = StandardVPNProvider(bundleIdentifier: GroupConstants.App.tunnelIdentifier)
#endif
}

View File

@ -26,11 +26,11 @@
import Foundation
import NetworkExtension
protocol VPNConfiguration {
public protocol VPNConfiguration {
}
struct NetworkExtensionVPNConfiguration: VPNConfiguration {
let protocolConfiguration: NETunnelProviderProtocol
public struct NetworkExtensionVPNConfiguration: VPNConfiguration {
public let protocolConfiguration: NETunnelProviderProtocol
let onDemandRules: [NEOnDemandRule]
public let onDemandRules: [NEOnDemandRule]
}

View File

@ -25,7 +25,7 @@
import Foundation
protocol VPNProvider: class {
public protocol VPNProvider: class {
var isPrepared: Bool { get }
var isEnabled: Bool { get }
@ -49,7 +49,7 @@ protocol VPNProvider: class {
func requestBytesCount(completionHandler: @escaping ((UInt, UInt)?) -> Void)
}
extension Notification.Name {
public extension Notification.Name {
static let VPNDidPrepare = Notification.Name("VPNDidPrepare")
static let VPNDidChangeStatus = Notification.Name("VPNDidChangeStatus")

View File

@ -25,7 +25,7 @@
import Foundation
enum VPNStatus {
public enum VPNStatus {
case connected
case connecting