Rewrite app in SwiftUI
2
.env.ios
|
@ -1,6 +1,6 @@
|
|||
APP_ROOT="Passepartout/App/iOS"
|
||||
MATCH_PLATFORM="ios"
|
||||
GYM_SCHEME="Passepartout-iOS"
|
||||
GYM_SCHEME="Passepartout"
|
||||
SCAN_DEVICE="iPhone 12"
|
||||
DELIVER_PLATFORM="ios"
|
||||
PILOT_PLATFORM="ios"
|
||||
|
|
8
.env.mac
|
@ -1,7 +1,9 @@
|
|||
APP_ROOT="Passepartout/App/macOS"
|
||||
MATCH_PLATFORM="macos"
|
||||
MATCH_PLATFORM="catalyst"
|
||||
MATCH_ADDITIONAL_CERT_TYPES="mac_installer_distribution"
|
||||
GYM_SCHEME="Passepartout-macOS"
|
||||
SCAN_DESTINATION="platform=macOS"
|
||||
GYM_SCHEME="Passepartout"
|
||||
|
||||
# not sure about these
|
||||
SCAN_DESTINATION="platform=iOS"
|
||||
DELIVER_PLATFORM="osx"
|
||||
PILOT_PLATFORM="osx"
|
||||
|
|
|
@ -146,7 +146,7 @@ jobs:
|
|||
publish_to_app_store:
|
||||
name: Publish to App Store
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build_upload, submit_for_app_review]
|
||||
needs: submit_for_app_review
|
||||
environment:
|
||||
name: app_store
|
||||
env:
|
||||
|
|
|
@ -14,7 +14,6 @@ iap/
|
|||
templates/
|
||||
.env.secret*
|
||||
Preview.html
|
||||
l10n
|
||||
passepartout-translations.zip
|
||||
default.profraw
|
||||
asc-key.json
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[submodule "Submodules/fastlane-ci-templates"]
|
||||
path = Submodules/fastlane-ci-templates
|
||||
url = https://github.com/keeshux/fastlane-ci-templates
|
||||
[submodule "PassepartoutCore/Sources/PassepartoutCore/API"]
|
||||
path = PassepartoutCore/Sources/PassepartoutCore/API
|
||||
[submodule "PassepartoutCore/Sources/PassepartoutServices/API"]
|
||||
path = PassepartoutCore/Sources/PassepartoutServices/API
|
||||
url = https://github.com/passepartoutvpn/api
|
||||
|
|
|
@ -33,4 +33,6 @@ CFG_GROUP_ID = com.algoritmico.Passepartout
|
|||
CFG_APPSTORE_ID = 1433648537
|
||||
CFG_COPYRIGHT = Copyright © 2022 Davide De Rosa. All rights reserved.
|
||||
|
||||
PATH = $(PATH):/opt/homebrew/bin:/usr/local/bin:/usr/local/go/bin
|
||||
|
||||
#include? "Secret.xcconfig"
|
||||
|
|
50
Gemfile.lock
|
@ -3,7 +3,7 @@ GEM
|
|||
specs:
|
||||
CFPropertyList (3.0.5)
|
||||
rexml
|
||||
activesupport (6.1.4.4)
|
||||
activesupport (6.1.5)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
|
@ -17,27 +17,27 @@ GEM
|
|||
artifactory (3.0.15)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.2.0)
|
||||
aws-partitions (1.552.0)
|
||||
aws-sdk-core (3.126.0)
|
||||
aws-partitions (1.570.0)
|
||||
aws-sdk-core (3.130.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
aws-partitions (~> 1, >= 1.525.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
jmespath (~> 1.0)
|
||||
aws-sdk-kms (1.54.0)
|
||||
aws-sdk-core (~> 3, >= 3.126.0)
|
||||
aws-sdk-kms (1.55.0)
|
||||
aws-sdk-core (~> 3, >= 3.127.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.112.0)
|
||||
aws-sdk-core (~> 3, >= 3.126.0)
|
||||
aws-sdk-s3 (1.113.0)
|
||||
aws-sdk-core (~> 3, >= 3.127.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.4)
|
||||
aws-sigv4 (1.4.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
babosa (1.0.4)
|
||||
claide (1.1.0)
|
||||
cocoapods (1.11.2)
|
||||
cocoapods (1.11.3)
|
||||
addressable (~> 2.8)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
cocoapods-core (= 1.11.2)
|
||||
cocoapods-core (= 1.11.3)
|
||||
cocoapods-deintegrate (>= 1.0.3, < 2.0)
|
||||
cocoapods-downloader (>= 1.4.0, < 2.0)
|
||||
cocoapods-plugins (>= 1.0.0, < 2.0)
|
||||
|
@ -52,7 +52,7 @@ GEM
|
|||
nap (~> 1.0)
|
||||
ruby-macho (>= 1.0, < 3.0)
|
||||
xcodeproj (>= 1.21.0, < 2.0)
|
||||
cocoapods-core (1.11.2)
|
||||
cocoapods-core (1.11.3)
|
||||
activesupport (>= 5.0, < 7)
|
||||
addressable (~> 2.8)
|
||||
algoliasearch (~> 1.0)
|
||||
|
@ -63,7 +63,7 @@ GEM
|
|||
public_suffix (~> 4.0)
|
||||
typhoeus (~> 1.0)
|
||||
cocoapods-deintegrate (1.0.5)
|
||||
cocoapods-downloader (1.5.1)
|
||||
cocoapods-downloader (1.6.1)
|
||||
cocoapods-plugins (1.0.0)
|
||||
nap
|
||||
cocoapods-search (1.0.1)
|
||||
|
@ -75,7 +75,7 @@ GEM
|
|||
colored2 (3.1.2)
|
||||
commander (4.6.0)
|
||||
highline (~> 2.0.0)
|
||||
concurrent-ruby (1.1.9)
|
||||
concurrent-ruby (1.1.10)
|
||||
declarative (0.0.20)
|
||||
digest-crc (0.6.4)
|
||||
rake (>= 12.0.0, < 14.0.0)
|
||||
|
@ -86,8 +86,8 @@ GEM
|
|||
escape (0.0.4)
|
||||
ethon (0.15.0)
|
||||
ffi (>= 1.15.0)
|
||||
excon (0.91.0)
|
||||
faraday (1.9.3)
|
||||
excon (0.92.1)
|
||||
faraday (1.10.0)
|
||||
faraday-em_http (~> 1.0)
|
||||
faraday-em_synchrony (~> 1.0)
|
||||
faraday-excon (~> 1.1)
|
||||
|
@ -116,7 +116,7 @@ GEM
|
|||
faraday_middleware (1.2.0)
|
||||
faraday (~> 1.0)
|
||||
fastimage (2.2.6)
|
||||
fastlane (2.204.2)
|
||||
fastlane (2.205.1)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.8, < 3.0.0)
|
||||
artifactory (~> 3.0)
|
||||
|
@ -179,10 +179,10 @@ GEM
|
|||
google-cloud-core (1.6.0)
|
||||
google-cloud-env (~> 1.0)
|
||||
google-cloud-errors (~> 1.0)
|
||||
google-cloud-env (1.5.0)
|
||||
faraday (>= 0.17.3, < 2.0)
|
||||
google-cloud-env (1.6.0)
|
||||
faraday (>= 0.17.3, < 3.0)
|
||||
google-cloud-errors (1.2.0)
|
||||
google-cloud-storage (1.36.0)
|
||||
google-cloud-storage (1.36.1)
|
||||
addressable (~> 2.8)
|
||||
digest-crc (~> 0.4)
|
||||
google-apis-iamcredentials_v1 (~> 0.1)
|
||||
|
@ -190,8 +190,8 @@ GEM
|
|||
google-cloud-core (~> 1.6)
|
||||
googleauth (>= 0.16.2, < 2.a)
|
||||
mini_mime (~> 1.0)
|
||||
googleauth (1.1.0)
|
||||
faraday (>= 0.17.3, < 2.0)
|
||||
googleauth (1.1.2)
|
||||
faraday (>= 0.17.3, < 3.a)
|
||||
jwt (>= 1.4, < 3.0)
|
||||
memoist (~> 0.16)
|
||||
multi_json (~> 1.11)
|
||||
|
@ -201,9 +201,9 @@ GEM
|
|||
http-cookie (1.0.4)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.8.3)
|
||||
i18n (1.9.1)
|
||||
i18n (1.10.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
jmespath (1.5.0)
|
||||
jmespath (1.6.1)
|
||||
json (2.6.1)
|
||||
jwt (2.3.0)
|
||||
memoist (0.16.2)
|
||||
|
@ -233,9 +233,9 @@ GEM
|
|||
ruby2_keywords (0.0.5)
|
||||
rubyzip (2.3.2)
|
||||
security (0.1.3)
|
||||
signet (0.16.0)
|
||||
signet (0.16.1)
|
||||
addressable (~> 2.8)
|
||||
faraday (>= 0.17.3, < 2.0)
|
||||
faraday (>= 0.17.5, < 3.0)
|
||||
jwt (>= 1.5, < 3.0)
|
||||
multi_json (~> 1.10)
|
||||
simctl (1.6.8)
|
||||
|
@ -256,7 +256,7 @@ GEM
|
|||
uber (0.1.0)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.8)
|
||||
unf_ext (0.0.8.1)
|
||||
unicode-display_width (1.8.0)
|
||||
webrick (1.7.0)
|
||||
word_wrap (1.0.0)
|
||||
|
|
|
@ -1,15 +1,6 @@
|
|||
{
|
||||
"object": {
|
||||
"pins": [
|
||||
{
|
||||
"package": "Convenience",
|
||||
"repositoryURL": "https://github.com/keeshux/convenience",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "347105ec0ce27cd4255acf9875fd60ad1f213801",
|
||||
"version": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "DTFoundation",
|
||||
"repositoryURL": "https://github.com/Cocoanetics/DTFoundation.git",
|
||||
|
@ -20,12 +11,12 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"package": "FontAwesome",
|
||||
"repositoryURL": "https://github.com/thii/FontAwesome.swift",
|
||||
"package": "GenericJSON",
|
||||
"repositoryURL": "https://github.com/zoul/generic-json-swift",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "07883a32d49dfc7bdedbeea115067b53dfbeeb43",
|
||||
"version": "1.9.1"
|
||||
"revision": "a137894b2a217abe489cdf1ea287e6f7819b1051",
|
||||
"version": "2.0.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -37,15 +28,6 @@
|
|||
"version": "1.0.6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "MBProgressHUD",
|
||||
"repositoryURL": "https://github.com/jdg/MBProgressHUD",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "bca42b801100b2b3a4eda0ba8dd33d858c780b0d",
|
||||
"version": "1.2.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "openssl-apple",
|
||||
"repositoryURL": "https://github.com/passepartoutvpn/openssl-apple",
|
||||
|
@ -64,22 +46,13 @@
|
|||
"version": "1.9.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "TunnelKit",
|
||||
"repositoryURL": "https://github.com/passepartoutvpn/tunnelkit",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "88544e4877f00990ef699873f3505fff606ab64b",
|
||||
"version": "4.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "WireGuardKit",
|
||||
"repositoryURL": "https://git.zx2c4.com/wireguard-apple",
|
||||
"repositoryURL": "https://github.com/passepartoutvpn/wireguard-apple",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "10da5cfdef362889b438cfbeff867a74e6d717fd",
|
||||
"version": "1.0.15-26"
|
||||
"revision": "d3b8f1ac6f3361d69bd3daf8aee3c43012c6ec0b",
|
||||
"version": "1.0.16"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1240"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0E5202F6259F573500CBAB56"
|
||||
BuildableName = "Passepartout.app"
|
||||
BlueprintName = "Passepartout-macOS"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0E5203B4259F5F3F00CBAB56"
|
||||
BuildableName = "PassepartoutTunnel.appex"
|
||||
BlueprintName = "PassepartoutTunnel-macOS"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "PassepartoutCoreTests"
|
||||
BuildableName = "PassepartoutCoreTests"
|
||||
BlueprintName = "PassepartoutCoreTests"
|
||||
ReferencedContainer = "container:PassepartoutCore">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0E5202F6259F573500CBAB56"
|
||||
BuildableName = "Passepartout.app"
|
||||
BlueprintName = "Passepartout-macOS"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0E5202F6259F573500CBAB56"
|
||||
BuildableName = "Passepartout.app"
|
||||
BlueprintName = "Passepartout-macOS"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -16,7 +16,7 @@
|
|||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0E57F63720C83FC5008323CF"
|
||||
BuildableName = "Passepartout.app"
|
||||
BlueprintName = "Passepartout-iOS"
|
||||
BlueprintName = "Passepartout"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
|
@ -29,8 +29,36 @@
|
|||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0EDE8DBE20C86910004C739C"
|
||||
BuildableName = "PassepartoutTunnel.appex"
|
||||
BlueprintName = "PassepartoutTunnel-iOS"
|
||||
BuildableName = "PassepartoutOpenVPNTunnel.appex"
|
||||
BlueprintName = "OpenVPNTunnel"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0ECF71F327B6D9CD00CDB528"
|
||||
BuildableName = "WireGuardGo"
|
||||
BlueprintName = "WireGuardGo"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0ED2B33E27D3C77800FD8EA9"
|
||||
BuildableName = "PassepartoutWireGuardTunnel.appex"
|
||||
BlueprintName = "WireGuardTunnel"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
|
@ -46,21 +74,11 @@
|
|||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0E57F63720C83FC5008323CF"
|
||||
BuildableName = "Passepartout.app"
|
||||
BlueprintName = "Passepartout-iOS"
|
||||
BlueprintName = "Passepartout"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "PassepartoutCoreTests"
|
||||
BuildableName = "PassepartoutCoreTests"
|
||||
BlueprintName = "PassepartoutCoreTests"
|
||||
ReferencedContainer = "container:PassepartoutCore">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
|
@ -79,14 +97,41 @@
|
|||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0E57F63720C83FC5008323CF"
|
||||
BuildableName = "Passepartout.app"
|
||||
BlueprintName = "Passepartout-iOS"
|
||||
BlueprintName = "Passepartout"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "-com.apple.CoreData.SQLDebug 0"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "-com.apple.CoreData.Logging.stderr 0 "
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "-com.apple.CoreData.CloudKitDebug 0"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "-com.apple.CoreData.ConcurrencyDebug 0"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "-com.apple.CoreData.MigrationDebug 0"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "FULL_VERSION"
|
||||
value = ""
|
||||
key = "APP_TYPE"
|
||||
value = "2"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
<EnvironmentVariable
|
||||
key = "LOG_LEVEL"
|
||||
value = "0"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
|
@ -103,7 +148,7 @@
|
|||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0E57F63720C83FC5008323CF"
|
||||
BuildableName = "Passepartout.app"
|
||||
BlueprintName = "Passepartout-iOS"
|
||||
BlueprintName = "Passepartout"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
|
@ -1,182 +0,0 @@
|
|||
//
|
||||
// Descriptible.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 1/12/21.
|
||||
// Copyright (c) 2022 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import PassepartoutCore
|
||||
|
||||
public protocol UIDescriptible {
|
||||
var uiDescription: String { get }
|
||||
}
|
||||
|
||||
extension OpenVPN.Cipher: UIDescriptible {
|
||||
public var uiDescription: String {
|
||||
return description
|
||||
}
|
||||
}
|
||||
|
||||
extension OpenVPN.Digest: UIDescriptible {
|
||||
public var uiDescription: String {
|
||||
return description
|
||||
}
|
||||
}
|
||||
|
||||
extension OpenVPN.CompressionFraming: UIDescriptible {
|
||||
public var uiDescription: String {
|
||||
let V = L10n.Configuration.Cells.self
|
||||
switch self {
|
||||
case .disabled:
|
||||
return L10n.Global.Values.disabled
|
||||
|
||||
case .compLZO:
|
||||
return V.CompressionFraming.Value.lzo
|
||||
|
||||
case .compress, .compressV2:
|
||||
return V.CompressionFraming.Value.compress
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension OpenVPN.CompressionAlgorithm: UIDescriptible {
|
||||
public var uiDescription: String {
|
||||
let V = L10n.Configuration.Cells.self
|
||||
switch self {
|
||||
case .disabled:
|
||||
return L10n.Global.Values.disabled
|
||||
|
||||
case .LZO:
|
||||
return V.CompressionAlgorithm.Value.lzo
|
||||
|
||||
case .other:
|
||||
return V.CompressionAlgorithm.Value.other
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension OpenVPN.ConfigurationBuilder {
|
||||
public var uiDescriptionForTLSWrap: String {
|
||||
let V = L10n.Configuration.Cells.self
|
||||
if let strategy = tlsWrap?.strategy {
|
||||
switch strategy {
|
||||
case .auth:
|
||||
return V.TlsWrapping.Value.auth
|
||||
|
||||
case .crypt:
|
||||
return V.TlsWrapping.Value.crypt
|
||||
}
|
||||
} else {
|
||||
return L10n.Global.Values.disabled
|
||||
}
|
||||
}
|
||||
|
||||
public var uiDescriptionForKeepAlive: String {
|
||||
let V = L10n.Configuration.Cells.self
|
||||
if let keepAlive = keepAliveInterval, keepAlive > 0 {
|
||||
return V.KeepAlive.Value.seconds(Int(keepAlive))
|
||||
} else {
|
||||
return L10n.Global.Values.disabled
|
||||
}
|
||||
}
|
||||
|
||||
public var uiDescriptionForClientCertificate: String {
|
||||
let V = L10n.Configuration.Cells.Client.Value.self
|
||||
return (clientCertificate != nil) ? V.enabled : V.disabled
|
||||
}
|
||||
|
||||
public var uiDescriptionForEKU: String {
|
||||
let V = L10n.Global.Values.self
|
||||
return (checksEKU ?? false) ? V.enabled : V.disabled
|
||||
}
|
||||
|
||||
public var uiDescriptionForRenegotiatesAfter: String {
|
||||
let V = L10n.Configuration.Cells.self
|
||||
if let reneg = renegotiatesAfter, reneg > 0 {
|
||||
return V.RenegotiationSeconds.Value.after(TimeInterval(reneg).localized)
|
||||
} else {
|
||||
return L10n.Global.Values.disabled
|
||||
}
|
||||
}
|
||||
|
||||
public var uiDescriptionForRandomizeEndpoint: String {
|
||||
let V = L10n.Global.Values.self
|
||||
return (randomizeEndpoint ?? false) ? V.enabled : V.disabled
|
||||
}
|
||||
|
||||
public var uiDescriptionForXOR: String {
|
||||
let V = L10n.Global.Values.self
|
||||
guard let mask = xorMask, mask != 0 else {
|
||||
return V.disabled
|
||||
}
|
||||
|
||||
return String(format: "0x%02x", UInt8(mask))
|
||||
}
|
||||
}
|
||||
|
||||
extension NetworkChoice: CustomStringConvertible {
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .client:
|
||||
return L10n.NetworkChoice.client
|
||||
|
||||
case .server:
|
||||
return L10n.NetworkChoice.server
|
||||
|
||||
case .manual:
|
||||
return L10n.Global.Values.manual
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension DNSProtocol: CustomStringConvertible {
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .plain:
|
||||
return "Cleartext"
|
||||
|
||||
case .https:
|
||||
return "HTTPS"
|
||||
|
||||
case .tls:
|
||||
return "TLS"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension VPNStatus: UIDescriptible {
|
||||
public var uiDescription: String {
|
||||
switch self {
|
||||
case .connecting:
|
||||
return L10n.Vpn.connecting
|
||||
|
||||
case .connected:
|
||||
return L10n.Vpn.active
|
||||
|
||||
case .disconnecting:
|
||||
return L10n.Vpn.disconnecting
|
||||
|
||||
case .disconnected:
|
||||
return L10n.Vpn.inactive
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
#!/bin/sh
|
||||
|
||||
# build_wireguard_go_bridge.sh - Builds WireGuardKitGo
|
||||
#
|
||||
# Figures out the directory where the wireguard-apple SPM package
|
||||
# is checked out by Xcode (so that it works when building as well as
|
||||
# archiving), then cd-s to the WireGuardKitGo directory
|
||||
# and runs make there.
|
||||
|
||||
project_data_dir="$BUILD_DIR"
|
||||
|
||||
# The wireguard-apple README suggests using ${BUILD_DIR%Build/*}, which
|
||||
# doesn't seem to work. So here, we do the equivalent in script.
|
||||
|
||||
while true; do
|
||||
parent_dir=$(dirname "$project_data_dir")
|
||||
basename=$(basename "$project_data_dir")
|
||||
project_data_dir="$parent_dir"
|
||||
if [ "$basename" = "Build" ]; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# The wireguard-apple README looks into
|
||||
# SourcePackages/checkouts/wireguard-apple, but Xcode seems to place the
|
||||
# sources in SourcePackages/checkouts/ so just playing it safe and
|
||||
# trying both.
|
||||
|
||||
checkouts_dir="$project_data_dir"/SourcePackages/checkouts
|
||||
if [ -e "$checkouts_dir"/wireguard-apple ]; then
|
||||
checkouts_dir="$checkouts_dir"/wireguard-apple
|
||||
fi
|
||||
|
||||
wireguard_go_dir="$checkouts_dir"/Sources/WireGuardKitGo
|
||||
|
||||
# To ensure we have Go in our path, we add where
|
||||
# Homebrew generally installs executables
|
||||
export PATH=${PATH}:/opt/homebrew/bin:/usr/local/bin:/usr/local/go/bin
|
||||
|
||||
cd "$wireguard_go_dir" && /usr/bin/make
|
|
@ -0,0 +1,9 @@
|
|||
# Type a script or drag a script file from your workspace to insert its path.
|
||||
CD_PROVIDERS_DIR="$PROJECT_TEMP_DIR/../PassepartoutCore.build/Debug-iphonesimulator/PassepartoutProviders.build/DerivedSources/CoreDataGenerated/Providers"
|
||||
CD_CORE_DIR="$PROJECT_TEMP_DIR/../PassepartoutCore.build/Debug-iphonesimulator/PassepartoutCore.build/DerivedSources/CoreDataGenerated/Core"
|
||||
if [ -d "$CD_PROVIDERS_DIR" ]; then
|
||||
cp "$CD_PROVIDERS_DIR"/* "$PROJECT_DIR/PassepartoutCore/Sources/PassepartoutProviders/DataModels"
|
||||
fi
|
||||
if [ -d "$CD_CORE_DIR" ]; then
|
||||
cp "$CD_CORE_DIR"/* "$PROJECT_DIR/PassepartoutCore/Sources/PassepartoutCore/DataModels"
|
||||
fi
|
|
@ -2,20 +2,36 @@
|
|||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>aps-environment</key>
|
||||
<string>development</string>
|
||||
<key>com.apple.developer.icloud-container-identifiers</key>
|
||||
<array>
|
||||
<string>iCloud.com.algoritmico.Passepartout</string>
|
||||
</array>
|
||||
<key>com.apple.developer.icloud-services</key>
|
||||
<array>
|
||||
<string>CloudKit</string>
|
||||
</array>
|
||||
<key>com.apple.developer.networking.networkextension</key>
|
||||
<array>
|
||||
<string>packet-tunnel-provider</string>
|
||||
</array>
|
||||
<key>com.apple.developer.networking.wifi-info</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.siri</key>
|
||||
<true/>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>$(TeamIdentifierPrefix)group.$(CFG_GROUP_ID)</string>
|
||||
<string>group.$(CFG_GROUP_ID)</string>
|
||||
</array>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.security.personal-information.location</key>
|
||||
<true/>
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$(AppIdentifierPrefix)group.com.algoritmico.Passepartout</string>
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x68",
|
||||
"green" : "0x9C",
|
||||
"red" : "0xD6"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "1.000",
|
||||
"green" : "1.000",
|
||||
"red" : "1.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.3 KiB |
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.443",
|
||||
"green" : "0.365",
|
||||
"red" : "0.318"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
//
|
||||
// AppContext.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 3/17/22.
|
||||
// Copyright (c) 2022 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
import Combine
|
||||
import PassepartoutCore
|
||||
import PassepartoutServices
|
||||
|
||||
@MainActor
|
||||
class AppContext {
|
||||
static let shared = AppContext()
|
||||
|
||||
private let persistenceManager: PersistenceManager
|
||||
|
||||
let appManager: AppManager
|
||||
|
||||
let providerManager: ProviderManager
|
||||
|
||||
let profileManager: ProfileManager
|
||||
|
||||
let vpnManager: VPNManager
|
||||
|
||||
let productManager: ProductManager
|
||||
|
||||
let intentsManager: IntentsManager
|
||||
|
||||
let reviewer: Reviewer
|
||||
|
||||
private var cancellables: Set<AnyCancellable> = []
|
||||
|
||||
private init() {
|
||||
|
||||
// core
|
||||
|
||||
appManager = AppManager()
|
||||
appManager.logLevel = Constants.Log.logLevel
|
||||
appManager.logFile = Constants.Log.appFileURL
|
||||
appManager.logFormat = Constants.Log.appLogFormat
|
||||
appManager.tunnelLogFormat = Constants.Log.tunnelLogFormat
|
||||
appManager.configureLogging()
|
||||
pp_log.info("Logging to: \(appManager.logFile!)")
|
||||
|
||||
persistenceManager = PersistenceManager(author: appManager.persistenceAuthor)
|
||||
|
||||
providerManager = ProviderManager(
|
||||
appBuild: Constants.Global.appBuildNumber,
|
||||
bundleServices: DefaultWebServices.bundledServices(
|
||||
withVersion: Constants.Services.version
|
||||
),
|
||||
webServices: DefaultWebServices(
|
||||
Constants.Services.version,
|
||||
Constants.Repos.api,
|
||||
timeout: Constants.Services.connectivityTimeout
|
||||
),
|
||||
persistence: persistenceManager.providersPersistence(
|
||||
withName: Constants.Persistence.providersContainerName
|
||||
)
|
||||
)
|
||||
|
||||
profileManager = ProfileManager(
|
||||
providerManager: providerManager,
|
||||
appGroup: Constants.App.appGroupId,
|
||||
keychainLabel: Unlocalized.Keychain.passwordLabel,
|
||||
strategy: ProfileManager.CoreDataStrategy(
|
||||
persistence: persistenceManager.profilesPersistence(
|
||||
withName: Constants.Persistence.profilesContainerName
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
#if targetEnvironment(simulator)
|
||||
vpnManager = VPNManager(
|
||||
appManager: appManager,
|
||||
profileManager: profileManager,
|
||||
providerManager: providerManager,
|
||||
strategy: VPNManager.MockStrategy()
|
||||
)
|
||||
#else
|
||||
vpnManager = VPNManager(
|
||||
appManager: appManager,
|
||||
profileManager: profileManager,
|
||||
providerManager: providerManager,
|
||||
strategy: VPNManager.TunnelKitStrategy(
|
||||
appGroup: Constants.App.appGroupId,
|
||||
tunnelBundleIdentifier: Constants.App.tunnelBundleId
|
||||
)
|
||||
)
|
||||
#endif
|
||||
|
||||
// app
|
||||
|
||||
productManager = ProductManager(.init(
|
||||
appType: Constants.InApp.appType,
|
||||
lastFullVersionBuild: Constants.InApp.lastFullVersionBuild
|
||||
))
|
||||
intentsManager = IntentsManager()
|
||||
reviewer = Reviewer()
|
||||
|
||||
// post
|
||||
|
||||
configureObjects()
|
||||
}
|
||||
|
||||
private func configureObjects() {
|
||||
|
||||
// core
|
||||
|
||||
profileManager.availabilityFilter = {
|
||||
self.isEligibleProfile(withHeader: $0)
|
||||
}
|
||||
profileManager.activeProfileId = appManager.activeProfileId
|
||||
providerManager.rateLimitMilliseconds = Constants.RateLimit.providerManager
|
||||
vpnManager.rateLimitMilliseconds = Constants.RateLimit.vpnManager
|
||||
vpnManager.isOnDemandSupported = {
|
||||
self.isEligibleForOnDemand()
|
||||
}
|
||||
|
||||
// app
|
||||
|
||||
reviewer.eventCountBeforeRating = Constants.Rating.eventCount
|
||||
vpnManager.currentState.$vpnStatus
|
||||
.removeDuplicates()
|
||||
.sink {
|
||||
if $0 == .connected {
|
||||
pp_log.info("VPN successful connection, report to Reviewer")
|
||||
self.reviewer.reportEvent()
|
||||
}
|
||||
}.store(in: &cancellables)
|
||||
}
|
||||
|
||||
// eligibility: hide providers not found or not purchased
|
||||
private func isEligibleProfile(withHeader header: Profile.Header) -> Bool {
|
||||
guard let providerName = header.providerName else {
|
||||
return true // always eligible for non-provider profiles
|
||||
}
|
||||
guard productManager.isEligible(forProvider: providerName) else {
|
||||
// pp_log.debug("Not eligible for provider \(metadata.name)")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// eligibility: reset on-demand rules if no trusted networks
|
||||
private func isEligibleForOnDemand() -> Bool {
|
||||
guard productManager.isEligible(forFeature: .trustedNetworks) else {
|
||||
pp_log.warning("Ignore on-demand rules, not eligible for trusted networks")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension AppManager {
|
||||
static let shared = AppContext.shared.appManager
|
||||
}
|
||||
|
||||
extension ProfileManager {
|
||||
static let shared = AppContext.shared.profileManager
|
||||
}
|
||||
|
||||
extension ProviderManager {
|
||||
static let shared = AppContext.shared.providerManager
|
||||
}
|
||||
|
||||
extension VPNManager {
|
||||
static let shared = AppContext.shared.vpnManager
|
||||
}
|
||||
|
||||
extension ProductManager {
|
||||
static let shared = AppContext.shared.productManager
|
||||
}
|
||||
|
||||
extension IntentsManager {
|
||||
static let shared = AppContext.shared.intentsManager
|
||||
}
|
||||
|
||||
extension Reviewer {
|
||||
static let shared = AppContext.shared.reviewer
|
||||
}
|
||||
|
||||
extension VPNManager.ObservableState {
|
||||
|
||||
@MainActor
|
||||
static let shared = AppContext.shared.vpnManager.currentState
|
||||
}
|
|
@ -0,0 +1,282 @@
|
|||
//
|
||||
// Constants+Extensions.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 9/15/18.
|
||||
// Copyright (c) 2022 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UniformTypeIdentifiers
|
||||
import PassepartoutCore
|
||||
import SwiftyBeaver
|
||||
|
||||
extension Constants {
|
||||
private static let bundleConfig = Bundle.main.infoDictionary?["com.algoritmico.Passepartout.config"] as? [String: Any]
|
||||
}
|
||||
|
||||
extension Constants {
|
||||
enum App {
|
||||
static let appLauncherId = bundleConfig?["app_launcher_id"] as? String ?? "DUMMY_app_launcher_id"
|
||||
|
||||
static let appStoreId = bundleConfig?["appstore_id"] as? String ?? "DUMMY_appstore_id"
|
||||
|
||||
static let appGroupId = bundleConfig?["group_id"] as? String ?? "DUMMY_group_id"
|
||||
|
||||
static func tunnelBundleId(_ vpnProtocol: VPNProtocolType) -> String {
|
||||
guard let identifier = Bundle.main.infoDictionary?[kCFBundleIdentifierKey as String] as? String else {
|
||||
fatalError("Missing kCFBundleIdentifierKey from Info.plist")
|
||||
}
|
||||
let prefix = "\(identifier).Tunnel"
|
||||
switch vpnProtocol {
|
||||
case .openVPN:
|
||||
return "\(prefix).OpenVPN"
|
||||
|
||||
case .wireGuard:
|
||||
return "\(prefix).WireGuard"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum InApp {
|
||||
static var appType: ProductManager.AppType {
|
||||
if let envString = ProcessInfo.processInfo.environment["APP_TYPE"],
|
||||
let envValue = Int(envString),
|
||||
let testAppType = ProductManager.AppType(rawValue: envValue) {
|
||||
|
||||
return testAppType
|
||||
}
|
||||
if let infoValue = bundleConfig?["app_type"] as? Int,
|
||||
let testAppType = ProductManager.AppType(rawValue: infoValue) {
|
||||
|
||||
return testAppType
|
||||
}
|
||||
return isBeta ? .beta : .freemium
|
||||
}
|
||||
|
||||
#if os(iOS)
|
||||
static let lastFullVersionBuild: (Int, LocalProduct) = (2016, .fullVersion_iOS)
|
||||
#else
|
||||
static let lastFullVersionBuild: (Int, LocalProduct) = (0, .fullVersion_macOS)
|
||||
#endif
|
||||
|
||||
private static var isBeta: Bool {
|
||||
#if os(iOS)
|
||||
#if targetEnvironment(simulator)
|
||||
return true
|
||||
#else
|
||||
return Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt"
|
||||
#endif
|
||||
#else
|
||||
// TODO: production, skip TestFlight on macOS until beta condition is clearly determined
|
||||
return false
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Constants {
|
||||
enum Activities {
|
||||
static let enableVPN = "EnableVPNIntent"
|
||||
|
||||
static let disableVPN = "DisableVPNIntent"
|
||||
|
||||
static let connectVPN = "ConnectVPNIntent"
|
||||
|
||||
static let moveToLocation = "MoveToLocationIntent"
|
||||
|
||||
static let trustCellularNetwork = "TrustCellularNetworkIntent"
|
||||
|
||||
static let trustCurrentNetwork = "TrustCurrentNetworkIntent"
|
||||
|
||||
static let untrustCellularNetwork = "UntrustCellularNetworkIntent"
|
||||
|
||||
static let untrustCurrentNetwork = "UntrustCurrentNetworkIntent"
|
||||
}
|
||||
}
|
||||
|
||||
extension Constants {
|
||||
enum Domain {
|
||||
static let name = "passepartoutvpn.app"
|
||||
}
|
||||
|
||||
enum Services {
|
||||
static let version = "v5"
|
||||
|
||||
private static let connectivityStrings: [String] = [
|
||||
"https://www.amazon.com",
|
||||
"https://www.google.com",
|
||||
"https://www.twitter.com",
|
||||
"https://www.facebook.com",
|
||||
"https://www.instagram.com"
|
||||
]
|
||||
|
||||
static let connectivityURL = URL(string: connectivityStrings.randomElement()!)!
|
||||
|
||||
static let connectivityTimeout: TimeInterval = 10.0
|
||||
}
|
||||
|
||||
enum Persistence {
|
||||
static let profilesContainerName = "Profiles"
|
||||
|
||||
static let providersContainerName = "Providers"
|
||||
}
|
||||
|
||||
// milliseconds
|
||||
enum RateLimit {
|
||||
static let providerManager = 10000
|
||||
|
||||
static let vpnManager = 500
|
||||
}
|
||||
|
||||
enum Log {
|
||||
static let logLevel: SwiftyBeaver.Level = {
|
||||
guard let levelString = ProcessInfo.processInfo.environment["LOG_LEVEL"], let levelNum = Int(levelString) else {
|
||||
return .info
|
||||
}
|
||||
return .init(rawValue: levelNum) ?? .info
|
||||
}()
|
||||
|
||||
static let appLogFormat = "$DHH:mm:ss.SSS$d $C$L$c $N.$F:$l - $M"
|
||||
|
||||
private static let appFileName = "Debug.log"
|
||||
|
||||
static var appFileURL: URL {
|
||||
return Files.cachesURL.appendingPathComponent(appFileName)
|
||||
}
|
||||
|
||||
static let tunnelLogFormat = "$DHH:mm:ss$d - $M"
|
||||
|
||||
static let tunnelLogMaxBytes = 15000
|
||||
|
||||
static let tunnelLogRefreshInterval: TimeInterval = 5.0
|
||||
}
|
||||
|
||||
enum URLs {
|
||||
static let readme = Repos.apple.appendingPathComponent("blob/master/README.md")
|
||||
|
||||
enum iOS {
|
||||
static let changelog = Repos.apple.appendingPathComponent("blob/master/Passepartout/App/iOS/CHANGELOG.md")
|
||||
}
|
||||
|
||||
enum macOS {
|
||||
static let changelog = Repos.apple.appendingPathComponent("blob/master/Passepartout/App/macOS/CHANGELOG.md")
|
||||
}
|
||||
|
||||
static let filetypes: [UTType] = [.item]
|
||||
|
||||
static let website = URL(string: "https://\(Domain.name)")!
|
||||
|
||||
static let faq = website.appendingPathComponent("faq")
|
||||
|
||||
static let disclaimer = website.appendingPathComponent("disclaimer")
|
||||
|
||||
static let privacyPolicy = website.appendingPathComponent("privacy")
|
||||
|
||||
static let donate = website.appendingPathComponent("donate")
|
||||
|
||||
static let subreddit = URL(string: "https://www.reddit.com/r/passepartout")!
|
||||
|
||||
static let twitch = URL(string: "twitch://stream/keeshux")!
|
||||
|
||||
static let twitchFallback = URL(string: "https://twitch.tv/keeshux")!
|
||||
|
||||
static let githubSponsors = URL(string: "https://www.github.com/sponsors/passepartoutvpn")!
|
||||
|
||||
static let alternativeTo = URL(string: "https://alternativeto.net/software/passepartout-vpn/about/")!
|
||||
|
||||
static let openVPNGuidances: [ProviderName: String] = [
|
||||
.protonvpn: "https://account.protonvpn.com/settings",
|
||||
.surfshark: "https://my.surfshark.com/vpn/manual-setup/main",
|
||||
.torguard: "https://torguard.net/clientarea.php?action=changepw",
|
||||
.windscribe: "https://windscribe.com/getconfig/openvpn"
|
||||
]
|
||||
|
||||
static let referrals: [ProviderName: String] = [
|
||||
.hideme: "https://member.hide.me/en/checkout?plan=new_default_prices&coupon=6CB-BDB-802&duration=24",
|
||||
.mullvad: "https://mullvad.net/en/account/create/",
|
||||
.nordvpn: "https://go.nordvpn.net/SH21Z",
|
||||
.pia: "https://www.privateinternetaccess.com/pages/buy-vpn/",
|
||||
.protonvpn: "https://proton.go2cloud.org/SHZ",
|
||||
.torguard: "https://torguard.net/",
|
||||
.tunnelbear: "https://www.tunnelbear.com/",
|
||||
.vyprvpn: "https://www.vyprvpn.com/",
|
||||
.windscribe: "https://secure.link/kCsD0prd"
|
||||
]
|
||||
}
|
||||
|
||||
enum Repos {
|
||||
private static let githubRoot = URL(string: "https://github.com/passepartoutvpn/")!
|
||||
|
||||
private static let githubRawRoot = URL(string: "https://\(Domain.name)/")!
|
||||
|
||||
private static func github(repo: String) -> URL {
|
||||
return githubRoot.appendingPathComponent(repo)
|
||||
}
|
||||
|
||||
private static func githubRaw(repo: String) -> URL {
|
||||
return githubRawRoot.appendingPathComponent(repo)
|
||||
}
|
||||
|
||||
static let apple = github(repo: "passepartout-apple")
|
||||
|
||||
static let api = githubRaw(repo: "api")
|
||||
}
|
||||
|
||||
// milliseconds
|
||||
enum Delays {
|
||||
static let scrolling = 100
|
||||
|
||||
// @available(*, deprecated, message: "for weird animation when using withAnimation() in View.onAppear")
|
||||
static let xxxAnimateOnAppear = 200
|
||||
|
||||
// @available(*, deprecated, message: "file importer stops showing again after closing with swipe down")
|
||||
static let xxxPresentFileImporter = 200
|
||||
|
||||
// @available(*, deprecated, message: "edited shortcut is outdated in delegate")
|
||||
static let xxxReloadEditedShortcut = 200
|
||||
}
|
||||
|
||||
enum Rating {
|
||||
#if os(iOS)
|
||||
static let eventCount = 3
|
||||
#else
|
||||
static let eventCount = 10
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
extension Constants {
|
||||
enum Files {
|
||||
private static var containerURL: URL {
|
||||
guard let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: App.appGroupId) else {
|
||||
print("Unable to access App Group container")
|
||||
return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
static let cachesURL: URL = {
|
||||
let url = containerURL.appendingPathComponent("Library/Caches", isDirectory: true)
|
||||
try? FileManager.default.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil)
|
||||
return url
|
||||
}()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,418 @@
|
|||
// swiftlint:disable all
|
||||
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
|
||||
|
||||
#if os(macOS)
|
||||
import AppKit
|
||||
#elseif os(iOS)
|
||||
import UIKit
|
||||
#elseif os(tvOS) || os(watchOS)
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
// Deprecated typealiases
|
||||
@available(*, deprecated, renamed: "ColorAsset.Color", message: "This typealias will be removed in SwiftGen 7.0")
|
||||
internal typealias AssetColorTypeAlias = ColorAsset.Color
|
||||
@available(*, deprecated, renamed: "ImageAsset.Image", message: "This typealias will be removed in SwiftGen 7.0")
|
||||
internal typealias AssetImageTypeAlias = ImageAsset.Image
|
||||
|
||||
// swiftlint:disable superfluous_disable_command file_length implicit_return
|
||||
|
||||
// MARK: - Asset Catalogs
|
||||
|
||||
// swiftlint:disable identifier_name line_length nesting type_body_length type_name
|
||||
internal enum Asset {
|
||||
internal enum Assets {
|
||||
internal static let accentColor = ColorAsset(name: "accentColor")
|
||||
internal static let lightTextColor = ColorAsset(name: "lightTextColor")
|
||||
internal static let logo = ImageAsset(name: "logo")
|
||||
internal static let primaryColor = ColorAsset(name: "primaryColor")
|
||||
}
|
||||
internal enum Flags {
|
||||
internal enum Flags {
|
||||
internal static let ad = ImageAsset(name: "flags/ad")
|
||||
internal static let ae = ImageAsset(name: "flags/ae")
|
||||
internal static let af = ImageAsset(name: "flags/af")
|
||||
internal static let ag = ImageAsset(name: "flags/ag")
|
||||
internal static let ai = ImageAsset(name: "flags/ai")
|
||||
internal static let al = ImageAsset(name: "flags/al")
|
||||
internal static let am = ImageAsset(name: "flags/am")
|
||||
internal static let ao = ImageAsset(name: "flags/ao")
|
||||
internal static let aq = ImageAsset(name: "flags/aq")
|
||||
internal static let ar = ImageAsset(name: "flags/ar")
|
||||
internal static let `as` = ImageAsset(name: "flags/as")
|
||||
internal static let at = ImageAsset(name: "flags/at")
|
||||
internal static let au = ImageAsset(name: "flags/au")
|
||||
internal static let aw = ImageAsset(name: "flags/aw")
|
||||
internal static let ax = ImageAsset(name: "flags/ax")
|
||||
internal static let az = ImageAsset(name: "flags/az")
|
||||
internal static let ba = ImageAsset(name: "flags/ba")
|
||||
internal static let bb = ImageAsset(name: "flags/bb")
|
||||
internal static let bd = ImageAsset(name: "flags/bd")
|
||||
internal static let be = ImageAsset(name: "flags/be")
|
||||
internal static let bf = ImageAsset(name: "flags/bf")
|
||||
internal static let bg = ImageAsset(name: "flags/bg")
|
||||
internal static let bh = ImageAsset(name: "flags/bh")
|
||||
internal static let bi = ImageAsset(name: "flags/bi")
|
||||
internal static let bj = ImageAsset(name: "flags/bj")
|
||||
internal static let bl = ImageAsset(name: "flags/bl")
|
||||
internal static let bm = ImageAsset(name: "flags/bm")
|
||||
internal static let bn = ImageAsset(name: "flags/bn")
|
||||
internal static let bo = ImageAsset(name: "flags/bo")
|
||||
internal static let bq = ImageAsset(name: "flags/bq")
|
||||
internal static let br = ImageAsset(name: "flags/br")
|
||||
internal static let bs = ImageAsset(name: "flags/bs")
|
||||
internal static let bt = ImageAsset(name: "flags/bt")
|
||||
internal static let bv = ImageAsset(name: "flags/bv")
|
||||
internal static let bw = ImageAsset(name: "flags/bw")
|
||||
internal static let by = ImageAsset(name: "flags/by")
|
||||
internal static let bz = ImageAsset(name: "flags/bz")
|
||||
internal static let ca = ImageAsset(name: "flags/ca")
|
||||
internal static let cc = ImageAsset(name: "flags/cc")
|
||||
internal static let cd = ImageAsset(name: "flags/cd")
|
||||
internal static let cf = ImageAsset(name: "flags/cf")
|
||||
internal static let cg = ImageAsset(name: "flags/cg")
|
||||
internal static let ch = ImageAsset(name: "flags/ch")
|
||||
internal static let ci = ImageAsset(name: "flags/ci")
|
||||
internal static let ck = ImageAsset(name: "flags/ck")
|
||||
internal static let cl = ImageAsset(name: "flags/cl")
|
||||
internal static let cm = ImageAsset(name: "flags/cm")
|
||||
internal static let cn = ImageAsset(name: "flags/cn")
|
||||
internal static let co = ImageAsset(name: "flags/co")
|
||||
internal static let cr = ImageAsset(name: "flags/cr")
|
||||
internal static let cu = ImageAsset(name: "flags/cu")
|
||||
internal static let cv = ImageAsset(name: "flags/cv")
|
||||
internal static let cw = ImageAsset(name: "flags/cw")
|
||||
internal static let cx = ImageAsset(name: "flags/cx")
|
||||
internal static let cy = ImageAsset(name: "flags/cy")
|
||||
internal static let cz = ImageAsset(name: "flags/cz")
|
||||
internal static let de = ImageAsset(name: "flags/de")
|
||||
internal static let dj = ImageAsset(name: "flags/dj")
|
||||
internal static let dk = ImageAsset(name: "flags/dk")
|
||||
internal static let dm = ImageAsset(name: "flags/dm")
|
||||
internal static let `do` = ImageAsset(name: "flags/do")
|
||||
internal static let dz = ImageAsset(name: "flags/dz")
|
||||
internal static let ec = ImageAsset(name: "flags/ec")
|
||||
internal static let ee = ImageAsset(name: "flags/ee")
|
||||
internal static let eg = ImageAsset(name: "flags/eg")
|
||||
internal static let eh = ImageAsset(name: "flags/eh")
|
||||
internal static let er = ImageAsset(name: "flags/er")
|
||||
internal static let esCt = ImageAsset(name: "flags/es-ct")
|
||||
internal static let es = ImageAsset(name: "flags/es")
|
||||
internal static let et = ImageAsset(name: "flags/et")
|
||||
internal static let eu = ImageAsset(name: "flags/eu")
|
||||
internal static let fi = ImageAsset(name: "flags/fi")
|
||||
internal static let fj = ImageAsset(name: "flags/fj")
|
||||
internal static let fk = ImageAsset(name: "flags/fk")
|
||||
internal static let fm = ImageAsset(name: "flags/fm")
|
||||
internal static let fo = ImageAsset(name: "flags/fo")
|
||||
internal static let fr = ImageAsset(name: "flags/fr")
|
||||
internal static let ga = ImageAsset(name: "flags/ga")
|
||||
internal static let gbEng = ImageAsset(name: "flags/gb-eng")
|
||||
internal static let gbNir = ImageAsset(name: "flags/gb-nir")
|
||||
internal static let gbSct = ImageAsset(name: "flags/gb-sct")
|
||||
internal static let gbWls = ImageAsset(name: "flags/gb-wls")
|
||||
internal static let gb = ImageAsset(name: "flags/gb")
|
||||
internal static let gd = ImageAsset(name: "flags/gd")
|
||||
internal static let ge = ImageAsset(name: "flags/ge")
|
||||
internal static let gf = ImageAsset(name: "flags/gf")
|
||||
internal static let gg = ImageAsset(name: "flags/gg")
|
||||
internal static let gh = ImageAsset(name: "flags/gh")
|
||||
internal static let gi = ImageAsset(name: "flags/gi")
|
||||
internal static let gl = ImageAsset(name: "flags/gl")
|
||||
internal static let gm = ImageAsset(name: "flags/gm")
|
||||
internal static let gn = ImageAsset(name: "flags/gn")
|
||||
internal static let gp = ImageAsset(name: "flags/gp")
|
||||
internal static let gq = ImageAsset(name: "flags/gq")
|
||||
internal static let gr = ImageAsset(name: "flags/gr")
|
||||
internal static let gs = ImageAsset(name: "flags/gs")
|
||||
internal static let gt = ImageAsset(name: "flags/gt")
|
||||
internal static let gu = ImageAsset(name: "flags/gu")
|
||||
internal static let gw = ImageAsset(name: "flags/gw")
|
||||
internal static let gy = ImageAsset(name: "flags/gy")
|
||||
internal static let hk = ImageAsset(name: "flags/hk")
|
||||
internal static let hm = ImageAsset(name: "flags/hm")
|
||||
internal static let hn = ImageAsset(name: "flags/hn")
|
||||
internal static let hr = ImageAsset(name: "flags/hr")
|
||||
internal static let ht = ImageAsset(name: "flags/ht")
|
||||
internal static let hu = ImageAsset(name: "flags/hu")
|
||||
internal static let id = ImageAsset(name: "flags/id")
|
||||
internal static let ie = ImageAsset(name: "flags/ie")
|
||||
internal static let il = ImageAsset(name: "flags/il")
|
||||
internal static let im = ImageAsset(name: "flags/im")
|
||||
internal static let `in` = ImageAsset(name: "flags/in")
|
||||
internal static let io = ImageAsset(name: "flags/io")
|
||||
internal static let iq = ImageAsset(name: "flags/iq")
|
||||
internal static let ir = ImageAsset(name: "flags/ir")
|
||||
internal static let `is` = ImageAsset(name: "flags/is")
|
||||
internal static let it = ImageAsset(name: "flags/it")
|
||||
internal static let je = ImageAsset(name: "flags/je")
|
||||
internal static let jm = ImageAsset(name: "flags/jm")
|
||||
internal static let jo = ImageAsset(name: "flags/jo")
|
||||
internal static let jp = ImageAsset(name: "flags/jp")
|
||||
internal static let ke = ImageAsset(name: "flags/ke")
|
||||
internal static let kg = ImageAsset(name: "flags/kg")
|
||||
internal static let kh = ImageAsset(name: "flags/kh")
|
||||
internal static let ki = ImageAsset(name: "flags/ki")
|
||||
internal static let km = ImageAsset(name: "flags/km")
|
||||
internal static let kn = ImageAsset(name: "flags/kn")
|
||||
internal static let kp = ImageAsset(name: "flags/kp")
|
||||
internal static let kr = ImageAsset(name: "flags/kr")
|
||||
internal static let kw = ImageAsset(name: "flags/kw")
|
||||
internal static let ky = ImageAsset(name: "flags/ky")
|
||||
internal static let kz = ImageAsset(name: "flags/kz")
|
||||
internal static let la = ImageAsset(name: "flags/la")
|
||||
internal static let lb = ImageAsset(name: "flags/lb")
|
||||
internal static let lc = ImageAsset(name: "flags/lc")
|
||||
internal static let li = ImageAsset(name: "flags/li")
|
||||
internal static let lk = ImageAsset(name: "flags/lk")
|
||||
internal static let lr = ImageAsset(name: "flags/lr")
|
||||
internal static let ls = ImageAsset(name: "flags/ls")
|
||||
internal static let lt = ImageAsset(name: "flags/lt")
|
||||
internal static let lu = ImageAsset(name: "flags/lu")
|
||||
internal static let lv = ImageAsset(name: "flags/lv")
|
||||
internal static let ly = ImageAsset(name: "flags/ly")
|
||||
internal static let ma = ImageAsset(name: "flags/ma")
|
||||
internal static let mc = ImageAsset(name: "flags/mc")
|
||||
internal static let md = ImageAsset(name: "flags/md")
|
||||
internal static let me = ImageAsset(name: "flags/me")
|
||||
internal static let mf = ImageAsset(name: "flags/mf")
|
||||
internal static let mg = ImageAsset(name: "flags/mg")
|
||||
internal static let mh = ImageAsset(name: "flags/mh")
|
||||
internal static let mk = ImageAsset(name: "flags/mk")
|
||||
internal static let ml = ImageAsset(name: "flags/ml")
|
||||
internal static let mm = ImageAsset(name: "flags/mm")
|
||||
internal static let mn = ImageAsset(name: "flags/mn")
|
||||
internal static let mo = ImageAsset(name: "flags/mo")
|
||||
internal static let mp = ImageAsset(name: "flags/mp")
|
||||
internal static let mq = ImageAsset(name: "flags/mq")
|
||||
internal static let mr = ImageAsset(name: "flags/mr")
|
||||
internal static let ms = ImageAsset(name: "flags/ms")
|
||||
internal static let mt = ImageAsset(name: "flags/mt")
|
||||
internal static let mu = ImageAsset(name: "flags/mu")
|
||||
internal static let mv = ImageAsset(name: "flags/mv")
|
||||
internal static let mw = ImageAsset(name: "flags/mw")
|
||||
internal static let mx = ImageAsset(name: "flags/mx")
|
||||
internal static let my = ImageAsset(name: "flags/my")
|
||||
internal static let mz = ImageAsset(name: "flags/mz")
|
||||
internal static let na = ImageAsset(name: "flags/na")
|
||||
internal static let nc = ImageAsset(name: "flags/nc")
|
||||
internal static let ne = ImageAsset(name: "flags/ne")
|
||||
internal static let nf = ImageAsset(name: "flags/nf")
|
||||
internal static let ng = ImageAsset(name: "flags/ng")
|
||||
internal static let ni = ImageAsset(name: "flags/ni")
|
||||
internal static let nl = ImageAsset(name: "flags/nl")
|
||||
internal static let no = ImageAsset(name: "flags/no")
|
||||
internal static let np = ImageAsset(name: "flags/np")
|
||||
internal static let nr = ImageAsset(name: "flags/nr")
|
||||
internal static let nu = ImageAsset(name: "flags/nu")
|
||||
internal static let nz = ImageAsset(name: "flags/nz")
|
||||
internal static let om = ImageAsset(name: "flags/om")
|
||||
internal static let pa = ImageAsset(name: "flags/pa")
|
||||
internal static let pe = ImageAsset(name: "flags/pe")
|
||||
internal static let pf = ImageAsset(name: "flags/pf")
|
||||
internal static let pg = ImageAsset(name: "flags/pg")
|
||||
internal static let ph = ImageAsset(name: "flags/ph")
|
||||
internal static let pk = ImageAsset(name: "flags/pk")
|
||||
internal static let pl = ImageAsset(name: "flags/pl")
|
||||
internal static let pm = ImageAsset(name: "flags/pm")
|
||||
internal static let pn = ImageAsset(name: "flags/pn")
|
||||
internal static let pr = ImageAsset(name: "flags/pr")
|
||||
internal static let ps = ImageAsset(name: "flags/ps")
|
||||
internal static let pt = ImageAsset(name: "flags/pt")
|
||||
internal static let pw = ImageAsset(name: "flags/pw")
|
||||
internal static let py = ImageAsset(name: "flags/py")
|
||||
internal static let qa = ImageAsset(name: "flags/qa")
|
||||
internal static let re = ImageAsset(name: "flags/re")
|
||||
internal static let ro = ImageAsset(name: "flags/ro")
|
||||
internal static let rs = ImageAsset(name: "flags/rs")
|
||||
internal static let ru = ImageAsset(name: "flags/ru")
|
||||
internal static let rw = ImageAsset(name: "flags/rw")
|
||||
internal static let sa = ImageAsset(name: "flags/sa")
|
||||
internal static let sb = ImageAsset(name: "flags/sb")
|
||||
internal static let sc = ImageAsset(name: "flags/sc")
|
||||
internal static let sd = ImageAsset(name: "flags/sd")
|
||||
internal static let se = ImageAsset(name: "flags/se")
|
||||
internal static let sg = ImageAsset(name: "flags/sg")
|
||||
internal static let sh = ImageAsset(name: "flags/sh")
|
||||
internal static let si = ImageAsset(name: "flags/si")
|
||||
internal static let sj = ImageAsset(name: "flags/sj")
|
||||
internal static let sk = ImageAsset(name: "flags/sk")
|
||||
internal static let sl = ImageAsset(name: "flags/sl")
|
||||
internal static let sm = ImageAsset(name: "flags/sm")
|
||||
internal static let sn = ImageAsset(name: "flags/sn")
|
||||
internal static let so = ImageAsset(name: "flags/so")
|
||||
internal static let sr = ImageAsset(name: "flags/sr")
|
||||
internal static let ss = ImageAsset(name: "flags/ss")
|
||||
internal static let st = ImageAsset(name: "flags/st")
|
||||
internal static let sv = ImageAsset(name: "flags/sv")
|
||||
internal static let sx = ImageAsset(name: "flags/sx")
|
||||
internal static let sy = ImageAsset(name: "flags/sy")
|
||||
internal static let sz = ImageAsset(name: "flags/sz")
|
||||
internal static let tc = ImageAsset(name: "flags/tc")
|
||||
internal static let td = ImageAsset(name: "flags/td")
|
||||
internal static let tf = ImageAsset(name: "flags/tf")
|
||||
internal static let tg = ImageAsset(name: "flags/tg")
|
||||
internal static let th = ImageAsset(name: "flags/th")
|
||||
internal static let tj = ImageAsset(name: "flags/tj")
|
||||
internal static let tk = ImageAsset(name: "flags/tk")
|
||||
internal static let tl = ImageAsset(name: "flags/tl")
|
||||
internal static let tm = ImageAsset(name: "flags/tm")
|
||||
internal static let tn = ImageAsset(name: "flags/tn")
|
||||
internal static let to = ImageAsset(name: "flags/to")
|
||||
internal static let tr = ImageAsset(name: "flags/tr")
|
||||
internal static let tt = ImageAsset(name: "flags/tt")
|
||||
internal static let tv = ImageAsset(name: "flags/tv")
|
||||
internal static let tw = ImageAsset(name: "flags/tw")
|
||||
internal static let tz = ImageAsset(name: "flags/tz")
|
||||
internal static let ua = ImageAsset(name: "flags/ua")
|
||||
internal static let ug = ImageAsset(name: "flags/ug")
|
||||
internal static let um = ImageAsset(name: "flags/um")
|
||||
internal static let un = ImageAsset(name: "flags/un")
|
||||
internal static let us = ImageAsset(name: "flags/us")
|
||||
internal static let uy = ImageAsset(name: "flags/uy")
|
||||
internal static let uz = ImageAsset(name: "flags/uz")
|
||||
internal static let va = ImageAsset(name: "flags/va")
|
||||
internal static let vc = ImageAsset(name: "flags/vc")
|
||||
internal static let ve = ImageAsset(name: "flags/ve")
|
||||
internal static let vg = ImageAsset(name: "flags/vg")
|
||||
internal static let vi = ImageAsset(name: "flags/vi")
|
||||
internal static let vn = ImageAsset(name: "flags/vn")
|
||||
internal static let vu = ImageAsset(name: "flags/vu")
|
||||
internal static let wf = ImageAsset(name: "flags/wf")
|
||||
internal static let ws = ImageAsset(name: "flags/ws")
|
||||
internal static let xk = ImageAsset(name: "flags/xk")
|
||||
internal static let ye = ImageAsset(name: "flags/ye")
|
||||
internal static let yt = ImageAsset(name: "flags/yt")
|
||||
internal static let za = ImageAsset(name: "flags/za")
|
||||
internal static let zm = ImageAsset(name: "flags/zm")
|
||||
internal static let zw = ImageAsset(name: "flags/zw")
|
||||
}
|
||||
}
|
||||
internal enum Providers {
|
||||
internal enum Providers {
|
||||
internal static let hideme = ImageAsset(name: "providers/hideme")
|
||||
internal static let mullvad = ImageAsset(name: "providers/mullvad")
|
||||
internal static let nordvpn = ImageAsset(name: "providers/nordvpn")
|
||||
internal static let oeck = ImageAsset(name: "providers/oeck")
|
||||
internal static let pia = ImageAsset(name: "providers/pia")
|
||||
internal static let placeholder = ImageAsset(name: "providers/placeholder")
|
||||
internal static let protonvpn = ImageAsset(name: "providers/protonvpn")
|
||||
internal static let surfshark = ImageAsset(name: "providers/surfshark")
|
||||
internal static let torguard = ImageAsset(name: "providers/torguard")
|
||||
internal static let tunnelbear = ImageAsset(name: "providers/tunnelbear")
|
||||
internal static let vyprvpn = ImageAsset(name: "providers/vyprvpn")
|
||||
internal static let windscribe = ImageAsset(name: "providers/windscribe")
|
||||
}
|
||||
}
|
||||
}
|
||||
// swiftlint:enable identifier_name line_length nesting type_body_length type_name
|
||||
|
||||
// MARK: - Implementation Details
|
||||
|
||||
internal final class ColorAsset {
|
||||
internal fileprivate(set) var name: String
|
||||
|
||||
#if os(macOS)
|
||||
internal typealias Color = NSColor
|
||||
#elseif os(iOS) || os(tvOS) || os(watchOS)
|
||||
internal typealias Color = UIColor
|
||||
#endif
|
||||
|
||||
@available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *)
|
||||
internal private(set) lazy var color: Color = Color(asset: self)
|
||||
|
||||
#if os(iOS) || os(tvOS)
|
||||
@available(iOS 11.0, tvOS 11.0, *)
|
||||
internal func color(compatibleWith traitCollection: UITraitCollection) -> Color {
|
||||
let bundle = BundleToken.bundle
|
||||
guard let color = Color(named: name, in: bundle, compatibleWith: traitCollection) else {
|
||||
fatalError("Unable to load color asset named \(name).")
|
||||
}
|
||||
return color
|
||||
}
|
||||
#endif
|
||||
|
||||
fileprivate init(name: String) {
|
||||
self.name = name
|
||||
}
|
||||
}
|
||||
|
||||
internal extension ColorAsset.Color {
|
||||
@available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *)
|
||||
convenience init!(asset: ColorAsset) {
|
||||
let bundle = BundleToken.bundle
|
||||
#if os(iOS) || os(tvOS)
|
||||
self.init(named: asset.name, in: bundle, compatibleWith: nil)
|
||||
#elseif os(macOS)
|
||||
self.init(named: NSColor.Name(asset.name), bundle: bundle)
|
||||
#elseif os(watchOS)
|
||||
self.init(named: asset.name)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
internal struct ImageAsset {
|
||||
internal fileprivate(set) var name: String
|
||||
|
||||
#if os(macOS)
|
||||
internal typealias Image = NSImage
|
||||
#elseif os(iOS) || os(tvOS) || os(watchOS)
|
||||
internal typealias Image = UIImage
|
||||
#endif
|
||||
|
||||
@available(iOS 8.0, tvOS 9.0, watchOS 2.0, macOS 10.7, *)
|
||||
internal var image: Image {
|
||||
let bundle = BundleToken.bundle
|
||||
#if os(iOS) || os(tvOS)
|
||||
let image = Image(named: name, in: bundle, compatibleWith: nil)
|
||||
#elseif os(macOS)
|
||||
let name = NSImage.Name(self.name)
|
||||
let image = (bundle == .main) ? NSImage(named: name) : bundle.image(forResource: name)
|
||||
#elseif os(watchOS)
|
||||
let image = Image(named: name)
|
||||
#endif
|
||||
guard let result = image else {
|
||||
fatalError("Unable to load image asset named \(name).")
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
#if os(iOS) || os(tvOS)
|
||||
@available(iOS 8.0, tvOS 9.0, *)
|
||||
internal func image(compatibleWith traitCollection: UITraitCollection) -> Image {
|
||||
let bundle = BundleToken.bundle
|
||||
guard let result = Image(named: name, in: bundle, compatibleWith: traitCollection) else {
|
||||
fatalError("Unable to load image asset named \(name).")
|
||||
}
|
||||
return result
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
internal extension ImageAsset.Image {
|
||||
@available(iOS 8.0, tvOS 9.0, watchOS 2.0, *)
|
||||
@available(macOS, deprecated,
|
||||
message: "This initializer is unsafe on macOS, please use the ImageAsset.image property")
|
||||
convenience init!(asset: ImageAsset) {
|
||||
#if os(iOS) || os(tvOS)
|
||||
let bundle = BundleToken.bundle
|
||||
self.init(named: asset.name, in: bundle, compatibleWith: nil)
|
||||
#elseif os(macOS)
|
||||
self.init(named: NSImage.Name(asset.name))
|
||||
#elseif os(watchOS)
|
||||
self.init(named: asset.name)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:disable convenience_type
|
||||
private final class BundleToken {
|
||||
static let bundle: Bundle = {
|
||||
#if SWIFT_PACKAGE
|
||||
return Bundle.module
|
||||
#else
|
||||
return Bundle(for: BundleToken.self)
|
||||
#endif
|
||||
}()
|
||||
}
|
||||
// swiftlint:enable convenience_type
|
|
@ -0,0 +1,394 @@
|
|||
//
|
||||
// Theme.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 2/24/22.
|
||||
// Copyright (c) 2022 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import PassepartoutCore
|
||||
|
||||
extension Color {
|
||||
init(red: Double, green: Double, blue: Double, brightness: Double) {
|
||||
self.init(
|
||||
red: red * brightness,
|
||||
green: green * brightness,
|
||||
blue: blue * brightness
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension View {
|
||||
|
||||
@available(iOS 14, *)
|
||||
func themeConfigureNavigationBarAppearance() {
|
||||
let navBackgroundColor = Asset.Assets.primaryColor.color
|
||||
let titleAttributes: [NSAttributedString.Key: Any] = [
|
||||
.foregroundColor: Asset.Assets.lightTextColor.color
|
||||
]
|
||||
|
||||
let navBarAppearance = UINavigationBarAppearance()
|
||||
navBarAppearance.configureWithOpaqueBackground()
|
||||
navBarAppearance.backgroundColor = navBackgroundColor
|
||||
navBarAppearance.titleTextAttributes = titleAttributes
|
||||
navBarAppearance.largeTitleTextAttributes = titleAttributes
|
||||
|
||||
let navBar = UINavigationBar.appearance()
|
||||
navBar.standardAppearance = navBarAppearance
|
||||
navBar.compactAppearance = navBarAppearance
|
||||
navBar.scrollEdgeAppearance = navBarAppearance
|
||||
|
||||
// UITableView.appearance().backgroundColor = .clear
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
var themeIdiom: UIUserInterfaceIdiom {
|
||||
UIDevice.current.userInterfaceIdiom
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Styles
|
||||
|
||||
extension View {
|
||||
func themeGlobal() -> some View {
|
||||
let color = themeAccentColor
|
||||
return accentColor(color)
|
||||
.toggleStyle(SwitchToggleStyle(tint: color))
|
||||
.listStyle(.insetGrouped)
|
||||
.themeNavigationViewStyle()
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func themeNavigationViewStyle() -> some View {
|
||||
switch UIDevice.current.userInterfaceIdiom {
|
||||
case .phone:
|
||||
navigationViewStyle(.stack)
|
||||
|
||||
default:
|
||||
navigationViewStyle(.automatic)
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func themePrimaryView() -> some View {
|
||||
switch UIDevice.current.userInterfaceIdiom {
|
||||
case .phone:
|
||||
navigationBarTitleDisplayMode(.large)
|
||||
|
||||
default:
|
||||
themeSecondaryView()
|
||||
}
|
||||
}
|
||||
|
||||
func themeSecondaryView() -> some View {
|
||||
navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
|
||||
func themeLongText() -> some View {
|
||||
lineLimit(1)
|
||||
.truncationMode(.middle)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Colors
|
||||
|
||||
extension View {
|
||||
var themeAccentColor: Color {
|
||||
Color(Asset.Assets.accentColor.color)
|
||||
}
|
||||
|
||||
var themePrimaryBackgroundColor: Color {
|
||||
Color(Asset.Assets.primaryColor.color)
|
||||
}
|
||||
|
||||
var themePrimaryBackground: some View {
|
||||
themePrimaryBackgroundColor
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
|
||||
var themeSecondaryColor: Color {
|
||||
.secondary
|
||||
}
|
||||
|
||||
var themeLightTextColor: Color {
|
||||
Color(Asset.Assets.lightTextColor.color)
|
||||
}
|
||||
|
||||
var themeErrorColor: Color {
|
||||
.red
|
||||
}
|
||||
|
||||
private func themeColor(_ string: String?, validator: (String) throws -> Void) -> Color? {
|
||||
guard let string = string else {
|
||||
return nil
|
||||
}
|
||||
do {
|
||||
try validator(string)
|
||||
return nil
|
||||
} catch {
|
||||
return themeErrorColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Fonts
|
||||
|
||||
extension View {
|
||||
func themeDebugLogFont() -> some View {
|
||||
font(.system(size: 13, weight: .medium, design: .monospaced))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Images
|
||||
|
||||
extension View {
|
||||
var themeAssetsLogoImage: String {
|
||||
"logo"
|
||||
}
|
||||
|
||||
func themeAssetsProviderImage(_ providerName: ProviderName) -> String {
|
||||
"providers/\(providerName)"
|
||||
}
|
||||
|
||||
func themeAssetsCountryImage(_ countryCode: String) -> String {
|
||||
"flags/\(countryCode.lowercased())"
|
||||
}
|
||||
|
||||
var themeHostImage: String {
|
||||
"folder.fill"
|
||||
}
|
||||
|
||||
var themeProviderImage: String {
|
||||
"externaldrive.connected.to.line.below.fill"
|
||||
}
|
||||
|
||||
var themeAddProfileImage: String {
|
||||
"plus"
|
||||
}
|
||||
|
||||
var themeCheckmarkImage: String {
|
||||
"checkmark"
|
||||
}
|
||||
|
||||
var themeStatusImage: String {
|
||||
"network"
|
||||
}
|
||||
|
||||
var themeShortcutsImage: String {
|
||||
"mic.fill"
|
||||
}
|
||||
|
||||
var themeDonateImage: String {
|
||||
"giftcard.fill"
|
||||
}
|
||||
|
||||
var themeRedditImage: String {
|
||||
"person.3.fill"
|
||||
}
|
||||
|
||||
var themeWriteReviewImage: String {
|
||||
"heart.fill"
|
||||
}
|
||||
|
||||
var themeAboutImage: String {
|
||||
"info.circle"
|
||||
}
|
||||
|
||||
var themeDeleteImage: String {
|
||||
"trash.fill"
|
||||
}
|
||||
|
||||
var themeRenameProfileImage: String {
|
||||
"highlighter"
|
||||
// "character.cursor.ibeam"
|
||||
}
|
||||
|
||||
var themeVPNProtocolImage: String {
|
||||
"bolt.fill"
|
||||
// "waveform.path.ecg"
|
||||
// "message.and.waveform.fill"
|
||||
// "pc"
|
||||
// "captions.bubble.fill"
|
||||
}
|
||||
|
||||
var themeEndpointImage: String {
|
||||
"link"
|
||||
}
|
||||
|
||||
var themeAccountImage: String {
|
||||
"person.fill"
|
||||
}
|
||||
|
||||
var themeProviderLocationImage: String {
|
||||
"location.fill"
|
||||
}
|
||||
|
||||
var themeProviderPresetImage: String {
|
||||
"slider.horizontal.3"
|
||||
}
|
||||
|
||||
var themeProviderRefreshImage: String {
|
||||
"arrow.clockwise"
|
||||
}
|
||||
|
||||
var themeNetworkSettingsImage: String {
|
||||
// "network"
|
||||
"globe"
|
||||
}
|
||||
|
||||
var themeOnDemandImage: String {
|
||||
"wifi"
|
||||
}
|
||||
|
||||
var themeDiagnosticsImage: String {
|
||||
"bandage.fill"
|
||||
}
|
||||
|
||||
var themeFAQImage: String {
|
||||
"questionmark.diamond.fill"
|
||||
}
|
||||
|
||||
var themeConceilImage: String {
|
||||
"eye.slash.fill"
|
||||
}
|
||||
|
||||
var themeRevealImage: String {
|
||||
"eye.fill"
|
||||
}
|
||||
|
||||
var themeShareImage: String {
|
||||
"square.and.arrow.up"
|
||||
}
|
||||
|
||||
func themeFavoritesImage(_ active: Bool) -> String {
|
||||
active ? "bookmark.fill" : "bookmark"
|
||||
}
|
||||
|
||||
func themeFavoriteActionImage(_ doFavorite: Bool) -> String {
|
||||
doFavorite ? "bookmark" : "bookmark.slash.fill"
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
var asAssetImage: Image {
|
||||
Image(self)
|
||||
}
|
||||
|
||||
var asSystemImage: Image {
|
||||
Image(systemName: self)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Shortcuts
|
||||
|
||||
extension View {
|
||||
func themeSaveButtonLabel() -> some View {
|
||||
// themeCheckmarkImage.asSystemImage
|
||||
Text(L10n.Global.Strings.save)
|
||||
}
|
||||
|
||||
func themeDoneButtonLabel() -> some View {
|
||||
// themeCheckmarkImage.asSystemImage
|
||||
Text(L10n.Global.Strings.ok)
|
||||
}
|
||||
|
||||
func themeTextPicker<T: Hashable>(_ title: String, selection: Binding<T>, values: [T], description: @escaping (T) -> String) -> some View {
|
||||
StyledPicker(title: title, selection: selection, values: values) {
|
||||
Text(description($0))
|
||||
} selectionLabel: {
|
||||
Text(description($0))
|
||||
.foregroundColor(themeSecondaryColor)
|
||||
} listStyle: {
|
||||
.insetGrouped
|
||||
}
|
||||
}
|
||||
|
||||
func themeLongContentLink(_ title: String, content: Binding<String>, withPreview preview: String? = nil) -> some View {
|
||||
LongContentLink(title, content: content, preview: preview) {
|
||||
Text(preview != nil ? $0 : "")
|
||||
.foregroundColor(themeSecondaryColor)
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func themeErrorMessage(_ message: String?) -> some View {
|
||||
if let message = message {
|
||||
if message.last != "." {
|
||||
Text("\(message).")
|
||||
.foregroundColor(themeErrorColor)
|
||||
} else {
|
||||
Text(message)
|
||||
.foregroundColor(themeErrorColor)
|
||||
}
|
||||
} else {
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Validation
|
||||
|
||||
extension View {
|
||||
func themeURL(_ urlString: String?) -> some View {
|
||||
themeValidating(urlString, validator: Validators.url)
|
||||
.keyboardType(.asciiCapable)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
}
|
||||
|
||||
func themeIPAddress(_ ipAddress: String?) -> some View {
|
||||
themeValidating(ipAddress, validator: Validators.ipAddress)
|
||||
.keyboardType(.numbersAndPunctuation)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
}
|
||||
|
||||
func themeSocketPort() -> some View {
|
||||
keyboardType(.numberPad)
|
||||
}
|
||||
|
||||
func themeDomainName(_ domainName: String?) -> some View {
|
||||
themeValidating(domainName, validator: Validators.domainName)
|
||||
.keyboardType(.asciiCapable)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
}
|
||||
|
||||
func themeSSID(_ text: String?) -> some View {
|
||||
themeValidating(text, validator: Validators.notEmpty)
|
||||
.keyboardType(.asciiCapable)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
}
|
||||
|
||||
private func themeValidating(_ string: String?, validator: (String) throws -> Void) -> some View {
|
||||
foregroundColor(themeColor(string, validator: validator))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Hacks
|
||||
|
||||
extension View {
|
||||
// @available(*, deprecated, message: "mitigates multiline text truncation (1.0 does not work though)")
|
||||
func xxxThemeTruncation() -> some View {
|
||||
minimumScaleFactor(0.5)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// DebugLog+Constants.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 3/24/22.
|
||||
// Copyright (c) 2022 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import PassepartoutCore
|
||||
|
||||
extension DebugLog {
|
||||
func decoratedString() -> String {
|
||||
return decoratedString(Constants.Global.appName, Constants.Global.appVersionString)
|
||||
}
|
||||
|
||||
func decoratedData() -> Data {
|
||||
return decoratedData(Constants.Global.appName, Constants.Global.appVersionString)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
//
|
||||
// PassepartoutProviders+Extensions.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 11/4/21.
|
||||
// Copyright (c) 2022 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import PassepartoutCore
|
||||
|
||||
extension ProviderMetadata: Identifiable, Comparable, Hashable {
|
||||
public var id: String {
|
||||
return name
|
||||
}
|
||||
|
||||
public static func ==(lhs: Self, rhs: Self) -> Bool {
|
||||
return lhs.name == rhs.name
|
||||
}
|
||||
|
||||
public static func <(lhs: Self, rhs: Self) -> Bool {
|
||||
return lhs.fullName.lowercased() < rhs.fullName.lowercased()
|
||||
}
|
||||
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(name)
|
||||
}
|
||||
}
|
||||
|
||||
extension ProviderCategory: Comparable {
|
||||
public static func ==(lhs: Self, rhs: Self) -> Bool {
|
||||
return lhs.name.lowercased() == rhs.name.lowercased()
|
||||
}
|
||||
|
||||
public static func <(lhs: Self, rhs: Self) -> Bool {
|
||||
return lhs.name.lowercased() < rhs.name.lowercased()
|
||||
}
|
||||
}
|
||||
|
||||
extension ProviderLocation: Comparable {
|
||||
public static func ==(lhs: Self, rhs: Self) -> Bool {
|
||||
return lhs.countryCode == rhs.countryCode
|
||||
}
|
||||
|
||||
public static func <(lhs: Self, rhs: Self) -> Bool {
|
||||
return lhs.localizedCountry < rhs.localizedCountry
|
||||
}
|
||||
}
|
||||
|
||||
extension ProviderServer: Comparable {
|
||||
public static func ==(lhs: Self, rhs: Self) -> Bool {
|
||||
return lhs.id == rhs.id
|
||||
}
|
||||
|
||||
// "Default" comes first
|
||||
// sorts by serverIndex first, see ProtonVPN > Germany (currently "Frankfurt #203" comes before "#3")
|
||||
public static func <(lhs: Self, rhs: Self) -> Bool {
|
||||
if let li = lhs.serverIndex, let ri = rhs.serverIndex {
|
||||
return li < ri
|
||||
}
|
||||
return lhs.localizedDetails < rhs.localizedDetails
|
||||
}
|
||||
}
|
||||
|
||||
extension ProviderServer.Preset: Comparable {
|
||||
public static func ==(lhs: Self, rhs: Self) -> Bool {
|
||||
return lhs.name == rhs.name
|
||||
}
|
||||
|
||||
public static func <(lhs: Self, rhs: Self) -> Bool {
|
||||
return lhs.name < rhs.name
|
||||
}
|
||||
}
|
||||
|
||||
extension ProviderMetadata {
|
||||
var openVPNGuidanceURL: URL? {
|
||||
guard let string = Constants.URLs.openVPNGuidances[name] else {
|
||||
return nil
|
||||
}
|
||||
return URL(string: string)
|
||||
}
|
||||
|
||||
var referralURL: URL? {
|
||||
guard let string = Constants.URLs.referrals[name] else {
|
||||
return nil
|
||||
}
|
||||
return URL(string: string)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// TunnelKit+Identifiable.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 3/12/22.
|
||||
// Copyright (c) 2022 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import TunnelKitCore
|
||||
|
||||
extension Endpoint: Identifiable {
|
||||
public var id: String {
|
||||
return "\(address):\(proto.port):\(proto.socketType.rawValue)"
|
||||
}
|
||||
}
|
||||
|
||||
extension IPv4Settings.Route: Identifiable {
|
||||
public var id: String {
|
||||
return "\(destination):\(mask):\(gateway)"
|
||||
}
|
||||
}
|
||||
|
||||
extension IPv6Settings.Route: Identifiable {
|
||||
public var id: String {
|
||||
return "\(destination):\(prefixLength):\(gateway)"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// VPNProtocolType+FileExtensions.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 4/7/22.
|
||||
// Copyright (c) 2022 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import PassepartoutCore
|
||||
|
||||
extension VPNProtocolType {
|
||||
static let knownFileExtensions: [String] = {
|
||||
let protos: [Self] = [.openVPN, .wireGuard]
|
||||
return protos.map(\.fileExtension)
|
||||
}()
|
||||
|
||||
var fileExtension: String {
|
||||
switch self {
|
||||
case .openVPN:
|
||||
return "ovpn"
|
||||
|
||||
case .wireGuard:
|
||||
return "wg"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,5 +2,8 @@
|
|||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"provides-namespace" : true
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 960 B After Width: | Height: | Size: 960 B |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 182 B After Width: | Height: | Size: 182 B |
Before Width: | Height: | Size: 216 B After Width: | Height: | Size: 216 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 164 B After Width: | Height: | Size: 164 B |
Before Width: | Height: | Size: 187 B After Width: | Height: | Size: 187 B |
Before Width: | Height: | Size: 785 B After Width: | Height: | Size: 785 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 918 B After Width: | Height: | Size: 918 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 565 B After Width: | Height: | Size: 565 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 175 B After Width: | Height: | Size: 175 B |
Before Width: | Height: | Size: 199 B After Width: | Height: | Size: 199 B |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 631 B After Width: | Height: | Size: 631 B |
Before Width: | Height: | Size: 909 B After Width: | Height: | Size: 909 B |
Before Width: | Height: | Size: 357 B After Width: | Height: | Size: 357 B |
Before Width: | Height: | Size: 414 B After Width: | Height: | Size: 414 B |
Before Width: | Height: | Size: 687 B After Width: | Height: | Size: 687 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 695 B After Width: | Height: | Size: 695 B |
Before Width: | Height: | Size: 997 B After Width: | Height: | Size: 997 B |
Before Width: | Height: | Size: 738 B After Width: | Height: | Size: 738 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 185 B After Width: | Height: | Size: 185 B |
Before Width: | Height: | Size: 191 B After Width: | Height: | Size: 191 B |