[
  {
    "path": ".gitignore",
    "content": "## System\n.DS_Store\n\n## Build generated\nbuild/\nDerivedData\nNuke.xcodeproj/xcshareddata/xcbaselines/\n\n## Various settings\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n\n## Other\n*.xccheckout\n*.moved-aside\n*.xcuserstate\n*.xcscmblueprint\n\n## Obj-C/Swift specific\n*.hmap\n*.ipa\n\n## Playgrounds\ntimeline.xctimeline\nplayground.xcworkspace\n\n\n## Swift Package Manager\n#\n# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.\n# Packages/\n\n.build/\n\n\n## CocoaPods\n#\n# We recommend against adding the Pods directory to your .gitignore. However\n# you should judge for yourself, the pros and cons are mentioned at:\n# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control\n#\n\nPods/\n\n\n## Carthage\n#\n# Add this line if you want to avoid checking in source code from Carthage dependencies.\n\nCarthage\n"
  },
  {
    "path": "README.md",
    "content": "# VPN (WIP)\n\nA sample VPN client/server written in Swift.\n\n# License\n\nVPN is available under the MIT license. See the LICENSE file for more info.\n"
  },
  {
    "path": "vpn-client/AppDelegate.swift",
    "content": "// The MIT License (MIT)\n//\n// Copyright (c) 2020 Alexander Grebenyuk (github.com/kean).\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n        // Override point for customization after application launch.\n        return true\n    }\n\n    // MARK: UISceneSession Lifecycle\n\n    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {\n        // Called when a new scene session is being created.\n        // Use this method to select a configuration to create the new scene with.\n        return UISceneConfiguration(name: \"Default Configuration\", sessionRole: connectingSceneSession.role)\n    }\n\n    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {\n        // Called when the user discards a scene session.\n        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.\n        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.\n    }\n\n\n}\n\n"
  },
  {
    "path": "vpn-client/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"20x20\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"20x20\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"29x29\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"29x29\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"40x40\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"40x40\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"60x60\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"60x60\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"scale\" : \"1x\",\n      \"size\" : \"20x20\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"scale\" : \"2x\",\n      \"size\" : \"20x20\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"scale\" : \"1x\",\n      \"size\" : \"29x29\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"scale\" : \"2x\",\n      \"size\" : \"29x29\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"scale\" : \"1x\",\n      \"size\" : \"40x40\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"scale\" : \"2x\",\n      \"size\" : \"40x40\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"scale\" : \"1x\",\n      \"size\" : \"76x76\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"scale\" : \"2x\",\n      \"size\" : \"76x76\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"scale\" : \"2x\",\n      \"size\" : \"83.5x83.5\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"scale\" : \"1x\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "vpn-client/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "vpn-client/Assets.xcassets/icon-vpn.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"icons8-vpn-status-bar-icon-50.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"filename\" : \"icons8-vpn-status-bar-icon-100.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"filename\" : \"icons8-vpn-status-bar-icon-101.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}\n"
  },
  {
    "path": "vpn-client/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" xcode11CocoaTouchSystemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "vpn-client/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UIApplicationSceneManifest</key>\n\t<dict>\n\t\t<key>UIApplicationSupportsMultipleScenes</key>\n\t\t<false/>\n\t\t<key>UISceneConfigurations</key>\n\t\t<dict>\n\t\t\t<key>UIWindowSceneSessionRoleApplication</key>\n\t\t\t<array>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>UISceneConfigurationName</key>\n\t\t\t\t\t<string>Default Configuration</string>\n\t\t\t\t\t<key>UISceneDelegateClassName</key>\n\t\t\t\t\t<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>\n\t\t\t\t</dict>\n\t\t\t</array>\n\t\t</dict>\n\t</dict>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "vpn-client/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "vpn-client/SceneDelegate.swift",
    "content": "// The MIT License (MIT)\n//\n// Copyright (c) 2020 Alexander Grebenyuk (github.com/kean).\n\nimport UIKit\nimport SwiftUI\n\nclass SceneDelegate: UIResponder, UIWindowSceneDelegate {\n\n    var window: UIWindow?\n\n\n    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {\n        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.\n        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.\n        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).\n\n        // Create the SwiftUI view that provides the window contents.\n        let contentView = RouterView()\n\n        // Use a UIHostingController as window root view controller.\n        if let windowScene = scene as? UIWindowScene {\n            let window = UIWindow(windowScene: windowScene)\n            window.rootViewController = UIHostingController(rootView: contentView)\n            self.window = window\n            window.makeKeyAndVisible()\n        }\n    }\n\n    func sceneDidDisconnect(_ scene: UIScene) {\n        // Called as the scene is being released by the system.\n        // This occurs shortly after the scene enters the background, or when its session is discarded.\n        // Release any resources associated with this scene that can be re-created the next time the scene connects.\n        // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).\n    }\n\n    func sceneDidBecomeActive(_ scene: UIScene) {\n        // Called when the scene has moved from an inactive state to an active state.\n        // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.\n    }\n\n    func sceneWillResignActive(_ scene: UIScene) {\n        // Called when the scene will move from an active state to an inactive state.\n        // This may occur due to temporary interruptions (ex. an incoming phone call).\n    }\n\n    func sceneWillEnterForeground(_ scene: UIScene) {\n        // Called as the scene transitions from the background to the foreground.\n        // Use this method to undo the changes made on entering the background.\n    }\n\n    func sceneDidEnterBackground(_ scene: UIScene) {\n        // Called as the scene transitions from the foreground to the background.\n        // Use this method to save data, release shared resources, and store enough scene-specific state information\n        // to restore the scene back to its current state.\n    }\n\n\n}\n\n"
  },
  {
    "path": "vpn-client/Screens/PrimaryButton.swift",
    "content": "// The MIT License (MIT)\n//\n// Copyright (c) 2020 Alexander Grebenyuk (github.com/kean).\n\nimport SwiftUI\n\nstruct PrimaryButton: View {\n    let title: String\n    let action: () -> Void\n    @Binding var isLoading: Bool\n\n    var body: some View {\n        Button(action: self.action) {\n            ZStack {\n                Spinner(isAnimating: $isLoading, color: .white, style: .medium)\n                Text(title)\n                    .opacity(isLoading ? 0 : 1)\n            }\n        }\n            .disabled(isLoading)\n            .padding()\n            .frame(maxWidth: .infinity)\n            .foregroundColor(Color.white)\n            .background(Color.blue)\n            .cornerRadius(8)\n    }\n}\n\nstruct PrimaryButtonView_Previews: PreviewProvider {\n    static var previews: some View {\n        Group {\n            PrimaryButton(title: \"Action\", action: {}, isLoading: .constant(false))\n                .previewLayout(.fixed(width: 300, height: 80))\n\n            PrimaryButton(title: \"Action\", action: {}, isLoading: .constant(false))\n                .previewLayout(.fixed(width: 300, height: 80))\n                .environment(\\.colorScheme, .dark)\n\n            PrimaryButton(title: \"Action\", action: {}, isLoading: .constant(true))\n                .previewLayout(.fixed(width: 300, height: 80))\n        }\n    }\n}\n"
  },
  {
    "path": "vpn-client/Screens/PrimaryButtonView.swift",
    "content": "// The MIT License (MIT)\n//\n// Copyright (c) 2020 Alexander Grebenyuk (github.com/kean).\n\nimport SwiftUI\n\nstruct PrimaryButton: View {\n    let title: String\n    let action: () -> Void\n    @Binding var isLoading: Bool\n\n    var body: some View {\n        Button(action: self.action) {\n            ZStack {\n                Spinner(isAnimating: .constant(true), style: .medium)\n                Text(title)\n            }\n        }\n            .padding()\n            .foregroundColor(Color.white)\n            .background(Color.blue)\n            .cornerRadius(8)\n    }\n}\n\nstruct PrimaryButtonView_Previews: PreviewProvider {\n    static var previews: some View {\n        Group {\n            PrimaryButton(title: \"Action\", action: {}, isLoading: .constant(false))\n                .previewLayout(.fixed(width: 300, height: 80))\n\n            PrimaryButton(title: \"Action\", action: {}, isLoading: .constant(false))\n                .previewLayout(.fixed(width: 300, height: 80))\n                .environment(\\.colorScheme, .dark)\n\n            PrimaryButton(title: \"Action\", action: {}, isLoading: .constant(true))\n                .previewLayout(.fixed(width: 300, height: 80))\n        }\n    }\n}\n"
  },
  {
    "path": "vpn-client/Screens/RouterView.swift",
    "content": "// The MIT License (MIT)\n//\n// Copyright (c) 2020 Alexander Grebenyuk (github.com/kean).\n\nimport SwiftUI\n\nstruct RouterView: View {\n    @ObservedObject var service: VPNConfigurationService = .shared\n\n    var body: some View {\n        if !service.isStarted {\n            return AnyView(SplashView())\n        } else {\n            if let tunnel = service.tunnel {\n                return AnyView(TunnelDetailsView(model: TunnelViewModel(tunnel: tunnel)))\n            } else {\n                return AnyView(WelcomeView())\n            }\n        }\n    }\n}\n\nstruct RouterView_Previews: PreviewProvider {\n    static var previews: some View {\n        RouterView()\n    }\n}\n"
  },
  {
    "path": "vpn-client/Screens/Spinner.swift",
    "content": "// The MIT License (MIT)\n//\n// Copyright (c) 2020 Alexander Grebenyuk (github.com/kean).\n\nimport SwiftUI\nimport UIKit\n\nstruct Spinner: UIViewRepresentable {\n    @Binding var isAnimating: Bool\n\n    let color: UIColor\n    let style: UIActivityIndicatorView.Style\n\n    func makeUIView(context: Context) -> UIActivityIndicatorView {\n        let indicator = UIActivityIndicatorView(style: style)\n        indicator.hidesWhenStopped = true\n        indicator.color = color\n        return indicator\n    }\n\n    func updateUIView(_ uiView: UIActivityIndicatorView, context: Context) {\n        isAnimating ? uiView.startAnimating() : uiView.stopAnimating()\n    }\n}\n"
  },
  {
    "path": "vpn-client/Screens/SplashView.swift",
    "content": "// The MIT License (MIT)\n//\n// Copyright (c) 2020 Alexander Grebenyuk (github.com/kean).\n\nimport SwiftUI\nimport NetworkExtension\n\nstruct SplashView: View {\n    @ObservedObject var service: VPNConfigurationService = .shared\n\n    @State private var isLoading = false\n    @State private var isShowingError = false\n    @State private var errorMessage = \"\"\n\n    var body: some View {\n        VStack {\n            Text(\"BestVPN\")\n                .font(.largeTitle)\n                .fontWeight(.heavy)\n            Spacer().frame(height: 32)\n            HStack {\n                Text(\"Loading profiles…\")\n                Spinner(isAnimating: $isLoading, color: .label, style: .medium)\n            }\n        }\n        .onAppear(perform: refresh)\n        .alert(isPresented: $isShowingError) {\n            Alert(\n                title: Text(\"Failed to load profiles\"),\n                message: Text(errorMessage),\n                primaryButton: .default(Text(\"Retry\"), action: refresh),\n                secondaryButton: .cancel()\n            )\n        }\n    }\n\n    private func refresh() {\n        isLoading = true\n        service.refresh {\n            self.isLoading = false\n            switch $0 {\n            case .success:\n                break // Handled by RouterView\n            case let .failure(error):\n                self.errorMessage = error.localizedDescription\n                self.isShowingError = true\n            }\n        }\n    }\n}\n\nstruct SplashView_Previews: PreviewProvider {\n    static var previews: some View {\n        SplashView()\n    }\n}\n"
  },
  {
    "path": "vpn-client/Screens/TunnelDetails/TunnelDetailsView.swift",
    "content": "// The MIT License (MIT)\n//\n// Copyright (c) 2020 Alexander Grebenyuk (github.com/kean).\n\nimport SwiftUI\n\nstruct TunnelDetailsView: View {\n    @ObservedObject var model: TunnelViewModel\n\n    var body: some View {\n        NavigationView {\n            Form {\n                Section(header: Text(\"Settings\")) {\n                    TextInputView(title: \"Username\", text: $model.username)\n                    TextInputView(title: \"Password\", text: $model.password)\n                    TextInputView(title: \"Server\", text: $model.server)\n                    Button(action: model.buttonSaveTapped) { Text(\"Save\") }\n                        .foregroundColor(Color.blue)\n                }\n                Section(header: Text(\"Status\")) {\n                    Toggle(isOn: $model.isEnabled, label: { Text(\"Enabled\") })\n                    if model.isEnabled {\n                        Text(\"Status: \") + Text(model.status).bold()\n                        if model.isStarted {\n                            Button(action: model.buttonStopTapped) { Text(\"Stop\") }\n                                .foregroundColor(Color.orange)\n                        } else {\n                            Button(action: model.buttonStartTapped) { Text(\"Start\") }\n                                .foregroundColor(Color.blue)\n                        }\n                    }\n                }\n                Section {\n                    ButtonRemoveProfile(model: model)\n                }\n            }\n            .disabled(model.isLoading)\n            .alert(isPresented: $model.isShowingError) {\n                Alert(\n                    title: Text(self.model.errorTitle),\n                    message: Text(self.model.errorMessage),\n                    dismissButton: .cancel()\n                )\n            }\n            .navigationBarItems(trailing:\n                Spinner(isAnimating: $model.isLoading, color: .label, style: .medium)\n            )\n            .navigationBarTitle(\"VPN Status\")\n        }\n    }\n}\n\nprivate struct TextInputView: View {\n    let title: String\n    let text: Binding<String>\n\n    var body: some View {\n        HStack(alignment: .center) {\n            Text(title)\n                .font(.callout)\n            TextField(title, text: text)\n                .multilineTextAlignment(.trailing)\n                .foregroundColor(Color.gray)\n        }\n    }\n}\n\nprivate struct ButtonRemoveProfile: View {\n    let model: TunnelViewModel\n\n    @State private var isConfirmationPresented = false\n\n    var body: some View {\n        Button(action: {\n            self.isConfirmationPresented = true\n        }) {\n            Text(\"Remove Profile\")\n        }\n        .foregroundColor(.red)\n        .alert(isPresented: $isConfirmationPresented) {\n            Alert(\n                title: Text(\"Are you sure you want to remove the profile?\"),\n                primaryButton: .destructive(Text(\"Remove profile\"), action: {\n                    self.isConfirmationPresented = false\n                    self.model.buttonRemoveProfileTapped()\n                }),\n                secondaryButton: .cancel()\n            )\n        }\n    }\n}\n\nstruct TunnelView_Previews: PreviewProvider {\n    static var previews: some View {\n        TunnelDetailsView(model: .init(tunnel: .init()))\n    }\n}\n"
  },
  {
    "path": "vpn-client/Screens/TunnelDetails/TunnelDetailsViewModel.swift",
    "content": "// The MIT License (MIT)\n//\n// Copyright (c) 2020 Alexander Grebenyuk (github.com/kean).\n\nimport SwiftUI\nimport Combine\nimport NetworkExtension\n\nfinal class TunnelViewModel: ObservableObject {\n    @Published var username = \"\"\n    @Published var password = \"\"\n    @Published var server = \"\"\n\n    @Published var isEnabled = false\n    @Published var isStarted = false\n\n    @Published private(set) var status: String = \"Unknown\"\n\n    @Published var isLoading = false\n    @Published var isShowingError = false\n    @Published private(set) var errorTitle = \"\"\n    @Published private(set) var errorMessage = \"\"\n\n    private let service: VPNConfigurationService\n    private let tunnel: NETunnelProviderManager\n\n    private var observers = [AnyObject]()\n    private var bag = [AnyCancellable]()\n\n    init(service: VPNConfigurationService = .shared, tunnel: NETunnelProviderManager) {\n        self.service = service\n        self.tunnel = tunnel\n\n        self.refresh()\n\n        observers.append(NotificationCenter.default\n            .addObserver(forName: .NEVPNStatusDidChange, object: tunnel.connection, queue: .main) { [weak self] _ in\n                self?.refresh()\n        })\n\n        observers.append(NotificationCenter.default\n            .addObserver(forName: .NEVPNConfigurationChange, object: tunnel, queue: .main) { [weak self] _ in\n                self?.refresh()\n        })\n\n        $isEnabled.sink { [weak self] in\n            self?.setEnabled($0)\n        }.store(in: &bag)\n    }\n\n    private func refresh() {\n        self.status = tunnel.connection.status.description\n        let username = tunnel.protocolConfiguration?.username ?? \"\"\n        self.username = username\n        self.password = tunnel.protocolConfiguration?.passwordReference.flatMap {\n            Keychain.password(for: username, reference: $0)\n        } ?? \"\"\n        self.server = tunnel.protocolConfiguration?.serverAddress ?? \"\"\n        self.isEnabled = tunnel.isEnabled\n        self.isStarted = tunnel.connection.status != .disconnected && tunnel.connection.status != .invalid\n    }\n\n    private func setEnabled(_ isEnabled: Bool) {\n        guard isEnabled != tunnel.isEnabled else { return }\n        tunnel.isEnabled = isEnabled\n        saveToPreferences()\n    }\n\n    func buttonStartTapped() {\n        do {\n            try tunnel.connection.startVPNTunnel(options: [:] as [String : NSObject])\n        } catch {\n            self.showError(title: \"Failed to start VPN tunnel\", message: error.localizedDescription)\n        }\n    }\n\n    func buttonStopTapped() {\n        tunnel.connection.stopVPNTunnel()\n    }\n\n    func buttonRemoveProfileTapped() {\n        isLoading = true\n\n        service.removeProfile { [weak self] in\n            guard let self = self else { return }\n            self.isLoading = false\n            switch $0 {\n            case .success:\n            break // Do nothing, router will show what's next\n            case let .failure(error):\n                self.showError(title: \"Failed to install a profile\", message: error.localizedDescription)\n            }\n        }\n    }\n\n    private func saveToPreferences() {\n        isLoading = true\n        tunnel.saveToPreferences { [weak self] error in\n            guard let self = self else { return }\n            self.isLoading = false\n            if let error = error {\n                self.showError(title: \"Failed to update VPN configuration\", message: error.localizedDescription)\n                self.errorMessage = error.localizedDescription\n                return\n            }\n        }\n    }\n\n    private func showError(title: String, message: String) {\n        self.errorTitle = title\n        self.errorMessage = message\n        self.isShowingError = true\n    }\n\n    func buttonSaveTapped() {\n        let proto = tunnel.protocolConfiguration as! NETunnelProviderProtocol\n        proto.username = self.username\n        proto.passwordReference = {\n            let keychain = Keychain(group: \"group.com.github.kean.vpn-client\")\n            keychain.set(password: self.password, for: username)\n            return keychain.passwordReference(for: username)\n        }()\n        proto.serverAddress = server\n\n        tunnel.protocolConfiguration = proto\n\n        saveToPreferences()\n    }\n\n    private func sayHelloToTunnel() {\n        // Send a simple IPC message to the provider, handle the response.\n        guard let session = tunnel.connection as? NETunnelProviderSession,\n            let message = \"Hello Provider\".data(using: String.Encoding.utf8), tunnel.connection.status != .invalid else {\n                return\n        }\n\n        do {\n            try session.sendProviderMessage(message) { response in\n                if response != nil {\n                    let responseString = NSString(data: response!, encoding: String.Encoding.utf8.rawValue)\n                    NSLog(\"Received response from the provider: \\(String(describing: responseString))\")\n                } else {\n                    NSLog(\"Got a nil response from the provider\")\n                }\n            }\n        } catch {\n            NSLog(\"Failed to send a message to the provider\")\n        }\n    }\n}\n"
  },
  {
    "path": "vpn-client/Screens/WelcomeView.swift",
    "content": "// The MIT License (MIT)\n//\n// Copyright (c) 2020 Alexander Grebenyuk (github.com/kean).\n\nimport SwiftUI\n\nstruct WelcomeView: View {\n    let service: VPNConfigurationService = .shared\n\n    @State private var isLoading = false\n    @State private var isShowingError = false\n    @State private var errorMessage = \"\"\n\n    var body: some View {\n        NavigationView {\n            VStack {\n                header\n                Spacer(minLength: 0)\n                buttonInstall\n                Spacer().frame(height: 16)\n            }.padding()\n        }\n    }\n\n    private var header: some View {\n        VStack {\n            Text(\"BestVPN\")\n                .font(.largeTitle)\n                .fontWeight(.heavy)\n            HStack(spacing: 20) {\n                Image(\"icon-vpn\")\n                    .resizable()\n                    .frame(width: 50, height: 50)\n                VStack(alignment: .leading) {\n                    Text(\"Custom VPN solution\")\n                        .font(.headline)\n                    Text(\"Powered by Network Extension and SwiftNIO\")\n                }\n            }\n        }\n    }\n\n    private var buttonInstall: some View {\n        PrimaryButton(\n            title: \"Install VPN Profile\",\n            action: self.installProfile,\n            isLoading: $isLoading\n        ).alert(isPresented: $isShowingError) {\n            Alert(\n                title: Text(\"Failed to install a profile\"),\n                message: Text(errorMessage),\n                dismissButton: .cancel()\n            )\n        }\n    }\n\n    private func installProfile() {\n        isLoading = true\n\n        service.installProfile { result in\n            self.isLoading = false\n            switch result {\n            case .success:\n                break // Do nothing, router will show what's next\n            case let .failure(error):\n                self.errorMessage = error.localizedDescription\n                self.isShowingError = true\n            }\n        }\n    }\n}\n\nstruct WelcomeView_Previews: PreviewProvider {\n    static var previews: some View {\n        WelcomeView()\n    }\n}\n"
  },
  {
    "path": "vpn-client/Services/Keychain.swift",
    "content": "// The MIT License (MIT)\n//\n// Copyright (c) 2020 Alexander Grebenyuk (github.com/kean).\n\nimport Foundation\n\n/// Wrapper for easy keychain access and modification.\npublic final class Keychain {\n    private let accessGroup: String\n\n    public init(group: String) {\n        self.accessGroup = group\n    }\n\n    @discardableResult\n    public func set(password: String, for username: String, label: String? = nil) -> OSStatus {\n        removePassword(for: username)\n\n        var query = [String: Any]()\n        query[kSecAttrAccessGroup as String] = accessGroup\n        query[kSecClass as String] = kSecClassGenericPassword\n        if let label = label {\n            query[kSecAttrLabel as String] = label\n        }\n        query[kSecAttrAccount as String] = username\n        query[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock\n        query[kSecValueData as String] = password.data(using: .utf8)\n\n        return SecItemAdd(query as CFDictionary, nil)\n    }\n\n    @discardableResult\n    public func removePassword(for username: String) -> Bool {\n        var query = [String: Any]()\n        query[kSecAttrAccessGroup as String] = accessGroup\n        query[kSecClass as String] = kSecClassGenericPassword\n        query[kSecAttrAccount as String] = username\n\n        let status = SecItemDelete(query as CFDictionary)\n        return status == errSecSuccess\n    }\n\n    public func password(for username: String) throws -> String? {\n        var query = [String: Any]()\n        query[kSecAttrAccessGroup as String] = accessGroup\n        query[kSecClass as String] = kSecClassGenericPassword\n        query[kSecAttrAccount as String] = username\n        query[kSecMatchLimit as String] = kSecMatchLimitOne\n        query[kSecReturnData as String] = true\n\n        var result: AnyObject?\n        let status = SecItemCopyMatching(query as CFDictionary, &result)\n        guard status == errSecSuccess, let data = result as? Data else {\n            return nil\n        }\n        return String(data: data, encoding: .utf8)\n    }\n\n    public func passwordReference(for username: String) -> Data? {\n        var query = [String: Any]()\n        query[kSecAttrAccessGroup as String] = accessGroup\n        query[kSecClass as String] = kSecClassGenericPassword\n        query[kSecAttrAccount as String] = username\n        query[kSecMatchLimit as String] = kSecMatchLimitOne\n        query[kSecReturnPersistentRef as String] = true\n\n        var result: AnyObject?\n        let status = SecItemCopyMatching(query as CFDictionary, &result)\n        guard status == errSecSuccess, let data = result as? Data else {\n            return nil\n        }\n        return data\n    }\n\n    public static func password(for username: String, reference: Data) -> String? {\n        var query = [String: Any]()\n        query[kSecClass as String] = kSecClassGenericPassword\n        query[kSecAttrAccount as String] = username\n        query[kSecMatchItemList as String] = [reference]\n        query[kSecReturnData as String] = true\n\n        var result: AnyObject?\n        let status = SecItemCopyMatching(query as CFDictionary, &result)\n        guard status == errSecSuccess, let data = result as? Data else {\n            return nil\n        }\n        return String(data: data, encoding: .utf8)\n    }\n}\n"
  },
  {
    "path": "vpn-client/Services/VPNConfigurationService.swift",
    "content": "// The MIT License (MIT)\n//\n// Copyright (c) 2020 Alexander Grebenyuk (github.com/kean).\n\nimport Foundation\nimport Combine\nimport NetworkExtension\nimport UIKit\n\nfinal class VPNConfigurationService: ObservableObject {\n    @Published private(set) var isStarted = false\n\n    /// If not nil, the tunnel is displayed.\n    @Published private(set) var tunnel: NETunnelProviderManager?\n\n    static let shared = VPNConfigurationService()\n\n    private var observer: AnyObject?\n\n    private init() {\n        observer = NotificationCenter.default.addObserver(\n            forName: UIApplication.willEnterForegroundNotification,\n            object: nil, queue: .main) { [weak self] _ in\n                self?.refresh()\n        }\n    }\n\n    private func refresh() {\n        refresh { _ in }\n    }\n\n    func refresh(_ completion: @escaping (Result<Void, Error>) -> Void) {\n        // Read all of the VPN configurations created by the app that have\n        // previously been saved to the Network Extension preferences.\n        NETunnelProviderManager.loadAllFromPreferences { [weak self] managers, error in\n            guard let self = self else { return }\n\n            // There is only one VPN configuration the app provides\n            self.tunnel = managers?.first\n            if let error = error {\n                completion(.failure(error))\n            } else {\n                self.isStarted = true\n                completion(.success(()))\n            }\n        }\n    }\n\n    func installProfile(_ completion: @escaping (Result<Void, Error>) -> Void) {\n        let tunnel = makeManager()\n        tunnel.saveToPreferences { [weak self] error in\n            if let error = error {\n                return completion(.failure(error))\n            }\n\n            // See https://forums.developer.apple.com/thread/25928\n            tunnel.loadFromPreferences { [weak self] error in\n                self?.tunnel = tunnel\n                completion(.success(()))\n            }\n        }\n    }\n\n    private func makeManager() -> NETunnelProviderManager {\n        let manager = NETunnelProviderManager()\n        manager.localizedDescription = \"BestVPN\"\n\n        let proto = NETunnelProviderProtocol()\n\n        // WARNING: This must match the bundle identifier of the app extension\n        // containing packet tunnel provider.\n        proto.providerBundleIdentifier = \"com.github.kean.vpn-client.vpn-tunnel\"\n\n        // WARNING: This must send the actual VPN server address, for the demo\n        // purposes, I'm passing the address of the server in my local network.\n        // The address is going to be different in your network.\n        proto.serverAddress = \"192.168.0.13:9999\"\n\n        proto.username = \"kean\"\n        proto.passwordReference = {\n            let keychain = Keychain(group: \"group.com.github.kean.vpn-client\")\n            keychain.set(password: \"123456\", for: \"kean\")\n            return keychain.passwordReference(for: \"kean\")\n        }()\n\n        manager.protocolConfiguration = proto\n\n        // Uncomment this to configure on-demand rules to make sure the tunnel\n        // starts automatically when needed.\n//        let onDemandRule = NEOnDemandRuleConnect()\n//        onDemandRule.interfaceTypeMatch = .any\n//        manager.isOnDemandEnabled = true\n//        manager.onDemandRules = [onDemandRule]\n\n        // Enable the manager bu default.\n        manager.isEnabled = true\n\n        return manager\n    }\n\n    private func statusUpdated() {\n\n    }\n    \n    func removeProfile(_ completion: @escaping (Result<Void, Error>) -> Void) {\n        assert(tunnel != nil, \"Tunnel is missing\")\n        tunnel?.removeFromPreferences { error in\n            if let error = error {\n                return completion(.failure(error))\n            }\n            self.tunnel = nil\n            completion(.success(()))\n        }\n    }\n}\n\n// MARK: - Extensions\n\n/// Make NEVPNStatus convertible to a string\nextension NEVPNStatus: CustomStringConvertible {\n    public var description: String {\n        switch self {\n        case .disconnected: return \"Disconnected\"\n        case .invalid: return \"Invalid\"\n        case .connected: return \"Connected\"\n        case .connecting: return \"Connecting\"\n        case .disconnecting: return \"Disconnecting\"\n        case .reasserting: return \"Reconnecting\"\n        @unknown default: return \"Unknown\"\n        }\n    }\n}\n"
  },
  {
    "path": "vpn-client/vpn-client.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.developer.networking.networkextension</key>\n\t<array>\n\t\t<string>packet-tunnel-provider</string>\n\t</array>\n\t<key>com.apple.security.application-groups</key>\n\t<array>\n\t\t<string>group.com.github.kean.vpn-client</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "vpn-protocol/Cipher.swift",
    "content": "// The MIT License (MIT)\n//\n// Copyright (c) 2020 Alexander Grebenyuk (github.com/kean).\n\nimport Foundation\nimport CryptoKit\n\n// WARNING: This is a simplified example, don't use it as a reference.\npublic enum Cipher {\n\n    /// WARNING: This is simplified example, don't do this in production!\n    ///\n    /// A \"pre-shared\" symmetric key.\n    public static let key = SymmetricKey(data: Data(base64Encoded: \"KGiEbfJODclOCzUVfWXBO7Y/ohnEVxf7+RnwaAA1/78=\")!)\n\n    // WARNING: This is a simplified example, don't use it as a reference.\n    public static func encrypt(_ data: Data, key: SymmetricKey) throws -> Data {\n        try ChaChaPoly.seal(data, using: key).combined\n    }\n\n    // WARNING: This is a simplified example, don't use it as a reference.\n    public static func decrypt(_ data: Data, key: SymmetricKey) throws -> Data {\n        try ChaChaPoly.open(ChaChaPoly.SealedBox(combined: data), using: key)\n    }\n}\n\npublic extension SymmetricKey {\n    /// A Data instance created safely from the contiguous bytes without making any copies.\n    var dataRepresentation: Data {\n        return self.withUnsafeBytes { bytes in\n            let cfdata = CFDataCreateWithBytesNoCopy(nil, bytes.baseAddress?.assumingMemoryBound(to: UInt8.self), bytes.count, kCFAllocatorNull)\n            return ((cfdata as NSData?) as Data?) ?? Data()\n        }\n    }\n}\n"
  },
  {
    "path": "vpn-protocol/Packet.swift",
    "content": "// The MIT License (MIT)\n//\n// Copyright (c) 2020 Alexander Grebenyuk (github.com/kean).\n\nimport Foundation\nimport CryptoKit\n\npublic enum PacketCode: UInt8 {\n    /// A control packet containing client authentication request (JSON).\n    case clientAuthRequest = 0x01\n    /// A control packet containing server authentication response (JSON).\n    case serverAuthResponse = 0x02\n    /// A data packet containing encrypted IP packets (raw bytes).\n    case data = 0x03\n\n    /// Initilizes the code code with the given UDP packet contents.\n    public init(datagram: Data) throws {\n        guard datagram.count > 0 else {\n            throw PacketParsingError.notEnoughData\n        }\n        guard let code = PacketCode(rawValue: datagram[0]) else {\n            throw PacketParsingError.invalidPacketCode\n        }\n        self = code\n    }\n}\n\npublic enum PacketParsingError: Error {\n    case notEnoughData\n    case invalidPacketCode\n}\n\npublic struct Header {\n    public let code: PacketCode\n\n    public static let length = 1\n\n    public init(code: PacketCode) {\n        self.code = code\n    }\n}\n\npublic enum Body {\n    public struct ClientAuthRequest: Codable {\n        public let login: String\n        public let password: String\n\n        public init(login: String, password: String) {\n            self.login = login\n            self.password = password\n        }\n    }\n\n    public struct ServerAuthResponse: Codable {\n        public let isOK: Bool\n\n        public init(isOK: Bool) {\n            self.isOK = isOK\n        }\n    }\n\n    public typealias Data = Foundation.Data\n}\n\n// MARK: - Encoder\n\npublic enum MessageEncoder {\n    public static func encode<Body: Codable>(header: Header, body: Body, key: SymmetricKey) throws -> Data {\n        try encode(header: header, body: JSONEncoder().encode(body), key: key)\n    }\n\n    public static func encode(header: Header, body: Data, key: SymmetricKey) throws -> Data {\n        var data = Data()\n\n        // Header\n        data.append(header.code.rawValue)\n\n        // Body\n        let body = try Cipher.encrypt(body, key: key)\n        data.append(body)\n\n        return data\n    }\n}\n\npublic enum MessageDecoder {\n    /// Decrypts and decodes the body of the given datagram.\n    public static func decode<T: Decodable>(_ type: T.Type, datagram: Data, key: SymmetricKey) throws -> T {\n        let data = try Cipher.decrypt(datagram[Header.length...], key: key)\n        return try JSONDecoder().decode(type, from: data)\n    }\n}\n"
  },
  {
    "path": "vpn-protocol/Session.swift",
    "content": "// The MIT License (MIT)\n//\n// Copyright (c) 2020 Alexander Grebenyuk (github.com/kean).\n\nimport Foundation\nimport CryptoKit\n\n// WARNING: This is a simplified example, don't use it as a reference.\npublic final class Cipher {\n    private let key: SymmetricKey\n\n    public init(key: SymmetricKey) {\n        self.key = key\n    }\n\n    // WARNING: This is a simplified example, don't use it as a reference.\n    public func encrypt(_ data: Data) throws -> Data {\n        try ChaChaPoly.seal(data, using: key).combined\n    }\n\n    // WARNING: This is a simplified example, don't use it as a reference.\n    public func decrypt(_ data: Data) throws -> Data {\n        try ChaChaPoly.open(ChaChaPoly.SealedBox(combined: data), using: key)\n    }\n}\n"
  },
  {
    "path": "vpn-server/main.swift",
    "content": "// The MIT License (MIT)\n//\n// Copyright (c) 2020 Alexander Grebenyuk (github.com/kean).\n\nimport Foundation\nimport NIO\nimport BestVPN\n\nprivate final class VPNDatagramHandler: ChannelInboundHandler {\n    public typealias InboundIn = AddressedEnvelope<ByteBuffer>\n    public typealias OutboundOut = AddressedEnvelope<ByteBuffer>\n\n    public func channelRead(context: ChannelHandlerContext, data: NIOAny) {\n        let inputEnvelope = unwrapInboundIn(data)\n        let inputData = Data(inputEnvelope.data.readableBytesView) // TODO: this probably isn't optimal\n        do {\n            let code = try PacketCode(datagram: inputData)\n\n            switch code {\n            case .clientAuthRequest:\n                let outputData = try MessageEncoder.encode(\n                    header: Header(code: .serverAuthResponse), body: Body.ServerAuthResponse(isOK: true), key: Cipher.key\n                )\n\n                var buffer = context.channel.allocator.buffer(capacity: outputData.count)\n                buffer.writeBytes(outputData)\n\n                let outputEnvelope = AddressedEnvelope(remoteAddress: inputEnvelope.remoteAddress, data: buffer)\n                context.write(wrapOutboundOut(outputEnvelope), promise: nil)\n\n            case .data:\n                // TODO: Inject packets into a virtual interface\n                break\n            default:\n                break\n            }\n        } catch {\n            // TODO: Handle errors\n        }\n    }\n\n    public func channelReadComplete(context: ChannelHandlerContext) {\n        // As we are not really interested getting notified on success or failure we just pass nil as promise to\n        // reduce allocations.\n        context.flush()\n    }\n\n    public func errorCaught(context: ChannelHandlerContext, error: Error) {\n        print(\"error: \", error)\n\n        // As we are not really interested getting notified on success or failure we just pass nil as promise to\n        // reduce allocations.\n        context.close(promise: nil)\n    }\n}\n\n// We don't need more than one thread, as we're creating only one datagram channel.\nlet group = MultiThreadedEventLoopGroup(numberOfThreads: 1)\nvar bootstrap = DatagramBootstrap(group: group)\n    // Specify backlog and enable SO_REUSEADDR\n    .channelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)\n\n    // Set the handlers that are applied to the bound channel\n    .channelInitializer { channel in\n        // Ensure we don't read faster than we can write by adding the BackPressureHandler into the pipeline.\n        channel.pipeline.addHandler(VPNDatagramHandler())\n    }\n\ndefer {\n    try! group.syncShutdownGracefully()\n}\n\nvar arguments = CommandLine.arguments.dropFirst(0) // just to get an ArraySlice<String> from [String]\nif arguments.dropFirst().first == .some(\"--enable-gathering-reads\") {\n    bootstrap = bootstrap.channelOption(ChannelOptions.datagramVectorReadMessageCount, value: 30)\n    bootstrap = bootstrap.channelOption(ChannelOptions.recvAllocator, value: FixedSizeRecvByteBufferAllocator(capacity: 30 * 2048))\n    arguments = arguments.dropFirst()\n}\nlet arg1 = arguments.dropFirst().first\nlet arg2 = arguments.dropFirst().dropFirst().first\n\n#warning(\"TEMP:\")\n//let defaultHost = \"::1\"\nlet defaultHost = \"192.168.0.13\"\nlet defaultPort = 9999\n\nenum BindTo {\n    case ip(host: String, port: Int)\n    case unixDomainSocket(path: String)\n}\n\nlet bindTarget: BindTo\nswitch (arg1, arg1.flatMap(Int.init), arg2.flatMap(Int.init)) {\ncase (.some(let h), _ , .some(let p)):\n    /* we got two arguments, let's interpret that as host and port */\n    bindTarget = .ip(host: h, port: p)\ncase (.some(let portString), .none, _):\n    /* couldn't parse as number, expecting unix domain socket path */\n    bindTarget = .unixDomainSocket(path: portString)\ncase (_, .some(let p), _):\n    /* only one argument --> port */\n    bindTarget = .ip(host: defaultHost, port: p)\ndefault:\n    bindTarget = .ip(host: defaultHost, port: defaultPort)\n}\n\nlet channel = try { () -> Channel in\n    switch bindTarget {\n    case .ip(let host, let port):\n        return try bootstrap.bind(host: host, port: port).wait()\n    case .unixDomainSocket(let path):\n        return try bootstrap.bind(unixDomainSocketPath: path).wait()\n    }\n}()\n\nprint(\"Server started and listening on \\(channel.localAddress!)\")\n\n// This will never unblock as we don't close the channel\ntry channel.closeFuture.wait()\n\nprint(\"Server closed\")\n\n"
  },
  {
    "path": "vpn-tunnel/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>vpn-tunnel</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>NSExtension</key>\n\t<dict>\n\t\t<key>NSExtensionPointIdentifier</key>\n\t\t<string>com.apple.networkextension.packet-tunnel</string>\n\t\t<key>NSExtensionPrincipalClass</key>\n\t\t<string>$(PRODUCT_MODULE_NAME).PacketTunnelProvider</string>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "vpn-tunnel/PacketTunnelProvider.swift",
    "content": "// The MIT License (MIT)\n//\n// Copyright (c) 2020 Alexander Grebenyuk (github.com/kean).\n\nimport NetworkExtension\nimport BestVPN\nimport CryptoKit\nimport os.log\n\nclass PacketTunnelProvider: NEPacketTunnelProvider {\n\n    private var configuration: Configuration!\n    private var udpSession: NWUDPSession!\n    private var key: SymmetricKey!\n    private var observer: AnyObject?\n    #warning(\"TODO: do we need this queue?\")\n    private let queue = DispatchQueue(label: \"com.github.packet-tunnel-provider\")\n    private let log = OSLog(subsystem: \"vpn-tunnel-ptp\", category: \"default\")\n    private var pendingCompletion: ((Error?) -> Void)?\n    private weak var timeoutTimer: Timer?\n\n    override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {\n        os_log(.default, log: log, \"Starting tunnel, options: %{private}@\", \"\\(String(describing: options))\")\n\n        do {\n            guard let proto = protocolConfiguration as? NETunnelProviderProtocol else {\n                throw NEVPNError(.configurationInvalid)\n            }\n            self.configuration = try Configuration(proto: proto)\n        } catch {\n            os_log(.error, log: log, \"Failed to read the configuration\", error.localizedDescription)\n            completionHandler(error)\n        }\n\n        os_log(.default, log: log, \"Read configuration %{private}@\", \"\\(String(describing: configuration))\")\n\n        // \"Get\" a pre-shared symmetric key.\n        //\n        // WARNING: Don't do this in production! This code uses the same key\n        // every time for simplicity. In practice, you are going to want to\n        // either pre-share it properly, or implement proper TLS handshake.\n        self.key = Cipher.key\n\n        // Remember the completion handler so that we could call it when the\n        // the connection with the server is established.\n        //\n        // When the Packet Tunnel Provider executes the completionHandler block\n        // with a nil error parameter, it signals to the system that it is ready\n        // to begin handling network data. Therefore, the Packet Tunnel Provider\n        // should call `setTunnelNetworkSettings(_:completionHandler:)` and wait\n        // for it to complete before executing the completionHandler block.\n        //\n        // The domain and code of the NSError object passed to the completionHandler\n        // block are defined by the Packet Tunnel Provider (`NEVPNError`).\n        self.pendingCompletion = completionHandler\n\n        self.startTunnel()\n    }\n\n    private func startTunnel() {\n        self.startUDPSession()\n\n        self.timeoutTimer = Timer.scheduledTimer(withTimeInterval: 10, repeats: false) { [weak self] _ in\n            guard let self = self else { return }\n\n            self.pendingCompletion?(NEVPNError(.connectionFailed))\n            self.pendingCompletion = nil\n        }\n    }\n\n    private func startUDPSession() {\n        os_log(.default, log: log, \"Starting UDP session, hostname: %{public}@, port: %{public}@\", configuration.hostname, configuration.port)\n\n        let endpoint = NWHostEndpoint(hostname: configuration.hostname, port: configuration.port)\n        self.udpSession = createUDPSession(to: endpoint, from: nil)\n        self.observer = udpSession.observe(\\.state, options: [.new]) { [weak self] session, _ in\n            guard let self = self else { return }\n            os_log(.default, log: self.log, \"Session did update state: %{public}@\", session.state.description)\n            self.queue.async {\n                self.udpSession(session, didUpdateState: session.state)\n            }\n        }\n    }\n\n    private func udpSession(_ session: NWUDPSession, didUpdateState state: NWUDPSessionState) {\n        switch state {\n        case .ready:\n            guard pendingCompletion != nil else { return }\n\n            session.setReadHandler({ [weak self] datagrams, error in\n                guard let self = self else { return }\n                self.queue.async {\n                    self.didReceiveDatagrams(datagrams: datagrams ?? [], error: error)\n                }\n            }, maxDatagrams: Int.max)\n\n            do {\n                try self.authenticate(username: configuration.username, password: configuration.password)\n            } catch {\n                // TODO: handle errors\n                os_log(.default, log: self.log, \"Did fail to authenticate: %{public}@\", \"\\(error)\")\n            }\n        case .failed:\n            guard pendingCompletion != nil else { return }\n            pendingCompletion?(NEVPNError(.connectionFailed))\n            pendingCompletion = nil\n        default:\n            break\n        }\n    }\n\n    private func didReceiveDatagrams(datagrams: [Data], error: Error?) {\n        for datagram in datagrams {\n            do {\n                try self.didReceiveDatagram(datagram: datagram)\n            } catch {\n                // TODO: handle error\n                os_log(.default, log: self.log, \"UDP session read handler error: %{public}@\", \"\\(error)\")\n            }\n        }\n        if let error = error {\n            // TODO: handle error\n            os_log(.default, log: self.log, \"UDP session read handler error: %{public}@\", \"\\(error)\")\n        }\n    }\n\n    private func didReceiveDatagram(datagram: Data) throws {\n        let code = try PacketCode(datagram: datagram)\n\n        os_log(.default, log: self.log, \"Did receive datagram with code: %{public}@\", \"\\(code)\")\n\n        switch code {\n        case .serverAuthResponse:\n            let response = try MessageDecoder.decode(Body.ServerAuthResponse.self, datagram: datagram, key: key)\n            os_log(.default, log: self.log, \"Did receive auth response: %{private}@\", \"\\(response)\")\n            if response.isOK {\n                // TODO: In reality, you would pass a resolved IP address, in our\n                // case we already provide an IP address in the configurtaion\n                self.didSetupTunnel(address: configuration.hostname)\n            } else {\n                // TODO: Handle error\n            }\n            self.timeoutTimer?.invalidate()\n        case .data:\n            let data = try MessageDecoder.decode(Data.self, datagram: datagram, key: key)\n            let proto = protocolNumber(for: data)\n            self.packetFlow.writePackets([data], withProtocols: [proto])\n        default:\n            break\n        }\n    }\n\n    private func didSetupTunnel(address: String) {\n        os_log(.default, log: self.log, \"Did setup tunnel with address: %{public}@\", \"\\(address)\")\n\n        let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: address)\n        // TODO: Configure DNS/split-tunnel/etc settings if needed\n\n        setTunnelNetworkSettings(settings) { error in\n            os_log(.default, log: self.log, \"Did setup tunnel settings: %{public}@, error: %{public}@\", \"\\(settings)\", \"\\(String(describing: error))\")\n\n            self.pendingCompletion?(error)\n            self.pendingCompletion = nil\n\n            self.didStartTunnel()\n        }\n    }\n\n    private func authenticate(username: String, password: String) throws {\n        let datagram = try MessageEncoder.encode(\n            header: Header(code: .clientAuthRequest),\n            body: Body.ClientAuthRequest(login: username, password: password),\n            key: key\n        )\n\n        udpSession.writeDatagram(datagram) { error in\n            if let error = error {\n                // TODO: Handle errors\n                os_log(.default, log: self.log, \"Failed to write auth request datagram, error: %{public}@\", \"\\(error)\")\n            }\n        }\n    }\n\n    private func didStartTunnel() {\n        readPackets()\n    }\n\n    private func readPackets() {\n        packetFlow.readPacketObjects { packets in\n            do {\n                let datagrams = try packets.map {\n                    try MessageEncoder.encode(\n                        header: Header(code: .data),\n                        body: $0.data,\n                        key: key\n                    )\n                }\n                self.session.writeMultipleDatagrams(datagrams) { error in\n                    // TODO: Handle errors\n                }\n            } catch {\n                // TODO: Handle errors\n            }\n\n            self.readPackets()\n        }\n    }\n\n    override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {\n        // Add code here to start the process of stopping the tunnel.\n        completionHandler()\n    }\n    \n    override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {\n        // Add code here to handle the message.\n        if let handler = completionHandler {\n            handler(messageData)\n        }\n    }\n    \n    override func sleep(completionHandler: @escaping () -> Void) {\n        // Add code here to get ready to sleep.\n        completionHandler()\n    }\n    \n    override func wake() {\n        // Add code here to wake up.\n    }\n}\n\nprivate struct Configuration {\n    let username: String\n    let password: String\n    let hostname: String\n    let port: String\n\n    init(proto: NETunnelProviderProtocol) throws {\n        guard let fullServerAddress = proto.serverAddress else {\n            throw NEVPNError(.configurationInvalid)\n        }\n        let serverAddressParts = fullServerAddress.split(separator: \":\")\n        guard serverAddressParts.count == 2 else {\n            throw NEVPNError(.configurationInvalid)\n        }\n\n        self.hostname = String(serverAddressParts[0])\n        self.port = String(serverAddressParts[1])\n\n        guard let username = proto.username else {\n            throw NEVPNError(.configurationInvalid)\n        }\n        self.username = username\n\n        guard let password = proto.passwordReference.flatMap({\n            Keychain.password(for: username, reference: $0)\n        }) else {\n            throw NEVPNError(.configurationInvalid)\n        }\n        self.password = password\n    }\n}\n\nextension NWUDPSessionState: CustomStringConvertible {\n    public var description: String {\n        switch self {\n        case .cancelled: return \".cancelled\"\n        case .failed: return \".failed\"\n        case .invalid: return \".invalid\"\n        case .preparing: return \".preparing\"\n        case .ready: return \".ready\"\n        case .waiting: return \".waiting\"\n        @unknown default: return \"unknown\"\n        }\n    }\n}\n\nprivate func protocolNumber(for packet: Data) -> NSNumber {\n    guard !packet.isEmpty else {\n        return AF_INET as NSNumber\n    }\n\n    // 'packet' contains the decrypted incoming IP packet data\n\n    // The first 4 bits identify the IP version\n    let ipVersion = (packet[0] & 0xf0) >> 4\n    return (ipVersion == 6) ? AF_INET6 as NSNumber : AF_INET as NSNumber\n}\n"
  },
  {
    "path": "vpn-tunnel/vpn_tunnel.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.developer.networking.networkextension</key>\n\t<array>\n\t\t<string>packet-tunnel-provider</string>\n\t</array>\n\t<key>com.apple.security.application-groups</key>\n\t<array>\n\t\t<string>group.com.github.kean.vpn-client</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "vpn.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 52;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t0C189C482479D399000EE6B3 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C189C432479D280000EE6B3 /* main.swift */; };\n\t\t0C230CDA24884C35005FEEBD /* libBestVPN.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CD38AF92486C12E00DB2626 /* libBestVPN.a */; };\n\t\t0C34DF93248D50E500FBBD11 /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C34DF92248D50E500FBBD11 /* Cipher.swift */; };\n\t\t0C3C1B5F247039EB00571084 /* VPNConfigurationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C3C1B5E247039EB00571084 /* VPNConfigurationService.swift */; };\n\t\t0C3C1B6124703B5E00571084 /* TunnelDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C3C1B6024703B5E00571084 /* TunnelDetailsView.swift */; };\n\t\t0C3C1B6524703D8600571084 /* PrimaryButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C3C1B6424703D8600571084 /* PrimaryButton.swift */; };\n\t\t0C3C1B692470404A00571084 /* Spinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C3C1B682470404A00571084 /* Spinner.swift */; };\n\t\t0C405BED2466FBFE00EB0786 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C405BEC2466FBFE00EB0786 /* AppDelegate.swift */; };\n\t\t0C405BEF2466FBFE00EB0786 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C405BEE2466FBFE00EB0786 /* SceneDelegate.swift */; };\n\t\t0C405BF12466FBFE00EB0786 /* RouterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C405BF02466FBFE00EB0786 /* RouterView.swift */; };\n\t\t0C405BF32466FC0000EB0786 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0C405BF22466FC0000EB0786 /* Assets.xcassets */; };\n\t\t0C405BF62466FC0000EB0786 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0C405BF52466FC0000EB0786 /* Preview Assets.xcassets */; };\n\t\t0C405BF92466FC0000EB0786 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0C405BF72466FC0000EB0786 /* LaunchScreen.storyboard */; };\n\t\t0C571CBA247050E5006B2931 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C571CB9247050E5006B2931 /* NetworkExtension.framework */; };\n\t\t0C571CBC24705809006B2931 /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C571CBB24705809006B2931 /* SplashView.swift */; };\n\t\t0C571CC42470B4D9006B2931 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C571CB9247050E5006B2931 /* NetworkExtension.framework */; };\n\t\t0C5F7022248DA579000297AB /* libBestVPN.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CD38AF92486C12E00DB2626 /* libBestVPN.a */; };\n\t\t0CA5FEBD2491B4B400C71D25 /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA5FEBC2491B4B400C71D25 /* Keychain.swift */; };\n\t\t0CA5FEBE2491B4B400C71D25 /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA5FEBC2491B4B400C71D25 /* Keychain.swift */; };\n\t\t0CA5FEC12491B72E00C71D25 /* TunnelDetailsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA5FEC02491B72E00C71D25 /* TunnelDetailsViewModel.swift */; };\n\t\t0CAE93DD246F4927007B2E95 /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CAE93DC246F4927007B2E95 /* PacketTunnelProvider.swift */; };\n\t\t0CAE93E2246F4927007B2E95 /* vpn-tunnel.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 0CAE93DA246F4927007B2E95 /* vpn-tunnel.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };\n\t\t0CAE940724702557007B2E95 /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CAE940624702557007B2E95 /* WelcomeView.swift */; };\n\t\t0CD38AFC2486C12E00DB2626 /* Packet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CD38AFB2486C12E00DB2626 /* Packet.swift */; };\n\t\t0CD38B06248735A700DB2626 /* NIO in Frameworks */ = {isa = PBXBuildFile; productRef = 0CD38B05248735A700DB2626 /* NIO */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t0C230CDB24884C35005FEEBD /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 0C405BE12466FBFE00EB0786 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 0CD38AF82486C12E00DB2626;\n\t\t\tremoteInfo = \"vpn-protocol\";\n\t\t};\n\t\t0C5F7023248DA579000297AB /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 0C405BE12466FBFE00EB0786 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 0CD38AF82486C12E00DB2626;\n\t\t\tremoteInfo = \"vpn-protocol\";\n\t\t};\n\t\t0CAE93E0246F4927007B2E95 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 0C405BE12466FBFE00EB0786 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 0CAE93D9246F4927007B2E95;\n\t\t\tremoteInfo = \"vpn-tunnel\";\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t0C189C3F2479D280000EE6B3 /* CopyFiles */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = /usr/share/man/man1/;\n\t\t\tdstSubfolderSpec = 0;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 1;\n\t\t};\n\t\t0CAE93D5246F4906007B2E95 /* Embed App Extensions */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 13;\n\t\t\tfiles = (\n\t\t\t\t0CAE93E2246F4927007B2E95 /* vpn-tunnel.appex in Embed App Extensions */,\n\t\t\t);\n\t\t\tname = \"Embed App Extensions\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t0CD38AF72486C12E00DB2626 /* CopyFiles */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"include/$(PRODUCT_NAME)\";\n\t\t\tdstSubfolderSpec = 16;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t0C189C412479D280000EE6B3 /* vpn-server */ = {isa = PBXFileReference; explicitFileType = \"compiled.mach-o.executable\"; includeInIndex = 0; path = \"vpn-server\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t0C189C432479D280000EE6B3 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = main.swift; path = \"vpn-server/main.swift\"; sourceTree = SOURCE_ROOT; };\n\t\t0C34DF92248D50E500FBBD11 /* Cipher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cipher.swift; sourceTree = \"<group>\"; };\n\t\t0C3C1B5D24702E1C00571084 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = \"<group>\"; };\n\t\t0C3C1B5E247039EB00571084 /* VPNConfigurationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNConfigurationService.swift; sourceTree = \"<group>\"; };\n\t\t0C3C1B6024703B5E00571084 /* TunnelDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelDetailsView.swift; sourceTree = \"<group>\"; };\n\t\t0C3C1B6424703D8600571084 /* PrimaryButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrimaryButton.swift; sourceTree = \"<group>\"; };\n\t\t0C3C1B682470404A00571084 /* Spinner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Spinner.swift; sourceTree = \"<group>\"; };\n\t\t0C405BE92466FBFE00EB0786 /* vpn-client.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = \"vpn-client.app\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t0C405BEC2466FBFE00EB0786 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\t0C405BEE2466FBFE00EB0786 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = \"<group>\"; };\n\t\t0C405BF02466FBFE00EB0786 /* RouterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouterView.swift; sourceTree = \"<group>\"; };\n\t\t0C405BF22466FC0000EB0786 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t0C405BF52466FC0000EB0786 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = \"Preview Assets.xcassets\"; sourceTree = \"<group>\"; };\n\t\t0C405BF82466FC0000EB0786 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\t0C405BFA2466FC0000EB0786 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t0C571CB7247050E5006B2931 /* vpn-client.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = \"vpn-client.entitlements\"; sourceTree = \"<group>\"; };\n\t\t0C571CB9247050E5006B2931 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; };\n\t\t0C571CBB24705809006B2931 /* SplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashView.swift; sourceTree = \"<group>\"; };\n\t\t0C571CC22470B343006B2931 /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = \"sourcecode.text-based-dylib-definition\"; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; };\n\t\t0CA5FEBC2491B4B400C71D25 /* Keychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keychain.swift; sourceTree = \"<group>\"; };\n\t\t0CA5FEC02491B72E00C71D25 /* TunnelDetailsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelDetailsViewModel.swift; sourceTree = \"<group>\"; };\n\t\t0CAE93DA246F4927007B2E95 /* vpn-tunnel.appex */ = {isa = PBXFileReference; explicitFileType = \"wrapper.app-extension\"; includeInIndex = 0; path = \"vpn-tunnel.appex\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t0CAE93DC246F4927007B2E95 /* PacketTunnelProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelProvider.swift; sourceTree = \"<group>\"; };\n\t\t0CAE93DE246F4927007B2E95 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t0CAE93DF246F4927007B2E95 /* vpn_tunnel.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = vpn_tunnel.entitlements; sourceTree = \"<group>\"; };\n\t\t0CAE940624702557007B2E95 /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = \"<group>\"; };\n\t\t0CD38AF92486C12E00DB2626 /* libBestVPN.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libBestVPN.a; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t0CD38AFB2486C12E00DB2626 /* Packet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Packet.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t0C189C3E2479D280000EE6B3 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0C5F7022248DA579000297AB /* libBestVPN.a in Frameworks */,\n\t\t\t\t0CD38B06248735A700DB2626 /* NIO in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t0C405BE62466FBFE00EB0786 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0C571CBA247050E5006B2931 /* NetworkExtension.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t0CAE93D7246F4927007B2E95 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0C230CDA24884C35005FEEBD /* libBestVPN.a in Frameworks */,\n\t\t\t\t0C571CC42470B4D9006B2931 /* NetworkExtension.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t0CD38AF62486C12E00DB2626 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t0C189C422479D280000EE6B3 /* vpn-server */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0C189C432479D280000EE6B3 /* main.swift */,\n\t\t\t);\n\t\t\tpath = \"vpn-server\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0C3C1B662470403600571084 /* Screens */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0CA5FEBF2491B71F00C71D25 /* TunnelDetails */,\n\t\t\t\t0CAE940624702557007B2E95 /* WelcomeView.swift */,\n\t\t\t\t0C405BF02466FBFE00EB0786 /* RouterView.swift */,\n\t\t\t\t0C3C1B6424703D8600571084 /* PrimaryButton.swift */,\n\t\t\t\t0C3C1B682470404A00571084 /* Spinner.swift */,\n\t\t\t\t0C571CBB24705809006B2931 /* SplashView.swift */,\n\t\t\t);\n\t\t\tpath = Screens;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0C3C1B672470403C00571084 /* Services */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0C3C1B5E247039EB00571084 /* VPNConfigurationService.swift */,\n\t\t\t\t0CA5FEBC2491B4B400C71D25 /* Keychain.swift */,\n\t\t\t);\n\t\t\tpath = Services;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0C405BE02466FBFE00EB0786 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0C3C1B5D24702E1C00571084 /* README.md */,\n\t\t\t\t0C405BEB2466FBFE00EB0786 /* vpn-client */,\n\t\t\t\t0CAE93DB246F4927007B2E95 /* vpn-tunnel */,\n\t\t\t\t0C189C422479D280000EE6B3 /* vpn-server */,\n\t\t\t\t0CD38AFA2486C12E00DB2626 /* vpn-protocol */,\n\t\t\t\t0C405BEA2466FBFE00EB0786 /* Products */,\n\t\t\t\t0C571CB8247050E5006B2931 /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0C405BEA2466FBFE00EB0786 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0C405BE92466FBFE00EB0786 /* vpn-client.app */,\n\t\t\t\t0CAE93DA246F4927007B2E95 /* vpn-tunnel.appex */,\n\t\t\t\t0C189C412479D280000EE6B3 /* vpn-server */,\n\t\t\t\t0CD38AF92486C12E00DB2626 /* libBestVPN.a */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0C405BEB2466FBFE00EB0786 /* vpn-client */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0C571CB7247050E5006B2931 /* vpn-client.entitlements */,\n\t\t\t\t0C405BEC2466FBFE00EB0786 /* AppDelegate.swift */,\n\t\t\t\t0C405BEE2466FBFE00EB0786 /* SceneDelegate.swift */,\n\t\t\t\t0C3C1B672470403C00571084 /* Services */,\n\t\t\t\t0C3C1B662470403600571084 /* Screens */,\n\t\t\t\t0C405BF22466FC0000EB0786 /* Assets.xcassets */,\n\t\t\t\t0C405BF72466FC0000EB0786 /* LaunchScreen.storyboard */,\n\t\t\t\t0C405BFA2466FC0000EB0786 /* Info.plist */,\n\t\t\t\t0C405BF42466FC0000EB0786 /* Preview Content */,\n\t\t\t);\n\t\t\tpath = \"vpn-client\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0C405BF42466FC0000EB0786 /* Preview Content */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0C405BF52466FC0000EB0786 /* Preview Assets.xcassets */,\n\t\t\t);\n\t\t\tpath = \"Preview Content\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0C571CB8247050E5006B2931 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0C571CC22470B343006B2931 /* libresolv.tbd */,\n\t\t\t\t0C571CB9247050E5006B2931 /* NetworkExtension.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0CA5FEBF2491B71F00C71D25 /* TunnelDetails */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0C3C1B6024703B5E00571084 /* TunnelDetailsView.swift */,\n\t\t\t\t0CA5FEC02491B72E00C71D25 /* TunnelDetailsViewModel.swift */,\n\t\t\t);\n\t\t\tpath = TunnelDetails;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0CAE93DB246F4927007B2E95 /* vpn-tunnel */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0CAE93DC246F4927007B2E95 /* PacketTunnelProvider.swift */,\n\t\t\t\t0CAE93DE246F4927007B2E95 /* Info.plist */,\n\t\t\t\t0CAE93DF246F4927007B2E95 /* vpn_tunnel.entitlements */,\n\t\t\t);\n\t\t\tpath = \"vpn-tunnel\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t0CD38AFA2486C12E00DB2626 /* vpn-protocol */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0CD38AFB2486C12E00DB2626 /* Packet.swift */,\n\t\t\t\t0C34DF92248D50E500FBBD11 /* Cipher.swift */,\n\t\t\t);\n\t\t\tpath = \"vpn-protocol\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t0C189C402479D280000EE6B3 /* vpn-server */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 0C189C452479D280000EE6B3 /* Build configuration list for PBXNativeTarget \"vpn-server\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t0C189C3D2479D280000EE6B3 /* Sources */,\n\t\t\t\t0C189C3E2479D280000EE6B3 /* Frameworks */,\n\t\t\t\t0C189C3F2479D280000EE6B3 /* CopyFiles */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t0C5F7024248DA579000297AB /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = \"vpn-server\";\n\t\t\tpackageProductDependencies = (\n\t\t\t\t0CD38B05248735A700DB2626 /* NIO */,\n\t\t\t);\n\t\t\tproductName = \"vpn-server\";\n\t\t\tproductReference = 0C189C412479D280000EE6B3 /* vpn-server */;\n\t\t\tproductType = \"com.apple.product-type.tool\";\n\t\t};\n\t\t0C405BE82466FBFE00EB0786 /* vpn-client */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 0C405BFD2466FC0100EB0786 /* Build configuration list for PBXNativeTarget \"vpn-client\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t0C405BE52466FBFE00EB0786 /* Sources */,\n\t\t\t\t0C405BE62466FBFE00EB0786 /* Frameworks */,\n\t\t\t\t0C405BE72466FBFE00EB0786 /* Resources */,\n\t\t\t\t0CAE93D5246F4906007B2E95 /* Embed App Extensions */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t0CAE93E1246F4927007B2E95 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = \"vpn-client\";\n\t\t\tproductName = VPNClient;\n\t\t\tproductReference = 0C405BE92466FBFE00EB0786 /* vpn-client.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\t0CAE93D9246F4927007B2E95 /* vpn-tunnel */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 0CAE93E3246F4927007B2E95 /* Build configuration list for PBXNativeTarget \"vpn-tunnel\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t0CAE93D6246F4927007B2E95 /* Sources */,\n\t\t\t\t0CAE93D7246F4927007B2E95 /* Frameworks */,\n\t\t\t\t0CAE93D8246F4927007B2E95 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t0C230CDC24884C35005FEEBD /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = \"vpn-tunnel\";\n\t\t\tproductName = \"vpn-tunnel\";\n\t\t\tproductReference = 0CAE93DA246F4927007B2E95 /* vpn-tunnel.appex */;\n\t\t\tproductType = \"com.apple.product-type.app-extension\";\n\t\t};\n\t\t0CD38AF82486C12E00DB2626 /* vpn-protocol */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 0CD38AFD2486C12E00DB2626 /* Build configuration list for PBXNativeTarget \"vpn-protocol\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t0CD38AF52486C12E00DB2626 /* Sources */,\n\t\t\t\t0CD38AF62486C12E00DB2626 /* Frameworks */,\n\t\t\t\t0CD38AF72486C12E00DB2626 /* CopyFiles */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"vpn-protocol\";\n\t\t\tproductName = \"vpn-protocol\";\n\t\t\tproductReference = 0CD38AF92486C12E00DB2626 /* libBestVPN.a */;\n\t\t\tproductType = \"com.apple.product-type.library.static\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t0C405BE12466FBFE00EB0786 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 1150;\n\t\t\t\tLastUpgradeCheck = 1140;\n\t\t\t\tORGANIZATIONNAME = kean;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t0C189C402479D280000EE6B3 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 11.5;\n\t\t\t\t\t};\n\t\t\t\t\t0C405BE82466FBFE00EB0786 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 11.4.1;\n\t\t\t\t\t};\n\t\t\t\t\t0CAE93D9246F4927007B2E95 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 11.4.1;\n\t\t\t\t\t};\n\t\t\t\t\t0CD38AF82486C12E00DB2626 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 11.5;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 0C405BE42466FBFE00EB0786 /* Build configuration list for PBXProject \"vpn\" */;\n\t\t\tcompatibilityVersion = \"Xcode 9.3\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 0C405BE02466FBFE00EB0786;\n\t\t\tpackageReferences = (\n\t\t\t\t0CD38B04248735A700DB2626 /* XCRemoteSwiftPackageReference \"swift-nio\" */,\n\t\t\t);\n\t\t\tproductRefGroup = 0C405BEA2466FBFE00EB0786 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t0C405BE82466FBFE00EB0786 /* vpn-client */,\n\t\t\t\t0CAE93D9246F4927007B2E95 /* vpn-tunnel */,\n\t\t\t\t0C189C402479D280000EE6B3 /* vpn-server */,\n\t\t\t\t0CD38AF82486C12E00DB2626 /* vpn-protocol */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t0C405BE72466FBFE00EB0786 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0C405BF92466FC0000EB0786 /* LaunchScreen.storyboard in Resources */,\n\t\t\t\t0C405BF62466FC0000EB0786 /* Preview Assets.xcassets in Resources */,\n\t\t\t\t0C405BF32466FC0000EB0786 /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t0CAE93D8246F4927007B2E95 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t0C189C3D2479D280000EE6B3 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0C189C482479D399000EE6B3 /* main.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t0C405BE52466FBFE00EB0786 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0C405BED2466FBFE00EB0786 /* AppDelegate.swift in Sources */,\n\t\t\t\t0C405BEF2466FBFE00EB0786 /* SceneDelegate.swift in Sources */,\n\t\t\t\t0C3C1B6124703B5E00571084 /* TunnelDetailsView.swift in Sources */,\n\t\t\t\t0CA5FEC12491B72E00C71D25 /* TunnelDetailsViewModel.swift in Sources */,\n\t\t\t\t0C3C1B5F247039EB00571084 /* VPNConfigurationService.swift in Sources */,\n\t\t\t\t0C405BF12466FBFE00EB0786 /* RouterView.swift in Sources */,\n\t\t\t\t0CAE940724702557007B2E95 /* WelcomeView.swift in Sources */,\n\t\t\t\t0C3C1B6524703D8600571084 /* PrimaryButton.swift in Sources */,\n\t\t\t\t0C3C1B692470404A00571084 /* Spinner.swift in Sources */,\n\t\t\t\t0C571CBC24705809006B2931 /* SplashView.swift in Sources */,\n\t\t\t\t0CA5FEBD2491B4B400C71D25 /* Keychain.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t0CAE93D6246F4927007B2E95 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0CAE93DD246F4927007B2E95 /* PacketTunnelProvider.swift in Sources */,\n\t\t\t\t0CA5FEBE2491B4B400C71D25 /* Keychain.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t0CD38AF52486C12E00DB2626 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0C34DF93248D50E500FBBD11 /* Cipher.swift in Sources */,\n\t\t\t\t0CD38AFC2486C12E00DB2626 /* Packet.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t0C230CDC24884C35005FEEBD /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 0CD38AF82486C12E00DB2626 /* vpn-protocol */;\n\t\t\ttargetProxy = 0C230CDB24884C35005FEEBD /* PBXContainerItemProxy */;\n\t\t};\n\t\t0C5F7024248DA579000297AB /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 0CD38AF82486C12E00DB2626 /* vpn-protocol */;\n\t\t\ttargetProxy = 0C5F7023248DA579000297AB /* PBXContainerItemProxy */;\n\t\t};\n\t\t0CAE93E1246F4927007B2E95 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 0CAE93D9246F4927007B2E95 /* vpn-tunnel */;\n\t\t\ttargetProxy = 0CAE93E0246F4927007B2E95 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\t0C405BF72466FC0000EB0786 /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t0C405BF82466FC0000EB0786 /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t0C189C462479D280000EE6B3 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.15;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t0C189C472479D280000EE6B3 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.15;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t0C405BFB2466FC0100EB0786 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t0C405BFC2466FC0100EB0786 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t0C405BFE2466FC0100EB0786 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = \"vpn-client/vpn-client.entitlements\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"vpn-client/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = NR8DLKJ7E6;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tINFOPLIST_FILE = \"vpn-client/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.github.kean.vpn-client\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t0C405BFF2466FC0100EB0786 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = \"vpn-client/vpn-client.entitlements\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"vpn-client/Preview Content\\\"\";\n\t\t\t\tDEVELOPMENT_TEAM = NR8DLKJ7E6;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tINFOPLIST_FILE = \"vpn-client/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.github.kean.vpn-client\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t0CAE93E4246F4927007B2E95 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = \"vpn-tunnel/vpn_tunnel.entitlements\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = NR8DLKJ7E6;\n\t\t\t\tINFOPLIST_FILE = \"vpn-tunnel/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@executable_path/../../Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.github.kean.vpn-client.vpn-tunnel\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t0CAE93E5246F4927007B2E95 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = \"vpn-tunnel/vpn_tunnel.entitlements\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = NR8DLKJ7E6;\n\t\t\t\tINFOPLIST_FILE = \"vpn-tunnel/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@executable_path/../../Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.github.kean.vpn-client.vpn-tunnel\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t0CD38AFE2486C12E00DB2626 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tOTHER_LDFLAGS = \"-ObjC\";\n\t\t\t\tPRODUCT_NAME = BestVPN;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSUPPORTED_PLATFORMS = \"iphonesimulator iphoneos macosx\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t0CD38AFF2486C12E00DB2626 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tOTHER_LDFLAGS = \"-ObjC\";\n\t\t\t\tPRODUCT_NAME = BestVPN;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSUPPORTED_PLATFORMS = \"iphonesimulator iphoneos macosx\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t0C189C452479D280000EE6B3 /* Build configuration list for PBXNativeTarget \"vpn-server\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t0C189C462479D280000EE6B3 /* Debug */,\n\t\t\t\t0C189C472479D280000EE6B3 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t0C405BE42466FBFE00EB0786 /* Build configuration list for PBXProject \"vpn\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t0C405BFB2466FC0100EB0786 /* Debug */,\n\t\t\t\t0C405BFC2466FC0100EB0786 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t0C405BFD2466FC0100EB0786 /* Build configuration list for PBXNativeTarget \"vpn-client\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t0C405BFE2466FC0100EB0786 /* Debug */,\n\t\t\t\t0C405BFF2466FC0100EB0786 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t0CAE93E3246F4927007B2E95 /* Build configuration list for PBXNativeTarget \"vpn-tunnel\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t0CAE93E4246F4927007B2E95 /* Debug */,\n\t\t\t\t0CAE93E5246F4927007B2E95 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t0CD38AFD2486C12E00DB2626 /* Build configuration list for PBXNativeTarget \"vpn-protocol\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t0CD38AFE2486C12E00DB2626 /* Debug */,\n\t\t\t\t0CD38AFF2486C12E00DB2626 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t0CD38B04248735A700DB2626 /* XCRemoteSwiftPackageReference \"swift-nio\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/apple/swift-nio\";\n\t\t\trequirement = {\n\t\t\t\tkind = upToNextMajorVersion;\n\t\t\t\tminimumVersion = 2.17.0;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t0CD38B05248735A700DB2626 /* NIO */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 0CD38B04248735A700DB2626 /* XCRemoteSwiftPackageReference \"swift-nio\" */;\n\t\t\tproductName = NIO;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 0C405BE12466FBFE00EB0786 /* Project object */;\n}\n"
  },
  {
    "path": "vpn.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "vpn.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "vpn.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved",
    "content": "{\n  \"object\": {\n    \"pins\": [\n      {\n        \"package\": \"swift-nio\",\n        \"repositoryURL\": \"https://github.com/apple/swift-nio\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"c5fa0b456524cd73dc3ddbb263d4f46c20b86ca3\",\n          \"version\": \"2.17.0\"\n        }\n      }\n    ]\n  },\n  \"version\": 1\n}\n"
  },
  {
    "path": "vpn.xcodeproj/xcshareddata/xcschemes/vpn-client.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1140\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"0C405BE82466FBFE00EB0786\"\n               BuildableName = \"vpn-client.app\"\n               BlueprintName = \"vpn-client\"\n               ReferencedContainer = \"container:vpn.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"0C405BE82466FBFE00EB0786\"\n            BuildableName = \"vpn-client.app\"\n            BlueprintName = \"vpn-client\"\n            ReferencedContainer = \"container:vpn.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"0C405BE82466FBFE00EB0786\"\n            BuildableName = \"vpn-client.app\"\n            BlueprintName = \"vpn-client\"\n            ReferencedContainer = \"container:vpn.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "vpn.xcodeproj/xcshareddata/xcschemes/vpn-tunnel.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1140\"\n   wasCreatedForAppExtension = \"YES\"\n   version = \"2.0\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"0CAE93D9246F4927007B2E95\"\n               BuildableName = \"vpn-tunnel.appex\"\n               BlueprintName = \"vpn-tunnel\"\n               ReferencedContainer = \"container:vpn.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"0C405BE82466FBFE00EB0786\"\n               BuildableName = \"vpn-client.app\"\n               BlueprintName = \"vpn-client\"\n               ReferencedContainer = \"container:vpn.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"\"\n      selectedLauncherIdentifier = \"Xcode.IDEFoundation.Launcher.PosixSpawn\"\n      launchStyle = \"0\"\n      askForAppToLaunch = \"Yes\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\"\n      launchAutomaticallySubstyle = \"2\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"0C405BE82466FBFE00EB0786\"\n            BuildableName = \"vpn-client.app\"\n            BlueprintName = \"vpn-client\"\n            ReferencedContainer = \"container:vpn.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      launchAutomaticallySubstyle = \"2\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"0C405BE82466FBFE00EB0786\"\n            BuildableName = \"vpn-client.app\"\n            BlueprintName = \"vpn-client\"\n            ReferencedContainer = \"container:vpn.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  }
]