Import v3 code (#597)

Closes #565
This commit is contained in:
Davide 2024-09-23 15:02:26 +02:00 committed by GitHub
parent 6bfda3487b
commit 6cc86e8668
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2336 changed files with 15005 additions and 50167 deletions

View File

@ -1 +0,0 @@
1130

View File

@ -1 +0,0 @@
3630

View File

@ -1,23 +0,0 @@
name: "Create custom keychain"
inputs:
name:
description: "Keychain name"
required: true
password:
description: "Keychain password"
required: true
runs:
using: "composite"
steps:
- shell: bash
env:
KEYCHAIN_NAME: ${{ inputs.name }}
KEYCHAIN_PASSWORD: ${{ inputs.password }}
run: |
bundle exec fastlane run create_keychain unlock:true lock_after_timeout:false timeout:6000
- uses: webiny/action-post-run@3.0.0
env:
KEYCHAIN_NAME: ${{ inputs.name }}
with:
run: |
bundle exec fastlane run delete_keychain

View File

@ -1,93 +0,0 @@
name: Private Beta
on:
workflow_dispatch:
inputs:
build_number:
description: "Build number"
required: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY }}
FASTLANE_USERNAME: ${{ secrets.FASTLANE_USERNAME }}
FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }}
BUILD_NUMBER: ${{ github.event.inputs.build_number }}
jobs:
build_upload:
name: Distribute Private Beta
runs-on: macos-13
environment:
name: private_beta
strategy:
fail-fast: true
matrix:
name: ["iOS", "macOS"]
include:
- name: "iOS"
platform: "ios"
- name: "macOS"
platform: "mac"
env:
PLATFORM: ${{ matrix.platform }}
MATCH_USERNAME: ${{ secrets.MATCH_USERNAME }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_GIT_URL: ${{ secrets.MATCH_GIT_URL }}
MATCH_GIT_PRIVATE_KEY: ${{ secrets.MATCH_GIT_PRIVATE_KEY }}
MATCH_KEYCHAIN_NAME: ${{ secrets.MATCH_KEYCHAIN_NAME }}
MATCH_KEYCHAIN_PASSWORD: ${{ secrets.MATCH_KEYCHAIN_PASSWORD }}
GYM_OUTPUT_DIRECTORY: "dist/${{ matrix.platform }}"
steps:
- uses: actions/checkout@v3
with:
submodules: true
- uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- uses: actions/setup-go@v4
with:
go-version: "^1.17"
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: "15.1"
- name: Create keychain
uses: ./.github/actions/create-keychain
with:
name: ${{ env.MATCH_KEYCHAIN_NAME }}
password: ${{ env.MATCH_KEYCHAIN_PASSWORD }}
- name: Preinstall certificates (SSH)
run: |
scripts/ci/recognize-match-hostname.sh
bundle exec fastlane --env ${{ matrix.platform }} match development
- name: Tweak build
env:
PLIST_COMMAND: "Add :com.algoritmico.Passepartout.config:app_type integer 2"
PLIST_PATH: "Passepartout/App/Info.plist"
run: |
ci/set-build.sh $BUILD_NUMBER
/usr/libexec/PlistBuddy -c "$PLIST_COMMAND" "$PLIST_PATH"
- name: Build ${{ matrix.name }} app
timeout-minutes: 15
run: |
bundle exec fastlane --env $PLATFORM,beta test_and_build_app test:false ensure_clean:false
- name: Submit to TestFlight
env:
PILOT_USERNAME: ${{ secrets.PILOT_USERNAME }}
PILOT_GROUPS: ${{ secrets.PILOT_GROUPS }}
PILOT_BETA_APP_FEEDBACK: ${{ secrets.PILOT_BETA_APP_FEEDBACK }}
PILOT_BETA_APP_REVIEW_INFO: ${{ secrets.PILOT_BETA_APP_REVIEW_INFO }}
PILOT_NOTIFY_EXTERNAL_TESTERS: ${{ secrets.PILOT_NOTIFY_EXTERNAL_TESTERS }}
CHANGELOG_PREFACE: ${{ secrets.CHANGELOG_PREFACE }}
run: |
if [ $PLATFORM == "ios" ]; then
export PILOT_IPA="$GYM_OUTPUT_DIRECTORY/Passepartout.ipa"
else
export PILOT_PKG="$GYM_OUTPUT_DIRECTORY/Passepartout.pkg"
fi
export PILOT_CHANGELOG=`ci/build-changelog.sh $PLATFORM`
bundle exec fastlane --env $PLATFORM,beta run pilot
- name: Tag beta
run: |
APP_VERSION=`ci/version-number.sh ios`
git tag "v$APP_VERSION-pb$BUILD_NUMBER" && git push --tags

View File

@ -2,10 +2,8 @@ name: Release
on: on:
push: push:
branches: tags:
- "master" - "builds/*"
paths:
- ".beta-build"
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -13,172 +11,47 @@ env:
FASTLANE_USERNAME: ${{ secrets.FASTLANE_USERNAME }} FASTLANE_USERNAME: ${{ secrets.FASTLANE_USERNAME }}
FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }} FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
build_upload: build_upload:
name: Upload to ASC name: Upload to ASC
runs-on: macos-13 runs-on: macos-14
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
name: ["iOS", "macOS", "tvOS"] #name: ["iOS", "macOS", "tvOS"]
name: ["iOS", "macOS"]
include: include:
- name: "iOS" - name: "iOS"
platform: "ios" platform: "ios"
use_version: true
- name: "macOS" - name: "macOS"
platform: "mac" platform: "macos"
- name: "tvOS" #- name: "tvOS"
platform: "tvos" # platform: "tvos"
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Access private repositories
env:
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
run: |
git config --global url.https://$ACCESS_TOKEN@github.com/.insteadOf git@github.com:
- name: Upload ${{ matrix.name }} app
id: upload_app
timeout-minutes: 15
env: env:
PLATFORM: ${{ matrix.platform }}
MATCH_USERNAME: ${{ secrets.MATCH_USERNAME }} MATCH_USERNAME: ${{ secrets.MATCH_USERNAME }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_GIT_URL: ${{ secrets.MATCH_GIT_URL }} MATCH_GIT_URL: ${{ secrets.MATCH_GIT_URL }}
MATCH_GIT_PRIVATE_KEY: ${{ secrets.MATCH_GIT_PRIVATE_KEY }} MATCH_GIT_PRIVATE_KEY: ${{ secrets.MATCH_GIT_PRIVATE_KEY }}
GYM_OUTPUT_DIRECTORY: "dist/${{ matrix.platform }}"
steps:
- uses: actions/checkout@v3
with:
submodules: true
- uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- uses: actions/setup-go@v4
with:
go-version: "^1.17"
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: "latest-stable"
- name: Store app version
id: app_version
if: ${{ matrix.use_version }}
run: |
VERSION=`ci/version-number.sh $PLATFORM`
BUILD=`ci/build-number.sh $PLATFORM`
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "build=$BUILD" >> $GITHUB_OUTPUT
- name: Preinstall certificates (SSH)
run: |
scripts/ci/recognize-match-hostname.sh
bundle exec fastlane --env ${{ matrix.platform }} match development
# - name: Run tests
# run: |
# cd PassepartoutLibrary
# swift test
- name: Build ${{ matrix.name }} app
timeout-minutes: 15
run: |
bundle exec fastlane --env $PLATFORM,beta test_and_build_app test:false
- name: Submit to TestFlight
env:
PILOT_USERNAME: ${{ secrets.PILOT_USERNAME }}
PILOT_GROUPS: ${{ secrets.PILOT_GROUPS }}
PILOT_BETA_APP_FEEDBACK: ${{ secrets.PILOT_BETA_APP_FEEDBACK }} PILOT_BETA_APP_FEEDBACK: ${{ secrets.PILOT_BETA_APP_FEEDBACK }}
PILOT_BETA_APP_REVIEW_INFO: ${{ secrets.PILOT_BETA_APP_REVIEW_INFO }} PILOT_BETA_APP_REVIEW_INFO: ${{ secrets.PILOT_BETA_APP_REVIEW_INFO }}
PILOT_NOTIFY_EXTERNAL_TESTERS: ${{ secrets.PILOT_NOTIFY_EXTERNAL_TESTERS }} PILOT_GROUPS: ${{ vars.PILOT_GROUPS }}
CHANGELOG_PREFACE: ${{ secrets.CHANGELOG_PREFACE }}
run: | run: |
if [ $PLATFORM == "mac" ]; then ci/recognize-match-hostname.sh
export PILOT_PKG="$GYM_OUTPUT_DIRECTORY/Passepartout.pkg" bundle exec fastlane --env ${{ matrix.platform }} beta
else
export PILOT_IPA="$GYM_OUTPUT_DIRECTORY/Passepartout.ipa"
fi
export PILOT_CHANGELOG=`ci/build-changelog.sh $PLATFORM`
bundle exec fastlane --env $PLATFORM,beta run pilot
outputs:
version: ${{ steps.app_version.outputs.version }}
build: ${{ steps.app_version.outputs.build }}
distribute_public_beta:
name: Distribute Public Beta
runs-on: ubuntu-latest
needs: build_upload
environment:
name: public_beta
url: "https://testflight.apple.com/join/K71mtLjZ"
env:
PILOT_APP_VERSION: ${{ needs.build_upload.outputs.version }}
PILOT_BUILD_NUMBER: ${{ needs.build_upload.outputs.build }}
PILOT_USERNAME: ${{ secrets.PILOT_USERNAME }}
PILOT_GROUPS: ${{ secrets.PILOT_GROUPS }}
PILOT_NOTIFY_EXTERNAL_TESTERS: ${{ secrets.PILOT_NOTIFY_EXTERNAL_TESTERS }}
PILOT_DISTRIBUTE_ONLY: true
steps:
- uses: actions/checkout@v3
with:
submodules: true
- uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Publish on TestFlight (iOS)
run: |
bundle exec fastlane --env ios,beta run pilot
- name: Publish on TestFlight (macOS)
run: |
bundle exec fastlane --env mac,beta run pilot
- name: Publish on TestFlight (tvOS)
run: |
bundle exec fastlane --env tvos,beta run pilot
submit_for_app_review:
name: Submit to App Review
runs-on: ubuntu-latest
needs: build_upload
environment:
name: app_review
env:
DELIVER_USERNAME: ${{ secrets.DELIVER_USERNAME }}
DELIVER_APP_VERSION: ${{ needs.build_upload.outputs.version }}
DELIVER_BUILD_NUMBER: ${{ needs.build_upload.outputs.build }}
DELIVER_FORCE: true
steps:
- uses: actions/checkout@v3
with:
submodules: true
- uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Submit for App Review (iOS)
run: |
bundle exec fastlane --env ios deliver_review add_id_info_uses_idfa:false
- name: Submit for App Review (macOS)
run: |
bundle exec fastlane --env mac deliver_review add_id_info_uses_idfa:false
- name: Submit for App Review (tvOS)
run: |
bundle exec fastlane --env tvos deliver_review add_id_info_uses_idfa:false
publish_to_app_store:
name: Publish to App Store
runs-on: ubuntu-latest
needs: [build_upload, submit_for_app_review]
environment:
name: app_store
env:
TAG_NAME: ${{ needs.build_upload.outputs.version }}
RELEASE_NOTES: release-notes.txt
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@v5
with:
gpg_private_key: ${{ secrets.GPG_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
git_user_signingkey: true
git_commit_gpgsign: true
git_tag_gpgsign: true
git_push_gpgsign: false
- name: Tag release
run: |
scripts/ci/tag-release.sh $TAG_NAME
git push --tags
- name: Assemble notes
run: |
scripts/ci/release-notes.sh $TAG_NAME >$RELEASE_NOTES
- name: Publish release
uses: softprops/action-gh-release@v1
with:
tag_name: "v${{ env.TAG_NAME }}"
body_path: ${{ env.RELEASE_NOTES }}
draft: true
files: |
${{ env.RELEASE_NOTES }}

View File

@ -4,36 +4,35 @@ on:
pull_request: pull_request:
types: [ opened, synchronize ] types: [ opened, synchronize ]
paths-ignore: paths-ignore:
- '.beta-*'
- '.env.*' - '.env.*'
- '**/*.md' - '**/*.md'
- '**/*.sh' - '**/*.sh'
- '**/*.yml' - '**/*.yml'
- 'Passepartout/App/fastlane/**' - 'fastlane/**'
concurrency: concurrency:
group: ${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} cancel-in-progress: true
jobs: jobs:
run_tests: run_tests:
name: Run tests name: Run tests
runs-on: macos-13 runs-on: macos-14
timeout-minutes: 15 timeout-minutes: 15
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with:
submodules: true
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: "15.1"
- uses: ruby/setup-ruby@v1 - uses: ruby/setup-ruby@v1
with: with:
bundler-cache: true bundler-cache: true
- uses: actions/setup-go@v4 - uses: maxim-lobanov/setup-xcode@v1
with: with:
go-version: "^1.17" xcode-version: 15.4
- name: Access private repositories
env:
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
run: |
git config --global url.https://$ACCESS_TOKEN@github.com/.insteadOf git@github.com:
- name: Run tests - name: Run tests
run: | run: |
cd PassepartoutLibrary cd Passepartout/Library
swift test swift test

20
.gitignore vendored
View File

@ -2,21 +2,19 @@
*.swp *.swp
*.pbxuser *.pbxuser
**/xcuserdata **/xcuserdata
Pods
**/fastlane/**/*.html **/fastlane/**/*.html
**/fastlane/README.md **/fastlane/README.md
**/fastlane/report.xml **/fastlane/report.xml
**/fastlane/test_output **/fastlane/test_output
**/fastlane/*/metadata/review_information **/fastlane/*/metadata/review_information
**/fastlane/*/metadata/trade_representative_contact_information **/fastlane/*/metadata/trade_representative_contact_information
dist/
iap/
templates/
.env.secret*
Preview.html
passepartout-translations.zip
default.profraw
asc-key.json
.bundle
vendor/
build/ build/
dist/
/iap
templates/
vendor/
Preview.html
default.profraw
.build
.bundle
.env.secret*

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "PassepartoutLibrary/Sources/PassepartoutServices/API"]
path = PassepartoutLibrary/Sources/PassepartoutProvidersImpl/API
url = https://github.com/passepartoutvpn/api

View File

@ -1,7 +1,9 @@
included: included:
- Passepartout - Passepartout/App
- PassepartoutLibrary/Sources - Passepartout/Library/Sources
- PassepartoutLibrary/Tests - Passepartout/Library/Tests
- Passepartout/Shared
- Passepartout/Tunnel
analyzer_rules: analyzer_rules:
- unused_declaration - unused_declaration
- unused_import - unused_import
@ -14,5 +16,6 @@ disabled_rules:
- function_body_length - function_body_length
- identifier_name - identifier_name
- line_length - line_length
- inclusive_language
- nesting - nesting
- todo - todo

1
API
View File

@ -1 +0,0 @@
PassepartoutLibrary/Sources/PassepartoutProvidersImpl/API/

View File

@ -1,520 +0,0 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 1.18.0 (2022-02-15)
### Added
- Handle `--keepalive` option.
### Changed
- Release app in the open via GitHub Actions.
### Fixed
- Trim whitespaces in text fields.
## 1.17.2 (2021-11-30)
### Changed
- Revert to OpenSSL.
### Fixed
- "TLS failed" with some certificates (e.g. Let's Encrypt).
- Newer infrastructure discarded over bundle.
## 1.17.0 (2021-11-16)
### Changed
- Replace OpenSSL with BoringSSL.
- Restrict support to secure TLS algorithms (security level).
- Allow Oeck provider without any purchase.
### Fixed
- iOS 15: Navigation bar has broken appearance.
- Missing account guidance footer in some providers.
- Files imported via Music (iTunes) File Sharing did not show up.
## 1.16.0 (2021-08-09)
### Added
- Support for `--scramble xormask`. [tunnelkit#38](https://github.com/passepartoutvpn/tunnelkit/issues/38)
- Oeck provider.
## 1.15.4 (2021-07-21)
### Added
- SurfShark provider.
- Support for `--compress stub-v2`.
## 1.15.2 (2021-04-17)
### Changed
- Drop Twitch link.
## 1.15.1 (2021-02-14)
### Fixed
- No way to set DNS servers when using DNS over HTTPS. [#171](https://github.com/passepartoutvpn/passepartout-apple/issues/171)
## 1.15.0 (2021-02-09)
### Added
- Support `--data-ciphers` from OpenVPN 2.5. [tunnelkit#193](https://github.com/passepartoutvpn/tunnelkit/issues/193)
- Support DNS over HTTPS/TLS in "Network settings". [#91](https://github.com/passepartoutvpn/passepartout-apple/issues/91)
### Changed
- Drop hosts restriction in free version ("Unlimited hosts").
### Fixed
- Redundant keychain items.
- Keyboard not dismissed in "Network settings".
- "Reset configuration" not working with encrypted configuration files.
- "Update list" locks up in providers.
## 1.14.0 (2021-01-07)
### Added
- Can now copy entries in "Server network".
### Changed
- Rendering of provider infrastructures.
- Default to low MTU (1200) when unspecified.
## 1.13.1 (2021-01-03)
### Fixed
- Losing profiles on upgrade. [#163](https://github.com/passepartoutvpn/passepartout-ios/issues/163)
- Twitch link does not work when Twitch app not installed. [#162](https://github.com/passepartoutvpn/passepartout-ios/issues/162)
## 1.13.0 (2021-01-01)
### Added
- Customize MTU in network settings.
### Changed
- Enter explicit Wi-Fi SSID to trust.
- Use default tunnel MTU rather than 1250.
## 1.12.1 (2020-11-15)
### Added
- Watch me make Passepartout live on Twitch.
## 1.12.0 (2020-10-06)
### Added
- Child Safe VPN provider.
### Changed
- Improved host import flow.
- Use active profile name in iOS settings.
### Fixed
- In-app purchases may not be credited/restored (Radu Ursache). [#153](https://github.com/passepartoutvpn/passepartout-ios/issues/153)
## 1.11.5 (2020-06-23)
### Fixed
- Skip DNS resolution of provider servers without a hostname (e.g. ProtonVPN "Secure Core").
## 1.11.4 (2020-06-03)
### Added
- Customize host endpoint.
### Fixed
- Invisible buttons in document browser. [#145](https://github.com/passepartoutvpn/passepartout-ios/issues/145)
## 1.11.3 (2020-05-21)
### Added
- TorGuard provider (Jorrit Visser). [api-source#5](https://github.com/passepartoutvpn/api-source/issues/5)
### Fixed
- Persistent crash on launch after "Add new provider > Update list".
## 1.11.2 (2020-05-12)
### Changed
- Relax keyboard for host titles.
### Fixed
- In-app purchase unavailable for new providers. [#141](https://github.com/passepartoutvpn/passepartout-ios/issues/141)
- Hosts may be renamed to same title. [#140](https://github.com/passepartoutvpn/passepartout-ios/issues/140)
## 1.11.1 (2020-05-11)
### Added
- Hide.me provider.
## 1.11.0 (2020-04-29)
### Changed
- Allow any character in host profile name. [#26](https://github.com/passepartoutvpn/passepartout-ios/issues/26)
### Fixed
- Programming error in some SoftEther negotiation (Grivus). [tunnelkit#143](https://github.com/passepartoutvpn/tunnelkit/pull/143)
- Default gateway not yet enforced for providers (e.g. TunnelBear). [passepartout-core-apple#4](https://github.com/passepartoutvpn/passepartout-core-apple/pull/4)
- Active profile lost after renaming. [#128](https://github.com/passepartoutvpn/passepartout-ios/issues/128)
- Handle server shutdown/restart (remote `--explicit-exit-notify`). [tunnelkit#131](https://github.com/passepartoutvpn/tunnelkit/issues/131)
- Handle explicit IPv4/IPv6 protocols (`4` or `6` suffix in `--proto`). [tunnelkit#153](https://github.com/passepartoutvpn/tunnelkit/issues/153)
- IPv6 traffic broken on Mojave. [tunnelkit#146](https://github.com/passepartoutvpn/tunnelkit/issues/146), [#169](https://github.com/passepartoutvpn/tunnelkit/pull/169)
- Transient connected state upon connection failure (rob-patchett). [tunnelkit#128](https://github.com/passepartoutvpn/tunnelkit/pull/128)
## 1.10.1 (2019-12-24)
### Fixed
- Provider purchases were not properly recognized/restored. [#124](https://github.com/passepartoutvpn/passepartout-ios/pull/124)
## 1.10.0 (2019-12-19)
### Added
- Dynamic providers, refresh supported list in real time.
- Favorite provider locations. [#118](https://github.com/passepartoutvpn/passepartout-ios/issues/118)
- Polish translations (Piotr Książek).
### Changed
- "Trusted networks" settings are now saved per profile. [#114](https://github.com/passepartoutvpn/passepartout-ios/issues/114)
- Require explicit `--ca` and `--cipher` in .ovpn configuration file.
- Revert fallback to CloudFlare DNS when no servers provided. [#116](https://github.com/passepartoutvpn/passepartout-ios/issues/116)
- German translations (Theodor Tietze).
### Fixed
- Only show pushed server configuration.
- Adjust UI to device text size. [#117](https://github.com/passepartoutvpn/passepartout-ios/pull/117)
- Restore provider flow after purchase.
- Improved some translations.
## 1.9.1 (2019-11-10)
### Changed
- Polish purchase screen.
## 1.9.0 (2019-11-05)
### Added
- Import host via document picker.
- Support for `--ping-restart` (Robert Patchett). [tunnelkit#122](https://github.com/passepartoutvpn/tunnelkit/pull/122)
- Support for proxy auto-configuration URL (ThinkChaos). [tunnelkit#125](https://github.com/passepartoutvpn/tunnelkit/pull/125)
- Disclose server configuration and network settings in Diagnostics. [#101](https://github.com/passepartoutvpn/passepartout-ios/issues/101)
- Support multiple DNS search domains. [tunnelkit#127](https://github.com/passepartoutvpn/tunnelkit/issues/127)
### Changed
- Upgrade project to Xcode 11.
### Fixed
- Cannot enter IP addresses in some localizations. [#103](https://github.com/passepartoutvpn/passepartout-ios/issues/103)
- Cannot easily trust Wi-Fi networks in iOS 13. [#100](https://github.com/passepartoutvpn/passepartout-ios/issues/100)
- Infrastructures not updated in non-English locales.
- Default gateway not enforced for providers (e.g. TunnelBear).
## 1.8.1 (2019-09-15)
### Added
- Chinese (Simplified) translations (OnlyThen). [#95](https://github.com/passepartoutvpn/passepartout-ios/pull/95)
- Support for iOS 13 Dark Mode. [#93](https://github.com/passepartoutvpn/passepartout-ios/issues/93)
### Fixed
- Transparent navigation bar in iPadOS 13.
- Unable to open .ovpn files in iOS 13. [#99](https://github.com/passepartoutvpn/passepartout-ios/issues/99)
- Premature disconnection due to .staleSession error. [tunnelkit#120](https://github.com/passepartoutvpn/tunnelkit/issues/120)
## 1.8.0 (2019-08-01)
### Added
- "Custom DNS" preset for Mullvad. [api-source-mullvad#1](https://github.com/passepartoutvpn/api-source-mullvad/issues/1)
- Change app language from Settings in iOS 13. [#90](https://github.com/passepartoutvpn/passepartout-ios/issues/90)
### Changed
- Disconnect on "No buffer space available" rather than leaving a stale connection (improve later). [tunnelkit#104](https://github.com/passepartoutvpn/tunnelkit/issues/104)
### Fixed
- VPN staying active while it's not. [tunnelkit#106](https://github.com/passepartoutvpn/tunnelkit/issues/106)
- Disconnection on renegotiation. [tunnelkit#105](https://github.com/passepartoutvpn/tunnelkit/issues/105)
- Support third party apps when sending e-mails.
- Refreshed infrastructures are not retained. [passepartout-core-apple#1](https://github.com/passepartoutvpn/passepartout-core-apple/issues/1)
- Portuguese bound to Brazil region.
- German spelling of "Default gateway".
- Some French wording (Joel Gallant).
- Erroneous placeholders in Network Settings (Joel Gallant).
## 1.7.0 (2019-06-02)
### Added
- Dutch translations (Norbert de Vreede). [#81](https://github.com/passepartoutvpn/passepartout-ios/pull/81)
- Greek translations (Konstantinos Koukoulakis).
- French translations (Julien Laniel).
- Spanish translations (Davide De Rosa, Elena Vivó).
- Swedish translations (Henry Gross-Hellsen). [#82](https://github.com/passepartoutvpn/passepartout-ios/pull/82)
## 1.6.1 (2019-05-20)
### Added
- Override network settings. [#77](https://github.com/passepartoutvpn/passepartout-ios/pull/77)
- Support for `--redirect-gateway block-local` (partial). [tunnelkit#81](https://github.com/passepartoutvpn/tunnelkit/issues/81)
- Russian translations (Alexander Korobynikov).
### Changed
- Host compression framing and algorithm are now editable.
### Fixed
- NordVPN double servers not connecting out of the box. [#78](https://github.com/passepartoutvpn/passepartout-ios/issues/78)
- Authentication with OpenVPN AS. [tunnelkit#95](https://github.com/passepartoutvpn/tunnelkit/issues/95)
- TLS failed with some servers. [tunnelkit#97](https://github.com/passepartoutvpn/tunnelkit/issues/97)
## 1.6.0 (2019-05-01)
### Added
- VyprVPN provider. [#72](https://github.com/passepartoutvpn/passepartout-ios/pull/72)
- More infrastructure metadata.
- Portuguese translations (Helder Santana). [#70](https://github.com/passepartoutvpn/passepartout-ios/pull/70)
- German translations (Christian Lederer).
- Russian translations (Alexander Korobynikov).
### Changed
- Do not redirect all traffic to VPN unless `--redirect-gateway` specified. [#71](https://github.com/passepartoutvpn/passepartout-ios/pull/71)
### Fixed
- Fall back to CloudFlare DNS when no servers provided. [tunnelkit#84](https://github.com/passepartoutvpn/tunnelkit/issues/84)
- UDP may disconnect on high speeds. [tunnelkit#87](https://github.com/passepartoutvpn/tunnelkit/issues/87)
- SoftEther connects without VPN icon. [#69](https://github.com/passepartoutvpn/passepartout-ios/issues/69)
- Misleading Mullvad password suggestion. [#75](https://github.com/passepartoutvpn/passepartout-ios/issues/75)
- Leave digest editable despite cipher. [#74](https://github.com/passepartoutvpn/passepartout-ios/issues/74)
- TLS errors with passphrase-protected .ovpn profiles. [tunnelkit#91](https://github.com/passepartoutvpn/tunnelkit/issues/91)
- Issue with DNS-only VPN profiles. [#73](https://github.com/passepartoutvpn/passepartout-ios/issues/73)
## 1.5.0 (2019-04-17)
### Added
- NordVPN provider. [#65](https://github.com/passepartoutvpn/passepartout-ios/pull/65)
- Support for `dhcp-option PROXY_HTTP[S]`. [tunnelkit#74](https://github.com/passepartoutvpn/tunnelkit/issues/74)
### Fixed
- Regression in DNS configuration. [#68](https://github.com/passepartoutvpn/passepartout-ios/issues/68)
- SoftEther timing out. [tunnelkit#67](https://github.com/passepartoutvpn/tunnelkit/issues/67)
- VPN status cell doesn't always enter active profile. [#63](https://github.com/passepartoutvpn/passepartout-ios/issues/63)
- Masking preference not retained. [#64](https://github.com/passepartoutvpn/passepartout-ios/issues/64)
- Issues with very long PUSH_REPLY. [tunnelkit#71](https://github.com/passepartoutvpn/tunnelkit/issues/71)
- Missing app icon in Credits.
## 1.4.0 (2019-04-11)
### Added
- ProtonVPN provider. [#7](https://github.com/passepartoutvpn/passepartout-ios/issues/7)
- Italian translations. [#58](https://github.com/passepartoutvpn/passepartout-ios/pull/58)
- In-app donations.
- Provider logos. [#55](https://github.com/passepartoutvpn/passepartout-ios/pull/55)
- Country flags. [#56](https://github.com/passepartoutvpn/passepartout-ios/pull/56)
- VPN status shortcut, enters active profile on selection.
### Changed
- Automatic protocol defaults to UDP endpoints. [#61](https://github.com/passepartoutvpn/passepartout-ios/pull/61)
- Improved Account screen, footers were hardly tappable.
### Fixed
- Some providers may crash on VPN activation. [#57](https://github.com/passepartoutvpn/passepartout-ios/issues/57)
- Mullvad dying due to ping timeout. [#62](https://github.com/passepartoutvpn/passepartout-ios/issues/62)
- Pushing DOMAIN has no effect. [#48](https://github.com/passepartoutvpn/passepartout-ios/issues/48)
## 1.3.0 (2019-04-03)
### Added
- Windscribe provider. [#39](https://github.com/passepartoutvpn/passepartout-ios/issues/39)
### Fixed
- Support PKCS#8 encrypted cert keys. [#43](https://github.com/passepartoutvpn/passepartout-ios/issues/43)
- Handle PEM with preamble. [tunnelkit#78](https://github.com/passepartoutvpn/tunnelkit/issues/78)
- Infrastructures not retained after refresh. [#54](https://github.com/passepartoutvpn/passepartout-ios/issues/54)
## 1.2.0 (2019-04-01)
### Added
- Siri Shortcuts in-app manager. [#46](https://github.com/passepartoutvpn/passepartout-ios/pull/46)
- Background data count updates in diagnostics. [#51](https://github.com/passepartoutvpn/passepartout-ios/pull/51)
- Configure masking in debug log for improved diagnostics.
- Mullvad provider. [#45](https://github.com/passepartoutvpn/passepartout-ios/pull/45)
- Support for encrypted certificate private keys. [#43](https://github.com/passepartoutvpn/passepartout-ios/pull/43)
### Changed
- Upgraded to Swift 5.
### Fixed
- EKU not verified with providers (regression).
- Occasionally overlapping footers in organizer.
## 1.1.0 (2019-03-22)
### Added
- Support for LZO compression. [#32](https://github.com/passepartoutvpn/passepartout-ios/issues/32)
- Siri shortcuts. [#41](https://github.com/passepartoutvpn/passepartout-ios/pull/41)
- Custom intents, have a look at Spotlight suggestions for Passepartout. [#40](https://github.com/passepartoutvpn/passepartout-ios/pull/40)
- TunnelBear provider. [#35](https://github.com/passepartoutvpn/passepartout-ios/pull/35)
### Changed
- Normalize localization of provider locations.
### Fixed
- Profile not activating if none is active. [#42](https://github.com/passepartoutvpn/passepartout-ios/issues/42)
- EKU verification enabled when it shouldn't be.
- Incorrect VPN status after renaming. [#37](https://github.com/passepartoutvpn/passepartout-ios/issues/37)
- Profile change doesn't disconnect active VPN. [#38](https://github.com/passepartoutvpn/passepartout-ios/issues/38)
- Some reconnection issues encountered with TunnelBear and NordVPN.
- Hosts gone while connected (credit to Aston Martin). [#19](https://github.com/passepartoutvpn/passepartout-ios/issues/19)
## 1.0.3 (2019-03-06)
### Fixed
- Regression in profile activation. [#36](https://github.com/passepartoutvpn/passepartout-ios/issues/36)
## 1.0.2 (2019-03-04)
### Fixed
- Profile sometimes not connecting right after add.
- Custom DNS servers were not applied.
- Shut down if server uses compression at all.
- Broken link to SwiftGen license.
## 1.0.1 (2019-02-27)
### Added
- Override DNS servers via `dhcp-option DNS`. [tunnelkit#56](https://github.com/passepartoutvpn/tunnelkit/pull/56)
- About link to FAQ.
### Changed
- Only enable EKU verification if `remote-cert-tls server`. [tunnelkit#64](https://github.com/passepartoutvpn/tunnelkit/pull/64)
### Fixed
- Shut down if server pushes a compression directive. [tunnelkit#65](https://github.com/passepartoutvpn/tunnelkit/pull/65)
- Retain DNS reply order in resolved endpoint addresses. [#31](https://github.com/passepartoutvpn/passepartout-ios/pull/31)
## 1.0 (2019-01-16)
### Added
- Automated app rating mechanism.
- Dot as a legal character in host profile title. [#22](https://github.com/passepartoutvpn/passepartout-ios/issues/22)
- Host profiles can now be renamed. [#24](https://github.com/passepartoutvpn/passepartout-ios/issues/24)
- Explicit rejection of encrypted client certificate keys. [#15](https://github.com/passepartoutvpn/passepartout-ios/issues/15)
- Attach .ovpn when reporting a connectivity issue, stripped of sensitive data. [#13](https://github.com/passepartoutvpn/passepartout-ios/pull/13)
- iTunes File Sharing (skythedesu). [#14](https://github.com/passepartoutvpn/passepartout-ios/pull/14)
- Tunnel failure reporting in UI. [#8](https://github.com/passepartoutvpn/passepartout-ios/pull/8)
- Explicit "Reconnect" button. [#9](https://github.com/passepartoutvpn/passepartout-ios/pull/9)
- Option to revert host parameters to original configuration (Nicholas Caito). [#10](https://github.com/passepartoutvpn/passepartout-ios/pull/10)
- Support for TLS wrapping (tls-auth and tls-crypt). [#5](https://github.com/passepartoutvpn/passepartout-ios/pull/5)
- AES-GCM and new endpoints to PIA network preset. [tunnelkit#32](https://github.com/passepartoutvpn/tunnelkit/pull/32)
- Disclosure indicators in profile organizer (Samuel Michaels).
- Disclaimer for app usage.
### Removed
- "Test connectivity" until it's more transparent.
- Password confirmation field, redundant with authentication failure message.
### Changed
- Relocated API endpoints, better before first release.
- Reorganized credits page.
- Internal refactoring (nothing visible).
- Disconnect VPN by default when entering a trusted network. [#25](https://github.com/passepartoutvpn/passepartout-ios/pull/25)
- Host parameters are read-only if there isn't an original configuration to revert to.
- Overall serialization performance.
- Drive generic support requests on Reddit.
- Add current Wi-Fi to trusted networks list but don't trust it by default.
### Fixed
- Infrastructures not refreshed. [#29](https://github.com/passepartoutvpn/passepartout-ios/issues/29)
- Incorrect compression warnings when importing host configurations. [#20](https://github.com/passepartoutvpn/passepartout-ios/pull/20)
- Regression in provider endpoints, IPv4 appearing reversed. [#23](https://github.com/passepartoutvpn/passepartout-ios/pull/23)
- Handling of extra whitespaces in .ovpn (Mike Mayer). [#17](https://github.com/passepartoutvpn/passepartout-ios/issues/17)
- Glitches in import wizard flow, sometimes not even appearing.
- Warn about .ovpn containing potentially unsupported compression. [#16](https://github.com/passepartoutvpn/passepartout-ios/issues/16)
- Retain credentials of replaced host profile.
- Original configuration not saved after reset.
- Connection occasionally turning inactive after a while.
- Improved performance and privacy of debug log.
- .ovpn files could not be imported without OpenVPN Connect installed. [#6](https://github.com/passepartoutvpn/passepartout-ios/issues/6)
- Fixed Mullvad abrupt disconnection. [tunnelkit#30](https://github.com/passepartoutvpn/tunnelkit/issues/30)
- Credentials are now optional for host profiles. [#4](https://github.com/passepartoutvpn/passepartout-ios/pull/4)
- Can now import .ovpn files from Apple Files app. [#1](https://github.com/passepartoutvpn/passepartout-ios/pull/1)
- Reject unrecognized values for `cipher`, `auth` and `proto`. [#1](https://github.com/passepartoutvpn/passepartout-ios/pull/1)
- Alert unsupported configuration options.
- Use accent color for checkmarks in table cells.
## 1.0 beta 975 (2018-10-11)
First public beta release.

View File

@ -1,149 +0,0 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 1.18.0 (2022-02-15)
### Added
- Handle `--keepalive` option.
### Changed
- Release app in the open via GitHub Actions.
### Fixed
- Last update was not refreshed on "Refresh infrastructure".
- Trim whitespaces in text fields.
## 1.17.2 (2021-11-30)
### Changed
- Revert to OpenSSL.
### Fixed
- "TLS failed" with some certificates (e.g. Let's Encrypt).
- Newer infrastructure discarded over bundle.
## 1.17.0 (2021-11-16)
### Changed
- Replace OpenSSL with BoringSSL.
- Restrict support to secure TLS algorithms (security level).
- Drop status bar icon color to automatically adjust to desktop background color. [#199](https://github.com/passepartoutvpn/passepartout-apple/issues/199)
- Allow Oeck provider without any purchase.
### Fixed
- Location areas were not sorted in menu.
## 1.16.0 (2021-08-09)
### Added
- Support for `--scramble xormask`. [tunnelkit#38](https://github.com/passepartoutvpn/tunnelkit/issues/38)
- Favorite provider locations.
- Oeck provider.
- In-app donations.
## 1.15.3 (2021-07-20)
### Added
- SurfShark provider.
- Support for `--compress stub-v2`.
### Fixed
- Crash when adding dynamically updated provider.
- In-app purchases might crash the app and not be credited until relaunch.
## 1.15.2 (2021-04-17)
### Added
- Website guidance in provider account screen.
- Missing translations (German, Greek, Spanish, French, Dutch, Polish, Portuguese, Russian, Swedish, Chinese Simplified).
### Changed
- Improve debug log appearance.
### Fixed
- Prevent ineffective editing of trusted network SSID.
- VPN not being disabled when "Inactive" due to trusted network.
## 1.15.1 (2021-02-14)
### Changed
- Skip keychain password prompt. [tunnelkit#200](https://github.com/passepartoutvpn/tunnelkit/issues/200)
### Fixed
- No way to set DNS servers when using DNS over HTTPS. [#171](https://github.com/passepartoutvpn/passepartout-apple/issues/171)
## 1.15.0 (2021-02-09)
### Added
- Support `--data-ciphers` from OpenVPN 2.5. [tunnelkit#193](https://github.com/passepartoutvpn/tunnelkit/issues/193)
- Support DNS over HTTPS/TLS in "Network settings". [#91](https://github.com/passepartoutvpn/passepartout-apple/issues/91)
- Menu tooltip describing active profile and status.
- Make "Confirm quit" a preference.
### Changed
- Rendering of profile configuration.
- Color-blind friendly menu icon.
### Fixed
- Missing PAC URL in proxy settings.
- Redundant keychain items.
## 1.14.0 (2021-01-07)
### Added
- Country flags in provider infrastructure menu.
### Changed
- Rendering of provider infrastructures.
### Fixed
- Provider infrastructure selectors not reloaded on profile change.
## 1.0.0 (2021-01-01)
### Added
- Launch on boot/login.
- Change active profile from menu.
- Edit credentials/profile from menu.
- Links in About dialog.
### Changed
- Mimic iOS app when activating a profile (Use then Enable).
- Do not autoconnect to selected location.
### Fixed
- Unsaved settings.
- Incorrect keychain management.
- Menu inconsistencies.
## 1.0.0 beta 345 (2018-10-01)
First private beta release.

View File

@ -1,169 +0,0 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 2.3.6 (2024-09-22)
### Fixed
- Restricted profile not updated. [#481](https://github.com/passepartoutvpn/passepartout-apple/pull/481)
- Selection and switch have the same color in organizer. [#458](https://github.com/passepartoutvpn/passepartout-apple/issues/458), [#486](https://github.com/passepartoutvpn/passepartout-apple/pull/486), [#490](https://github.com/passepartoutvpn/passepartout-apple/pull/490)
## 2.3.5 (2024-01-19)
### Fixed
- Minor stuff.
## 2.3.4 (2024-01-14)
### Fixed
- Unintended sensitive data in issue reports. [#471](https://github.com/passepartoutvpn/passepartout-apple/pull/471)
## 2.3.3 (2024-01-11)
### Fixed
- Platform purchasers cannot upgrade to full version. [#464](https://github.com/passepartoutvpn/passepartout-apple/issues/464)
## 2.3.2 (2024-01-11)
### Fixed
- "Restore purchases" not working. [#459](https://github.com/passepartoutvpn/passepartout-apple/issues/459)
- Purchase is not credited if any refund was issued in the past. [#461](https://github.com/passepartoutvpn/passepartout-apple/issues/461)
- On-demand not applying to wired connections. [#463](https://github.com/passepartoutvpn/passepartout-apple/pull/463)
## 2.3.1 (2024-01-06)
### Fixed
- OpenVPN: Regressions from the upgrade to OpenSSL 3. [tunnelkit#403](https://github.com/passepartoutvpn/tunnelkit/issues/403)
## 2.3.0 (2023-12-31)
### Added
- App for tvOS. [#315](https://github.com/passepartoutvpn/passepartout-apple/issues/315)
- WireGuard: Show data count. [#312](https://github.com/passepartoutvpn/passepartout-apple/issues/312)
### Changed
- Upgrade OpenSSL to 3.2.0. [tunnelkit#336](https://github.com/passepartoutvpn/tunnelkit/issues/336)
- Encrypt profiles stored to iCloud. [#436](https://github.com/passepartoutvpn/passepartout-apple/pull/436)
## 2.2.1 (2023-10-14)
### Fixed
- Persisted profile is overwritten with its former value. [#367](https://github.com/passepartoutvpn/passepartout-apple/issues/367)
## 2.2.0 (2023-10-10)
### Added
- OpenVPN: Allow editing of endpoints. [#335](https://github.com/passepartoutvpn/passepartout-apple/pull/335)
### Changed
- Make iCloud an opt-in preference. [#227](https://github.com/passepartoutvpn/passepartout-apple/issues/227)
- OpenVPN: Endpoint UX. [#332](https://github.com/passepartoutvpn/passepartout-apple/pull/332)
- Convert trusted networks to on demand activation. [#119](https://github.com/passepartoutvpn/passepartout-apple/issues/119)
## 2.1.2 (2023-07-06)
### Fixed
- Allow wildcards in proxy bypass domains. [#296](https://github.com/passepartoutvpn/passepartout-apple/issues/296)
- Fail gracefully when refreshing infrastructure. [#307](https://github.com/passepartoutvpn/passepartout-apple/pull/307)
- Only show 'Reconnect' on active profile. [#311](https://github.com/passepartoutvpn/passepartout-apple/pull/311)
- IPv4/6 address validation. [#308](https://github.com/passepartoutvpn/passepartout-apple/pull/308)
- Domain name validation. [#297](https://github.com/passepartoutvpn/passepartout-apple/pull/297)
## 2.1.1 (2023-04-19)
### Added
- Show app version in Mac menu (macOS). [#286](https://github.com/passepartoutvpn/passepartout-apple/pull/286)
### Fixed
- Roll back broken kill switch flag. [#294](https://github.com/passepartoutvpn/passepartout-apple/pull/294)
- Remove nonsense Mac menus (macOS). [#285](https://github.com/passepartoutvpn/passepartout-apple/pull/285)
## 2.1.0 (2023-04-07)
### Added
- Option to lock app when entering background (iOS). [#270](https://github.com/passepartoutvpn/passepartout-apple/pull/270)
- 3D Touch items (iOS). [#267](https://github.com/passepartoutvpn/passepartout-apple/pull/267)
- Ukranian translations (@josser). [#243](https://github.com/passepartoutvpn/passepartout-apple/pull/243)
- Randomize provider server. [#263](https://github.com/passepartoutvpn/passepartout-apple/pull/263)
- Restore DNS "Domain" setting. [#260](https://github.com/passepartoutvpn/passepartout-apple/pull/260)
- OpenVPN: Full implementation of Tunnelblick XOR patch (@tmthecoder). [#245](https://github.com/passepartoutvpn/passepartout-apple/pull/245), [tunnelkit#255](https://github.com/passepartoutvpn/tunnelkit/pull/255)
- WireGuard: DoH/DoT options. [#264](https://github.com/passepartoutvpn/passepartout-apple/pull/264)
### Changed
- Bump targets to iOS 15 / macOS 12.
- Always show "Reconnect" button. [#277](https://github.com/passepartoutvpn/passepartout-apple/pull/277)
- Move Diagnostics view to Profile bottom. [#261](https://github.com/passepartoutvpn/passepartout-apple/pull/261)
### Fixed
- Improve kill switch behavior. [#181](https://github.com/passepartoutvpn/passepartout-apple/issues/181)
- Retain original filename as imported profile name. [#240](https://github.com/passepartoutvpn/passepartout-apple/pull/240)
- In-app purchases other than full version were not recognized (macOS). [#281](https://github.com/passepartoutvpn/passepartout-apple/pull/281)
## 2.0.2 (2022-10-31)
### Added
- OpenVPN: Support for `--remote-random-hostname`. [tunnelkit#286](https://github.com/passepartoutvpn/tunnelkit/pull/286)
### Fixed
- OpenVPN: Tunnel dying prematurely. [tunnelkit#289](https://github.com/passepartoutvpn/tunnelkit/issues/289), [#237](https://github.com/passepartoutvpn/passepartout-apple/issues/237)
- OpenVPN: Local network settings being ignored. [tunnelkit#290](https://github.com/passepartoutvpn/tunnelkit/issues/290)
- OpenVPN: Routes from configuration file are ignored. [tunnelkit#278](https://github.com/passepartoutvpn/tunnelkit/issues/278)
- OpenVPN: Parse IPv6 endpoints properly. [tunnelkit#294](https://github.com/passepartoutvpn/tunnelkit/issues/294)
- Restore "Reconnect" action in profiles. [#232](https://github.com/passepartoutvpn/passepartout-apple/pull/232)
- Systematic uninstallation of VPN profile if any IAP was refunded. [#238](https://github.com/passepartoutvpn/passepartout-apple/issues/238)
- Use .includeAllNetworks for best-effort kill switch. [#181](https://github.com/passepartoutvpn/passepartout-apple/issues/181), [tunnelkit#300](https://github.com/passepartoutvpn/tunnelkit/pull/300)
## 2.0.1 (2022-10-17)
### Added
- IVPN provider.
- OpenVPN: Support for `--route-nopull`. [#230](https://github.com/passepartoutvpn/passepartout-apple/pull/230)
- App log in Diagnostics screen. [#234](https://github.com/passepartoutvpn/passepartout-apple/pull/234)
### Changed
- Retain whitespaces in imported file names.
### Fixed
- Oeck provider is available again to free users.
- Randomic crashes on profile updates. [#229](https://github.com/passepartoutvpn/passepartout-apple/pull/229)
- Mullvad: enforce password to avoid "Auth failed". [#233](https://github.com/passepartoutvpn/passepartout-apple/pull/233)
## 2.0.0 (2022-10-02)
### Added
- WireGuard support. [#201](https://github.com/passepartoutvpn/passepartout-apple/issues/201)
- iCloud support. [#137](https://github.com/passepartoutvpn/passepartout-apple/issues/137)
### Changed
- App completely rewritten in SwiftUI.
### Fixed
- Files occasionally not selectable in browser. [#215](https://github.com/passepartoutvpn/passepartout-apple/issues/215)

View File

@ -1,6 +1,6 @@
source "https://rubygems.org" source "https://rubygems.org"
gem "fastlane" gem "fastlane", ">= 2.2.0", :github => "keeshux/fastlane", :branch => "bugfix/build-multiplatform-for-ipa-pkg"
gem "dotenv" gem "dotenv"
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')

View File

@ -1,74 +1,9 @@
GEM GIT
remote: https://rubygems.org/ remote: https://github.com/keeshux/fastlane.git
revision: d08c54ec635ea28fe797d76a56af8a83548ecc96
branch: bugfix/build-multiplatform-for-ipa-pkg
specs: specs:
CFPropertyList (3.0.7) fastlane (2.221.1)
base64
nkf
rexml
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.3.0)
aws-partitions (1.977.0)
aws-sdk-core (3.207.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.9)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.92.0)
aws-sdk-core (~> 3, >= 3.207.0)
aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.164.0)
aws-sdk-core (~> 3, >= 3.207.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5)
aws-sigv4 (1.10.0)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
base64 (0.2.0)
claide (1.1.0)
colored (1.2)
colored2 (3.1.2)
commander (4.6.0)
highline (~> 2.0.0)
declarative (0.0.20)
digest-crc (0.6.5)
rake (>= 12.0.0, < 14.0.0)
domain_name (0.6.20240107)
dotenv (2.8.1)
emoji_regex (3.2.3)
excon (0.111.0)
faraday (1.10.4)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
faraday-httpclient (~> 1.0)
faraday-multipart (~> 1.0)
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.0)
faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
faraday-retry (~> 1.0)
ruby2_keywords (>= 0.0.4)
faraday-cookie_jar (0.0.7)
faraday (>= 0.8.0)
http-cookie (~> 1.0.0)
faraday-em_http (1.0.0)
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.4)
multipart-post (~> 2)
faraday-net_http (1.0.2)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
faraday-retry (1.0.3)
faraday_middleware (1.2.0)
faraday (~> 1.0)
fastimage (2.3.1)
fastlane (2.222.0)
CFPropertyList (>= 2.3, < 4.0.0) CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0) addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0) artifactory (~> 3.0)
@ -109,6 +44,83 @@ GEM
xcodeproj (>= 1.13.0, < 2.0.0) xcodeproj (>= 1.13.0, < 2.0.0)
xcpretty (~> 0.3.0) xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.7)
base64
nkf
rexml
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.3.0)
aws-partitions (1.975.0)
aws-sdk-core (3.205.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.9)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.91.0)
aws-sdk-core (~> 3, >= 3.205.0)
aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.162.0)
aws-sdk-core (~> 3, >= 3.205.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5)
aws-sigv4 (1.9.1)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
base64 (0.2.0)
bigdecimal (3.1.8)
claide (1.1.0)
colored (1.2)
colored2 (3.1.2)
commander (4.6.0)
highline (~> 2.0.0)
csv (3.3.0)
declarative (0.0.20)
digest-crc (0.6.5)
rake (>= 12.0.0, < 14.0.0)
domain_name (0.6.20240107)
dotenv (2.8.1)
emoji_regex (3.2.3)
excon (0.111.0)
faraday (1.10.3)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
faraday-httpclient (~> 1.0)
faraday-multipart (~> 1.0)
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.0)
faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
faraday-retry (~> 1.0)
ruby2_keywords (>= 0.0.4)
faraday-cookie_jar (0.0.7)
faraday (>= 0.8.0)
http-cookie (~> 1.0.0)
faraday-em_http (1.0.0)
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.4)
multipart-post (~> 2)
faraday-net_http (1.0.2)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
faraday-retry (1.0.3)
faraday_middleware (1.2.0)
faraday (~> 1.0)
fastimage (2.3.1)
fastlane-plugin-translate_gpt (0.1.8.2)
loco_strings (~> 0.1.4.1)
ruby-openai (~> 3.7)
fastlane-plugin-versioning (0.6.0)
gh_inspector (1.1.3) gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.54.0) google-apis-androidpublisher_v3 (0.54.0)
google-apis-core (>= 0.11.0, < 2.a) google-apis-core (>= 0.11.0, < 2.a)
@ -149,22 +161,37 @@ GEM
highline (2.0.3) highline (2.0.3)
http-cookie (1.0.7) http-cookie (1.0.7)
domain_name (~> 0.5) domain_name (~> 0.5)
httparty (0.22.0)
csv
mini_mime (>= 1.0.0)
multi_xml (>= 0.5.2)
httpclient (2.8.3) httpclient (2.8.3)
jmespath (1.6.2) jmespath (1.6.2)
json (2.7.2) json (2.7.2)
jwt (2.9.0) jwt (2.9.0)
base64 base64
loco_strings (0.1.4.1)
nokogiri (~> 1.13, >= 1.13.8)
mini_magick (4.13.2) mini_magick (4.13.2)
mini_mime (1.1.5) mini_mime (1.1.5)
mini_portile2 (2.8.7)
multi_json (1.15.0) multi_json (1.15.0)
multi_xml (0.7.1)
bigdecimal (~> 3.1)
multipart-post (2.4.1) multipart-post (2.4.1)
nanaimo (0.3.0) nanaimo (0.3.0)
naturally (2.2.1) naturally (2.2.1)
nkf (0.2.0) nkf (0.2.0)
nokogiri (1.16.7)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
nokogiri (1.16.7-arm64-darwin)
racc (~> 1.4)
optparse (0.5.0) optparse (0.5.0)
os (1.1.4) os (1.1.4)
plist (3.7.1) plist (3.7.1)
public_suffix (6.0.1) public_suffix (6.0.1)
racc (1.8.1)
rake (13.2.1) rake (13.2.1)
representable (3.2.0) representable (3.2.0)
declarative (< 0.1.0) declarative (< 0.1.0)
@ -173,6 +200,8 @@ GEM
retriable (3.1.2) retriable (3.1.2)
rexml (3.3.7) rexml (3.3.7)
rouge (2.0.7) rouge (2.0.7)
ruby-openai (3.7.0)
httparty (>= 0.18.1)
ruby2_keywords (0.0.5) ruby2_keywords (0.0.5)
rubyzip (2.3.2) rubyzip (2.3.2)
security (0.1.5) security (0.1.5)
@ -209,12 +238,13 @@ GEM
PLATFORMS PLATFORMS
arm64-darwin-23 arm64-darwin-23
x86_64-darwin-21 ruby
x86_64-linux
DEPENDENCIES DEPENDENCIES
dotenv dotenv
fastlane fastlane (>= 2.2.0)!
fastlane-plugin-translate_gpt
fastlane-plugin-versioning
BUNDLED WITH BUNDLED WITH
2.5.17 2.5.14

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,21 @@
{ {
"pins" : [ "pins" : [
{ {
"identity" : "generic-json-swift", "identity" : "dtfoundation",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/zoul/generic-json-swift", "location" : "https://github.com/Cocoanetics/DTFoundation.git",
"state" : { "state" : {
"revision" : "0a06575f4038b504e78ac330913d920f1630f510", "revision" : "76062513434421cb6c8a1ae1d4f8368a7ebc2da3",
"version" : "2.0.2" "version" : "1.7.18"
}
},
{
"identity" : "kvitto",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Cocoanetics/Kvitto",
"state" : {
"revision" : "88888674d772ddcf19671159ed0022cb0bc37be2",
"version" : "1.0.6"
} }
}, },
{ {
@ -14,25 +23,44 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/passepartoutvpn/openssl-apple", "location" : "https://github.com/passepartoutvpn/openssl-apple",
"state" : { "state" : {
"revision" : "026702febcaebcbf9ea68f2fa66b017eba998cdf", "revision" : "0edc07c7a0e4ec2ca0f448dd68314241ccc925b3",
"version" : "3.2.105" "version" : "3.2.107"
} }
}, },
{ {
"identity" : "swiftybeaver", "identity" : "passepartoutkit",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/SwiftyBeaver/SwiftyBeaver", "location" : "git@github.com:passepartoutvpn/passepartoutkit",
"state" : { "state" : {
"revision" : "12b5acf96d98f91d50de447369bd18df74600f1a", "revision" : "2c32459d6a669e8feed0e6ea2d1250ef72364aa3",
"version" : "1.9.6" "version" : "0.7.0"
} }
}, },
{ {
"identity" : "tunnelkit", "identity" : "passepartoutkit-openvpn-openssl",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/passepartoutvpn/tunnelkit", "location" : "git@github.com:passepartoutvpn/passepartoutkit-openvpn-openssl",
"state" : { "state" : {
"revision" : "6ab1759e048867fbca9bd5d33f2dc7eb1fa79ca6" "revision" : "a3092a6ee0a63f666aa47ef3f0f50c324a64598d",
"version" : "0.6.0"
}
},
{
"identity" : "passepartoutkit-wireguard-go",
"kind" : "remoteSourceControl",
"location" : "git@github.com:passepartoutvpn/passepartoutkit-wireguard-go",
"state" : {
"revision" : "2cbd6023300d2dcc3f6f68de4812cf390421ec35",
"version" : "0.6.2"
}
},
{
"identity" : "wg-go-apple",
"kind" : "remoteSourceControl",
"location" : "https://github.com/passepartoutvpn/wg-go-apple",
"state" : {
"revision" : "860e82efaf261da37483a5f51555be83e5a79ad3",
"version" : "0.0.20240714"
} }
}, },
{ {
@ -40,7 +68,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/passepartoutvpn/wireguard-apple", "location" : "https://github.com/passepartoutvpn/wireguard-apple",
"state" : { "state" : {
"revision" : "b79f0f150356d8200a64922ecf041dd020140aa0" "revision" : "a896f784bc5ed94f29d97e376be5cfa08d4a5d44",
"version" : "1.1.1"
} }
} }
], ],

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1510" LastUpgradeVersion = "1540"
version = "1.7"> version = "1.7">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@ -14,54 +14,12 @@
buildForAnalyzing = "YES"> buildForAnalyzing = "YES">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "0E57F63720C83FC5008323CF" BlueprintIdentifier = "0E06D18E2B87629100176E1D"
BuildableName = "Passepartout.app" BuildableName = "Passepartout.app"
BlueprintName = "Passepartout" BlueprintName = "Passepartout"
ReferencedContainer = "container:Passepartout.xcodeproj"> ReferencedContainer = "container:Passepartout.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0EDE8DBE20C86910004C739C"
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>
</BuildActionEntries> </BuildActionEntries>
</BuildAction> </BuildAction>
<TestAction <TestAction
@ -70,21 +28,11 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES" shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES"> shouldAutocreateTestPlan = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0E57F63720C83FC5008323CF"
BuildableName = "Passepartout.app"
BlueprintName = "Passepartout"
ReferencedContainer = "container:Passepartout.xcodeproj">
</BuildableReference>
</MacroExpansion>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = "it"
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
@ -95,7 +43,7 @@
runnableDebuggingMode = "0"> runnableDebuggingMode = "0">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "0E57F63720C83FC5008323CF" BlueprintIdentifier = "0E06D18E2B87629100176E1D"
BuildableName = "Passepartout.app" BuildableName = "Passepartout.app"
BlueprintName = "Passepartout" BlueprintName = "Passepartout"
ReferencedContainer = "container:Passepartout.xcodeproj"> ReferencedContainer = "container:Passepartout.xcodeproj">
@ -103,35 +51,33 @@
</BuildableProductRunnable> </BuildableProductRunnable>
<CommandLineArguments> <CommandLineArguments>
<CommandLineArgument <CommandLineArgument
argument = "-com.apple.CoreData.SQLDebug 0" argument = "-com.apple.CoreData.SQLDebug 1"
isEnabled = "YES"> isEnabled = "NO">
</CommandLineArgument> </CommandLineArgument>
<CommandLineArgument <CommandLineArgument
argument = "-com.apple.CoreData.Logging.stderr 0 " argument = " -com.apple.CoreData.ConcurrencyDebug 1"
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"> isEnabled = "YES">
</CommandLineArgument> </CommandLineArgument>
</CommandLineArguments> </CommandLineArguments>
<EnvironmentVariables> <EnvironmentVariables>
<EnvironmentVariable <EnvironmentVariable
key = "APP_TYPE" key = "SQLITE_ENABLE_THREAD_ASSERTIONS"
value = "0" value = "1"
isEnabled = "YES"> isEnabled = "YES">
</EnvironmentVariable> </EnvironmentVariable>
<EnvironmentVariable <EnvironmentVariable
key = "LOG_LEVEL" key = "SQLITE_ENABLE_FILE_ASSERTIONS"
value = "0" value = "1"
isEnabled = "YES">
</EnvironmentVariable>
<EnvironmentVariable
key = "SQLITE_AUTO_TRACE"
value = "1"
isEnabled = "NO">
</EnvironmentVariable>
<EnvironmentVariable
key = "CUSTOM_USER_LEVEL"
value = "2"
isEnabled = "YES"> isEnabled = "YES">
</EnvironmentVariable> </EnvironmentVariable>
</EnvironmentVariables> </EnvironmentVariables>
@ -146,7 +92,7 @@
runnableDebuggingMode = "0"> runnableDebuggingMode = "0">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "0E57F63720C83FC5008323CF" BlueprintIdentifier = "0E06D18E2B87629100176E1D"
BuildableName = "Passepartout.app" BuildableName = "Passepartout.app"
BlueprintName = "Passepartout" BlueprintName = "Passepartout"
ReferencedContainer = "container:Passepartout.xcodeproj"> ReferencedContainer = "container:Passepartout.xcodeproj">

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1510" LastUpgradeVersion = "1540"
version = "1.3"> wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"> buildImplicitDependencies = "YES">
@ -14,9 +15,23 @@
buildForAnalyzing = "YES"> buildForAnalyzing = "YES">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "0E41BD96286711C3006346B4" BlueprintIdentifier = "0EC332C72B8A1808000B9C2F"
BuildableName = "PassepartoutLauncher.app" BuildableName = "PassepartoutTunnel.appex"
BlueprintName = "PassepartoutLauncher" BlueprintName = "PassepartoutTunnel"
ReferencedContainer = "container:Passepartout.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0E06D18E2B87629100176E1D"
BuildableName = "Passepartout.app"
BlueprintName = "Passepartout"
ReferencedContainer = "container:Passepartout.xcodeproj"> ReferencedContainer = "container:Passepartout.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
@ -26,27 +41,28 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES"
<Testables> shouldAutocreateTestPlan = "YES">
</Testables>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
launchStyle = "0" launchStyle = "0"
askForAppToLaunch = "Yes"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES" debugDocumentVersioning = "YES"
debugServiceExtension = "internal" debugServiceExtension = "internal"
allowLocationSimulation = "YES"> allowLocationSimulation = "YES"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable <BuildableProductRunnable
runnableDebuggingMode = "0"> runnableDebuggingMode = "0">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "0E41BD96286711C3006346B4" BlueprintIdentifier = "0E06D18E2B87629100176E1D"
BuildableName = "PassepartoutLauncher.app" BuildableName = "Passepartout.app"
BlueprintName = "PassepartoutLauncher" BlueprintName = "Passepartout"
ReferencedContainer = "container:Passepartout.xcodeproj"> ReferencedContainer = "container:Passepartout.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
@ -56,14 +72,16 @@
shouldUseLaunchSchemeArgsEnv = "YES" shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = "" savedToolIdentifier = ""
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"> debugDocumentVersioning = "YES"
askForAppToLaunch = "Yes"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable <BuildableProductRunnable
runnableDebuggingMode = "0"> runnableDebuggingMode = "0">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "0E41BD96286711C3006346B4" BlueprintIdentifier = "0E06D18E2B87629100176E1D"
BuildableName = "PassepartoutLauncher.app" BuildableName = "Passepartout.app"
BlueprintName = "PassepartoutLauncher" BlueprintName = "Passepartout"
ReferencedContainer = "container:Passepartout.xcodeproj"> ReferencedContainer = "container:Passepartout.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>

View File

@ -2,40 +2,29 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.icloud-container-identifiers</key>
<array>
<string>iCloud.com.algoritmico.Passepartout</string>
<string>iCloud.com.algoritmico.Passepartout.Shared</string>
</array>
<key>com.apple.developer.icloud-services</key>
<array>
<string>CloudKit</string>
</array>
<key>com.apple.developer.networking.networkextension</key> <key>com.apple.developer.networking.networkextension</key>
<array> <array>
<string>packet-tunnel-provider</string> <string>packet-tunnel-provider</string>
</array> </array>
<key>com.apple.developer.networking.wifi-info</key> <key>com.apple.developer.networking.wifi-info</key>
<true/> <true/>
<key>com.apple.developer.siri</key>
<true/>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key> <key>com.apple.security.application-groups</key>
<array> <array>
<string>group.$(CFG_GROUP_ID)</string> <string>$(CFG_GROUP_ID)</string>
</array> </array>
<key>com.apple.security.files.user-selected.read-write</key> <key>com.apple.security.app-sandbox</key>
<true/> <true/>
<key>com.apple.security.network.client</key> <key>com.apple.security.files.user-selected.read-only</key>
<true/> <true/>
<key>com.apple.security.personal-information.location</key> <key>com.apple.security.personal-information.location</key>
<true/> <true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>keychain-access-groups</key> <key>keychain-access-groups</key>
<array> <array>
<string>$(AppIdentifierPrefix)group.com.algoritmico.Passepartout</string> <string>$(AppIdentifierPrefix)$(CFG_GROUP_ID)</string>
</array> </array>
</dict> </dict>
</plist> </plist>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>AppConfig</key>
<dict>
<key>appId</key>
<string>$(CFG_APP_ID)</string>
<key>appStoreId</key>
<string>$(CFG_APP_STORE_ID)</string>
<key>groupId</key>
<string>$(CFG_GROUP_ID)</string>
<key>iapBundlePrefix</key>
<string>$(CFG_IAP_BUNDLE_PREFIX)</string>
<key>keychainGroupId</key>
<string>$(CFG_TEAM_ID).$(CFG_GROUP_ID)</string>
<key>profilesContainerName</key>
<string>$(CFG_PROFILES_CONTAINER_NAME)</string>
<key>teamId</key>
<string>$(CFG_TEAM_ID)</string>
<key>tunnelId</key>
<string>$(CFG_TUNNEL_ID)</string>
</dict>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
</dict>
</plist>

View File

@ -2,7 +2,7 @@
// AppDelegate.swift // AppDelegate.swift
// Passepartout // Passepartout
// //
// Created by Davide De Rosa on 6/25/22. // Created by Davide De Rosa on 9/18/24.
// Copyright (c) 2024 Davide De Rosa. All rights reserved. // Copyright (c) 2024 Davide De Rosa. All rights reserved.
// //
// https://github.com/passepartoutvpn // https://github.com/passepartoutvpn
@ -23,37 +23,31 @@
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>. // along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
// //
import Foundation #if os(iOS)
import PassepartoutLibrary
import UIKit import UIKit
final class AppDelegate: UIResponder, UIApplicationDelegate, ObservableObject { final class AppDelegate: NSObject, UIApplicationDelegate {
private let mac = MacBundle.shared }
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { #else
#if targetEnvironment(macCatalyst)
mac.configure() import AppKit
mac.menu.install() import CommonLibrary
if mac.utils.isStartedByLauncher { import PassepartoutKit
mac.utils.sendAppToBackground()
final class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ notification: Notification) {
NSWindow.allowsAutomaticWindowTabbing = false
// XXX: hack to only retain "Edit" menu
NSApp.mainMenu?.items = NSApp.mainMenu?.items.filter {
[BundleConfiguration.main.displayName, "Edit"].contains($0.title)
} ?? []
}
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
true
}
} }
#endif #endif
return true
}
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
let sceneConfiguration = UISceneConfiguration(name: "SceneDelegate", sessionRole: connectingSceneSession.role)
sceneConfiguration.delegateClass = SceneDelegate.self
return sceneConfiguration
}
override func buildMenu(with builder: UIMenuBuilder) {
super.buildMenu(with: builder)
builder.remove(menu: .file)
builder.remove(menu: .services)
builder.remove(menu: .format)
builder.remove(menu: .toolbar)
builder.remove(menu: .view)
builder.remove(menu: .help)
}
}

View File

@ -1,15 +1,6 @@
{ {
"colors" : [ "colors" : [
{ {
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x68",
"green" : "0x9C",
"red" : "0xD6"
}
},
"idiom" : "universal" "idiom" : "universal"
} }
], ],

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

@ -47,12 +47,13 @@
"size" : "256x256" "size" : "256x256"
}, },
{ {
"filename" : "AppIcon-mac.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "1x", "scale" : "1x",
"size" : "512x512" "size" : "512x512"
}, },
{ {
"filename" : "AppIcon-mac.png", "filename" : "AppIcon-mac@2x.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "2x", "scale" : "2x",
"size" : "512x512" "size" : "512x512"

View File

@ -1,20 +0,0 @@
{
"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
}
}

View File

@ -1,20 +0,0 @@
{
"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
}
}

View File

@ -1,259 +0,0 @@
//
// Constants+App.swift
// Passepartout
//
// Created by Davide De Rosa on 9/15/18.
// Copyright (c) 2024 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 PassepartoutLibrary
import UniformTypeIdentifiers
extension Constants {
enum App {
static var appId: String {
guard let identifier = Bundle.main.infoDictionary?[kCFBundleIdentifierKey as String] as? String else {
fatalError("Missing kCFBundleIdentifierKey from Info.plist")
}
return identifier
}
static let appStoreId: String = bundleConfig("appstore_id")
static let appGroupId: String = bundleConfig("group_id")
}
enum CloudKit {
static let containerId: String = bundleConfig("cloudkit_id")
static let sharedContainerId: String = bundleConfig("cloudkit_shared_id")
static let coreDataZone = "com.apple.coredata.cloudkit.zone"
}
enum Plugins {
static let macBridgeName = "PassepartoutMac.bundle"
}
enum InApp {
static var overriddenAppType: AppType? {
if let envString = ProcessInfo.processInfo.environment["APP_TYPE"],
let envValue = Int(envString),
let testAppType = AppType(rawValue: envValue) {
return testAppType
}
if let infoValue: Int = bundleConfig("app_type"),
let testAppType = AppType(rawValue: infoValue) {
return testAppType
}
return nil
}
#if targetEnvironment(macCatalyst)
static let buildProducts = BuildProducts {
if $0 <= 3000 {
return [.networkSettings]
}
return []
}
#else
static let buildProducts = BuildProducts {
if $0 <= 2016 {
return [.fullVersion_iOS]
} else if $0 <= 3000 {
return [.networkSettings]
}
return []
}
#endif
static let tvLimitedMinutes = 10
}
}
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 sharedProfilesContainerName = "SharedProfiles"
static let providersContainerName = "Providers"
}
// milliseconds
enum RateLimit {
static let providerManager = 10000
static let vpnToggle = 500
}
enum Log {
enum App {
static let url = containerURL(filename: "App.log")
static let format = "$DHH:mm:ss.SSS$d $C$L$c $N.$F:$l - $M"
}
enum Tunnel {
static let path = containerPath(filename: "Tunnel.log")
static let format = "$DHH:mm:ss$d - $M"
}
private static let parentPath = "Library/Caches"
static let level: LoggerLevel = {
guard let levelString = ProcessInfo.processInfo.environment["LOG_LEVEL"],
let levelNum = Int(levelString) else {
return .debug
}
return .init(rawValue: levelNum) ?? .debug
}()
static let maxBytes = 100000
static let refreshInterval: TimeInterval = 5.0
private static func containerURL(filename: String) -> URL {
Files.containerURL
.appendingPathComponent(parentPath)
.appendingPathComponent(filename)
}
private static func containerPath(filename: String) -> String {
[parentPath, filename].joined(separator: "/")
}
}
enum URLs {
static let readme = Repos.apple.appendingPathComponent("blob/master/README.md")
static let changelog = Repos.apple.appendingPathComponent("blob/master/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")!
}
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 {
githubRoot.appendingPathComponent(repo)
}
private static func githubRaw(repo: String) -> URL {
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: "File importer stops showing again after closing with swipe down")
static let xxxPresentFileImporter = 200
}
enum Rating {
#if targetEnvironment(macCatalyst)
static let eventCount = 10
#else
static let eventCount = 20
#endif
}
}
extension Constants {
enum Files {
fileprivate 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
}
}
}

View File

@ -1,63 +0,0 @@
//
// Constants+Library.swift
// Passepartout
//
// Created by Davide De Rosa on 6/25/22.
// Copyright (c) 2024 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 PassepartoutLibrary
extension Constants.App {
static func tunnelBundleId(_ vpnProtocol: VPNProtocolType) -> String {
guard let identifier = Bundle.main.infoDictionary?[kCFBundleIdentifierKey as String] as? String else {
fatalError("Missing kCFBundleIdentifierKey from Info.plist")
}
switch vpnProtocol {
case .openVPN:
return "\(identifier).OpenVPNTunnel"
case .wireGuard:
return "\(identifier).WireGuardTunnel"
}
}
}
extension Constants.URLs {
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"
]
}

View File

@ -1,648 +0,0 @@
//
// Theme.swift
// Passepartout
//
// Created by Davide De Rosa on 2/24/22.
// Copyright (c) 2024 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/>.
//
#if !os(tvOS)
import LocalAuthentication
#endif
import PassepartoutLibrary
import SwiftUI
extension View {
var themeIdiom: UIUserInterfaceIdiom {
UIDevice.current.userInterfaceIdiom
}
var themeIsiPadPortrait: Bool {
#if !os(tvOS)
#if targetEnvironment(macCatalyst)
false
#else
let device: UIDevice = .current
return device.userInterfaceIdiom == .pad && device.orientation.isPortrait
#endif
#else
false
#endif
}
var themeIsiPadMultitasking: Bool {
#if !os(tvOS)
#if targetEnvironment(macCatalyst)
false
#else
UIDevice.current.userInterfaceIdiom == .pad
#endif
#else
false
#endif
}
}
// MARK: Global
extension View {
func themeGlobal() -> some View {
themeNavigationViewStyle()
#if !os(tvOS)
#if !targetEnvironment(macCatalyst)
.themeLockScreen()
#endif
.themeTint()
.listStyle(themeListStyleValue())
.toggleStyle(themeToggleStyleValue())
.menuStyle(.borderlessButton)
#endif
.withErrorHandler()
}
#if os(tvOS)
func themeTV() -> some View {
GeometryReader { geo in
self
.padding(.horizontal, 0.25 * geo.size.width)
.scrollClipDisabled()
}
}
#endif
func themePrimaryView() -> some View {
#if targetEnvironment(macCatalyst)
navigationBarTitleDisplayMode(.inline)
.themeSidebarListStyle()
#elseif !os(tvOS)
navigationBarTitleDisplayMode(.large)
.navigationTitle(Unlocalized.appName)
.themeSidebarListStyle()
#else
self
#endif
}
func themeSecondaryView() -> some View {
#if !os(tvOS)
navigationBarTitleDisplayMode(.inline)
#else
self
#endif
}
@ViewBuilder
private func themeNavigationViewStyle() -> some View {
switch themeIdiom {
case .phone:
navigationViewStyle(.stack)
default:
navigationViewStyle(.automatic)
}
}
@ViewBuilder
private func themeSidebarListStyle() -> some View {
#if !os(tvOS)
switch themeIdiom {
case .phone:
listStyle(.insetGrouped)
default:
listStyle(.sidebar)
}
#else
self
#endif
}
func themeTint() -> some View {
tint(.accentColor)
}
func themeListSelectionColor(isSelected: Bool) -> some View {
let background = isSelected ? Color.gray.opacity(0.6) : .clear
return listRowBackground(background.themeRounded())
}
private func themeListStyleValue() -> some ListStyle {
#if !os(tvOS)
.insetGrouped
#else
PlainListStyle()
#endif
}
private func themeToggleStyleValue() -> some ToggleStyle {
#if !os(tvOS)
.switch
#else
DefaultToggleStyle()
#endif
}
}
// MARK: Colors
extension View {
fileprivate var themePrimaryBackgroundColor: Color {
Color(.primary)
}
fileprivate var themeSecondaryColor: Color {
.secondary
}
fileprivate var themeLightTextColor: Color {
Color(.lightText)
}
fileprivate 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: Images
extension View {
var themeAssetsLogoImage: String {
"Logo"
}
var themeCheckmarkImage: String {
"checkmark"
}
var themeShareImage: String {
"square.and.arrow.up"
}
var themeCopyImage: String {
"doc.on.doc"
}
var themeCloseImage: String {
"xmark"
}
var themeConceilImage: String {
"eye.slash"
}
var themeRevealImage: String {
"eye"
}
var themeAppleTVImage: String {
"tv"
}
// MARK: Organizer
func themeAssetsProviderImage(_ providerName: ProviderName) -> String {
"providers/\(providerName)"
}
func themeAssetsCountryImage(_ countryCode: String) -> String {
"flags/\(countryCode.lowercased())"
}
var themeProviderImage: String {
"externaldrive.connected.to.line.below"
}
var themeHostFilesImage: String {
"folder"
}
var themeHostTextImage: String {
"text.justify"
}
var themeSettingsImage: String {
"gearshape"
}
var themeDonateImage: String {
"giftcard"
}
var themeRedditImage: String {
"person.3"
}
var themeWriteReviewImage: String {
"star"
}
var themeAddMenuImage: String {
"plus"
}
var themeProfileActiveImage: String {
"checkmark.circle"
}
var themeProfileConnectedImage: String {
"circle.fill"
}
var themeProfileInactiveImage: String {
"circle"
}
// MARK: Profile
var themeSettingsMenuImage: String {
"ellipsis.circle"
}
var themeReconnectImage: String {
"arrow.clockwise"
}
var themeShortcutsImage: String {
"mic"
}
var themeRenameProfileImage: String {
"highlighter"
// "character.cursor.ibeam"
}
var themeDuplicateImage: String {
"doc.on.doc"
}
var themeUninstallImage: String {
"arrow.uturn.down"
}
var themeDeleteImage: String {
"trash"
}
var themeVPNProtocolImage: String {
"bolt"
// "waveform.path.ecg"
// "message.and.waveform.fill"
// "pc"
// "captions.bubble.fill"
}
var themeEndpointImage: String {
"link"
}
var themeAccountImage: String {
"person"
}
var themeProviderLocationImage: String {
"location"
}
var themeProviderPresetImage: String {
"slider.horizontal.3"
}
var themeNetworkSettingsImage: String {
// "network"
"globe"
}
var themeOnDemandImage: String {
"wifi"
}
var themeDiagnosticsImage: String {
"bandage.fill"
}
var themeFAQImage: String {
"questionmark.diamond"
}
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: Styles
extension View {
func themeAccentForegroundStyle() -> some View {
foregroundColor(.accentColor)
}
var themePrimaryBackground: some View {
themePrimaryBackgroundColor
.ignoresSafeArea()
}
func themeSecondaryTextStyle() -> some View {
foregroundColor(themeSecondaryColor)
}
func themeLightTextStyle() -> some View {
foregroundColor(themeLightTextColor)
}
func themePrimaryTintStyle() -> some View {
tint(themePrimaryBackgroundColor)
}
func themeDestructiveTintStyle() -> some View {
tint(themeErrorColor)
}
func themeTextButtonStyle() -> some View {
accentColor(.primary)
}
func themeLongTextStyle() -> some View {
lineLimit(1)
.truncationMode(.middle)
}
func themeRawTextStyle() -> some View {
disableAutocorrection(true)
.autocapitalization(.none)
}
func themeInformativeTextStyle() -> some View {
multilineTextAlignment(.center)
.font(.title)
.foregroundColor(themeSecondaryColor)
}
func themeCellTitleStyle() -> some View {
font(.headline)
}
func themeCellSubtitleStyle() -> some View {
font(.subheadline)
}
func themeDebugLogStyle() -> some View {
font(.system(size: 13, weight: .medium, design: .monospaced))
}
func themeRounded() -> some View {
clipShape(.rect(cornerRadius: 10.0))
}
}
// MARK: Shortcuts
#if !os(tvOS)
extension ShortcutType {
var themeImageName: String {
switch self {
case .enableVPN:
return "power"
case .disableVPN:
return "xmark"
case .reconnectVPN:
return "arrow.clockwise"
}
}
}
#endif
// MARK: Animations
extension View {
func themeAnimation<V: Equatable>(on value: V) -> some View {
animation(.default, value: value)
}
}
extension Binding {
func themeAnimation() -> Binding<Value> {
animation(.default)
}
}
// MARK: Shortcuts
extension View {
func themeCloseItem(presentationMode: Binding<PresentationMode>) -> some ToolbarContent {
ToolbarItem(placement: .cancellationAction) {
Button {
presentationMode.wrappedValue.dismiss()
} label: {
themeCloseImage.asSystemImage
}
}
}
func themeCloseItem(isPresented: Binding<Bool>) -> some ToolbarContent {
ToolbarItem(placement: .cancellationAction) {
Button {
isPresented.wrappedValue = false
} label: {
themeCloseImage.asSystemImage
}
}
}
func themeSaveButtonLabel() -> some View {
Text(L10n.Global.Strings.save)
}
func themeSecureField(_ placeholder: String, text: Binding<String>, contentType: UITextContentType = .password) -> some View {
RevealingSecureField(placeholder, text: text) {
themeConceilImage.asSystemImage
.themeAccentForegroundStyle()
} revealImage: {
themeRevealImage.asSystemImage
.themeAccentForegroundStyle()
}.textContentType(contentType)
.themeRawTextStyle()
}
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: {
themeListStyleValue()
}
}
func themeLongContentLinkDefault(_ title: String, content: Binding<String>) -> some View {
LongContentLink(title, content: content) {
Text($0)
.foregroundColor(themeSecondaryColor)
}
}
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: Lock screen
#if !os(tvOS)
extension View {
func themeLockScreen() -> some View {
@AppStorage(AppPreference.locksInBackground.key) var locksInBackground = false
return LockableView(
locksInBackground: $locksInBackground,
content: {
self
},
lockedContent: LogoView.init,
unlockBlock: Self.themeUnlockScreenBlock
)
}
private static func themeUnlockScreenBlock() async -> Bool {
let context = LAContext()
let policy: LAPolicy = .deviceOwnerAuthentication
var error: NSError?
guard context.canEvaluatePolicy(policy, error: &error) else {
return true
}
do {
let isAuthorized = try await context.evaluatePolicy(
policy,
localizedReason: L10n.Global.Messages.unlockApp
)
return isAuthorized
} catch {
return false
}
}
}
#endif
// MARK: Validation
extension View {
func themeValidProfileName() -> some View {
themeRawTextStyle()
}
func themeValidURL(_ urlString: String?) -> some View {
themeValidating(urlString, validator: Validators.url)
.keyboardType(.asciiCapable)
.themeRawTextStyle()
}
func themeValidIPAddress(_ ipAddress: String?) -> some View {
themeValidating(ipAddress, validator: Validators.ipAddress)
.keyboardType(.numbersAndPunctuation)
.themeRawTextStyle()
}
func themeValidSocketPort(_ port: String?) -> some View {
themeValidating(port, validator: Validators.socketPort)
.keyboardType(.numberPad)
}
func themeValidDomainName(_ domainName: String?) -> some View {
themeValidating(domainName, validator: Validators.domainName)
.keyboardType(.asciiCapable)
.themeRawTextStyle()
}
func themeValidWildcardDomainName(_ domainName: String?) -> some View {
themeValidating(domainName, validator: Validators.wildcardDomainName)
.keyboardType(.asciiCapable)
.themeRawTextStyle()
}
func themeValidDNSOverTLSServerName(_ string: String?) -> some View {
themeValidating(string, validator: Validators.dnsOverTLSServerName)
.keyboardType(.asciiCapable)
.themeRawTextStyle()
}
func themeValidSSID(_ text: String?) -> some View {
themeValidating(text, validator: Validators.notEmpty)
.keyboardType(.asciiCapable)
.themeRawTextStyle()
}
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)
}
}

View File

@ -1,67 +0,0 @@
//
// AppContext+Shared.swift
// Passepartout
//
// Created by Davide De Rosa on 6/15/22.
// Copyright (c) 2024 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 PassepartoutLibrary
// safer alternative to @EnvironmentObject
// MARK: App
extension AppContext {
static let shared = AppContext(store: UserDefaultsStore(defaults: .standard, key: \.key))
}
extension UpgradeManager {
static let shared = AppContext.shared.upgradeManager
}
extension ProductManager {
static let shared = AppContext.shared.productManager
}
extension PersistenceManager {
static let shared = AppContext.shared.persistenceManager
}
// MARK: App -> Core
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 ObservableVPNState {
@MainActor
static let shared = AppContext.shared.vpnManager.currentState
}

View File

@ -1,183 +0,0 @@
//
// AppContext.swift
// Passepartout
//
// Created by Davide De Rosa on 3/17/22.
// Copyright (c) 2024 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 Combine
import Foundation
import PassepartoutLibrary
@MainActor
final class AppContext {
private let coreContext: CoreContext
let upgradeManager: UpgradeManager
let productManager: ProductManager
let persistenceManager: PersistenceManager
private let reviewer: Reviewer
private var cancellables: Set<AnyCancellable> = []
init(store: KeyValueStore) {
let logger = SwiftyBeaverLogger(
logFile: Constants.Log.App.url,
logLevel: Constants.Log.level,
logFormat: Constants.Log.App.format
)
Passepartout.shared.logger = logger
pp_log.info("Logging to: \(logger.logFile!)")
upgradeManager = UpgradeManager(
store: store,
strategy: DefaultUpgradeManagerStrategy()
)
upgradeManager.migrate(toVersion: Constants.Global.appVersionNumber)
productManager = ProductManager(
inApp: StoreKitInApp<LocalProduct>(),
receiptReader: StoreKitReceiptReader(),
overriddenAppType: Constants.InApp.overriddenAppType,
buildProducts: Constants.InApp.buildProducts
)
persistenceManager = PersistenceManager(
store: store,
ckContainerId: Constants.CloudKit.containerId,
ckSharedContainerId: Constants.CloudKit.sharedContainerId,
ckCoreDataZone: Constants.CloudKit.coreDataZone
)
reviewer = Reviewer()
reviewer.eventCountBeforeRating = Constants.Rating.eventCount
coreContext = CoreContext(persistenceManager: persistenceManager)
// post
configureObjects()
}
var providerManager: ProviderManager {
coreContext.providerManager
}
var profileManager: ProfileManager {
coreContext.profileManager
}
var vpnManager: VPNManager {
coreContext.vpnManager
}
}
private extension AppContext {
func configureObjects() {
coreContext.profileManager.willSaveSharedProfile = { [unowned self] in
willSaveSharedProfile(withNewProfile: $0, existingProfile: $1)
}
coreContext.vpnManager.isOnDemandRulesSupported = {
self.isEligibleForOnDemandRules()
}
coreContext.vpnManager.isNetworkSettingsSupported = {
self.isEligibleForNetworkSettings()
}
coreContext.vpnManager.userData = {
if let expirationDate = $0.connectionExpirationDate {
return [Constants.Tunnel.expirationTimeIntervalKey: expirationDate.timeIntervalSinceReferenceDate]
}
return nil
}
coreContext.vpnManager.currentState.$vpnStatus
.removeDuplicates()
.receive(on: DispatchQueue.main)
.sink { [weak self] in
if $0 == .connected {
pp_log.info("VPN successful connection, report to Reviewer")
self?.reviewer.reportEvent()
}
}.store(in: &cancellables)
}
// eligibility: ignore network settings if ineligible
func isEligibleForNetworkSettings() -> Bool {
guard productManager.isEligible(forFeature: .networkSettings) else {
pp_log.warning("Ignore network settings, not eligible")
return false
}
return true
}
// eligibility: reset on demand rules if no trusted networks
func isEligibleForOnDemandRules() -> Bool {
guard productManager.isEligible(forFeature: .trustedNetworks) else {
pp_log.warning("Ignore on demand rules, not eligible for trusted networks")
return false
}
return true
}
// eligibility: expire restricted TV profiles after N minutes
func willSaveSharedProfile(withNewProfile newProfile: Profile, existingProfile: Profile?) -> Profile {
if let existingProfile {
assert(newProfile.id == existingProfile.id)
}
guard productManager.isEligible(forFeature: .appleTV) else {
var restricted = newProfile
let remainingMinutes: Int
let expirationDate: Date
// retain current expiration period if any
if let existingProfile, let currentExpirationDate = existingProfile.connectionExpirationDate {
remainingMinutes = Int(currentExpirationDate.timeIntervalSinceNow / 60.0)
expirationDate = currentExpirationDate
restricted.connectionExpirationDate = currentExpirationDate
}
// otherwise, expire in N minutes from now
else {
remainingMinutes = Constants.InApp.tvLimitedMinutes
expirationDate = Date()
.addingTimeInterval(TimeInterval(remainingMinutes) * 60.0)
restricted.connectionExpirationDate = expirationDate
}
if remainingMinutes > 0 {
pp_log.warning("\(newProfile.logDescription): TV connection expires in \(remainingMinutes) minutes (at \(expirationDate))")
} else {
pp_log.warning("\(newProfile.logDescription): TV connection expired at \(expirationDate)")
}
return restricted
}
return newProfile
}
}

View File

@ -1,145 +0,0 @@
//
// CoreContext.swift
// Passepartout
//
// Created by Davide De Rosa on 6/4/22.
// Copyright (c) 2024 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 Combine
import Foundation
import PassepartoutLibrary
import TunnelKitCore
import TunnelKitManager
@MainActor
final class CoreContext {
let store: KeyValueStore
let providerManager: ProviderManager
let profileManager: ProfileManager
let vpnManager: VPNManager
private var cancellables: Set<AnyCancellable> = []
init(persistenceManager: PersistenceManager) {
store = persistenceManager.store
#if !os(tvOS)
let vpnPersistence = persistenceManager.loadVPNPersistence(
withName: Constants.Persistence.profilesContainerName
)
#endif
let sharedVPNPersistence = persistenceManager.loadSharedVPNPersistence(
withName: Constants.Persistence.sharedProfilesContainerName
)
let providersPersistence = persistenceManager.loadProvidersPersistence(
withName: Constants.Persistence.providersContainerName
)
let remoteProvidersStrategy = APIRemoteProvidersStrategy(
appBuild: Constants.Global.appBuildNumber,
bundleServices: APIWebServices.bundledServices(
withVersion: Constants.Services.version
),
remoteServices: APIWebServices(
Constants.Services.version,
Constants.Repos.api,
timeout: Constants.Services.connectivityTimeout
),
webServicesRepository: providersPersistence.webServicesRepository()
)
providerManager = ProviderManager(
localProvidersRepository: providersPersistence.localProvidersRepository(),
remoteProvidersStrategy: remoteProvidersStrategy
)
let tvProfileRepository = sharedVPNPersistence.profileRepository()
#if !os(tvOS)
let profileRepository = vpnPersistence.profileRepository()
let sharedProfileRepository = tvProfileRepository
#else
let profileRepository = tvProfileRepository
let sharedProfileRepository: ProfileRepository? = nil
#endif
profileManager = ProfileManager(
store: store,
providerManager: providerManager,
profileRepository: profileRepository,
sharedProfileRepository: sharedProfileRepository,
keychain: KeychainSecretRepository(appGroup: Constants.App.appGroupId),
keychainEntry: Unlocalized.Keychain.passwordEntry,
keychainLabel: Unlocalized.Keychain.passwordLabel
)
#if targetEnvironment(simulator)
let vpn = MockVPN()
#else
let vpn = NetworkExtensionVPN()
#endif
let vpnManagerStrategy = TunnelKitVPNManagerStrategy(
appGroup: Constants.App.appGroupId,
tunnelBundleIdentifier: Constants.App.tunnelBundleId,
vpn: vpn
)
vpnManager = VPNManager(
store: store,
profileManager: profileManager,
providerManager: providerManager,
strategy: vpnManagerStrategy
)
// post
configureObjects(persistenceManager: persistenceManager)
}
}
private extension CoreContext {
func configureObjects(persistenceManager: PersistenceManager) {
providerManager.rateLimitMilliseconds = Constants.RateLimit.providerManager
vpnManager.tunnelLogPath = Constants.Log.Tunnel.path
vpnManager.tunnelLogFormat = Constants.Log.Tunnel.format
profileManager.observeUpdates()
vpnManager.observeUpdates()
CoreConfiguration.masksPrivateData = vpnManager.masksPrivateData
vpnManager.didUpdatePreferences
.sink {
CoreConfiguration.masksPrivateData = $0.masksPrivateData
}.store(in: &cancellables)
persistenceManager.didChangePersistence
.sink { [weak self] in
self?.reloadPersistenceObjects(persistenceManager: persistenceManager)
}.store(in: &cancellables)
}
func reloadPersistenceObjects(persistenceManager: PersistenceManager) {
let vpnPersistence = persistenceManager.loadVPNPersistence(
withName: Constants.Persistence.profilesContainerName
)
profileManager.swapProfileRepository(vpnPersistence.profileRepository())
}
}

View File

@ -1,14 +0,0 @@
{\rtf1\ansi\ansicpg1252\cocoartf2638
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 HelveticaNeue;}
{\colortbl;\red255\green255\blue255;\red0\green0\blue233;}
{\*\expandedcolortbl;;\cssrgb\c0\c0\c93333;}
\paperw11900\paperh16840\margl1440\margr1440\vieww13440\viewh7800\viewkind0
\deftab720
\pard\pardeftab720\partightenfactor0
{\field{\*\fldinst{HYPERLINK "https://github.com/passepartoutvpn/passepartout-apple/blob/master/README.md"}}{\fldrslt
\f0\fs24 \cf2 \expnd0\expndtw0\kerning0
\ul \ulc2 README}}
\f0\fs24 \expnd0\expndtw0\kerning0
\'a0\'b7\'a0{\field{\*\fldinst{HYPERLINK "https://github.com/passepartoutvpn/passepartout-apple/blob/master/CHANGELOG.md"}}{\fldrslt \cf2 \ul \ulc2 CHANGELOG}}\'a0\'b7\'a0{\field{\*\fldinst{HYPERLINK "https://passepartoutvpn.app/faq/"}}{\fldrslt \cf2 \ul \ulc2 FAQ}}\
\pard\pardeftab720\partightenfactor0
{\field{\*\fldinst{HYPERLINK "https://passepartoutvpn.app/disclaimer/"}}{\fldrslt \cf2 \ul \ulc2 Disclaimer}}\'a0\'b7\'a0{\field{\*\fldinst{HYPERLINK "https://passepartoutvpn.app/privacy/"}}{\fldrslt \cf2 \ul \ulc2 Privacy policy}}}

View File

@ -1,51 +0,0 @@
//
// AppError.swift
// Passepartout
//
// Created by Davide De Rosa on 5/30/23.
// Copyright (c) 2024 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 PassepartoutLibrary
enum AppError: Error {
case profile(Passepartout.ProfileError)
case provider(Passepartout.ProviderError)
case vpn(Passepartout.VPNError)
case tunnel(TunnelError)
case generic(Error)
init(_ error: Error) {
if let profileError = error as? Passepartout.ProfileError {
self = .profile(profileError)
} else if let providerError = error as? Passepartout.ProviderError {
self = .provider(providerError)
} else if let vpnError = error as? Passepartout.VPNError {
self = .vpn(vpnError)
} else {
self = .generic(error)
}
}
}

View File

@ -1,515 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>INEnums</key>
<array/>
<key>INIntentDefinitionModelVersion</key>
<string>1.2</string>
<key>INIntentDefinitionNamespace</key>
<string>CM6KGi</string>
<key>INIntentDefinitionSystemVersion</key>
<string>21E230</string>
<key>INIntentDefinitionToolsBuildVersion</key>
<string>13E113</string>
<key>INIntentDefinitionToolsVersion</key>
<string>13.3</string>
<key>INIntents</key>
<array>
<dict>
<key>INIntentCategory</key>
<string>generic</string>
<key>INIntentDescription</key>
<string>Connects to a host profile</string>
<key>INIntentDescriptionID</key>
<string>eXXb2z</string>
<key>INIntentLastParameterTag</key>
<integer>6</integer>
<key>INIntentName</key>
<string>ConnectVPN</string>
<key>INIntentParameterCombinations</key>
<dict>
<key>profileId,profileName</key>
<dict>
<key>INIntentParameterCombinationIsPrimary</key>
<true/>
<key>INIntentParameterCombinationSupportsBackgroundExecution</key>
<true/>
<key>INIntentParameterCombinationTitle</key>
<string>Connect to ${profileName}</string>
<key>INIntentParameterCombinationTitleID</key>
<string>U6o81V</string>
</dict>
</dict>
<key>INIntentParameters</key>
<array>
<dict>
<key>INIntentParameterDisplayPriority</key>
<integer>1</integer>
<key>INIntentParameterMetadata</key>
<dict>
<key>INIntentParameterMetadataCapitalization</key>
<string>Sentences</string>
</dict>
<key>INIntentParameterName</key>
<string>profileId</string>
<key>INIntentParameterTag</key>
<integer>4</integer>
<key>INIntentParameterType</key>
<string>String</string>
</dict>
<dict>
<key>INIntentParameterDisplayPriority</key>
<integer>2</integer>
<key>INIntentParameterMetadata</key>
<dict>
<key>INIntentParameterMetadataCapitalization</key>
<string>Sentences</string>
</dict>
<key>INIntentParameterName</key>
<string>profileName</string>
<key>INIntentParameterTag</key>
<integer>6</integer>
<key>INIntentParameterType</key>
<string>String</string>
</dict>
</array>
<key>INIntentResponse</key>
<dict>
<key>INIntentResponseCodes</key>
<array>
<dict>
<key>INIntentResponseCodeName</key>
<string>success</string>
<key>INIntentResponseCodeSuccess</key>
<true/>
</dict>
<dict>
<key>INIntentResponseCodeName</key>
<string>failure</string>
</dict>
</array>
</dict>
<key>INIntentTitle</key>
<string>Connect to VPN</string>
<key>INIntentTitleID</key>
<string>LA99yM</string>
<key>INIntentType</key>
<string>Custom</string>
<key>INIntentVerb</key>
<string>Do</string>
</dict>
<dict>
<key>INIntentCategory</key>
<string>generic</string>
<key>INIntentDescription</key>
<string>Adds current Wi-Fi to trusted networks</string>
<key>INIntentDescriptionID</key>
<string>BKxs8X</string>
<key>INIntentName</key>
<string>TrustCurrentNetwork</string>
<key>INIntentParameterCombinations</key>
<dict>
<key></key>
<dict>
<key>INIntentParameterCombinationIsPrimary</key>
<true/>
<key>INIntentParameterCombinationSupportsBackgroundExecution</key>
<true/>
<key>INIntentParameterCombinationTitle</key>
<string>Trust current Wi-Fi</string>
<key>INIntentParameterCombinationTitleID</key>
<string>POyDPM</string>
</dict>
</dict>
<key>INIntentResponse</key>
<dict>
<key>INIntentResponseCodes</key>
<array>
<dict>
<key>INIntentResponseCodeName</key>
<string>success</string>
<key>INIntentResponseCodeSuccess</key>
<true/>
</dict>
<dict>
<key>INIntentResponseCodeName</key>
<string>failure</string>
</dict>
</array>
</dict>
<key>INIntentTitle</key>
<string>Trust current Wi-Fi</string>
<key>INIntentTitleID</key>
<string>m2E7SI</string>
<key>INIntentType</key>
<string>Custom</string>
<key>INIntentVerb</key>
<string>Do</string>
</dict>
<dict>
<key>INIntentCategory</key>
<string>generic</string>
<key>INIntentDescription</key>
<string>Disables the VPN service</string>
<key>INIntentDescriptionID</key>
<string>eQ1yzr</string>
<key>INIntentName</key>
<string>DisableVPN</string>
<key>INIntentParameterCombinations</key>
<dict>
<key></key>
<dict>
<key>INIntentParameterCombinationIsPrimary</key>
<true/>
<key>INIntentParameterCombinationSupportsBackgroundExecution</key>
<true/>
<key>INIntentParameterCombinationTitle</key>
<string>Disable VPN</string>
<key>INIntentParameterCombinationTitleID</key>
<string>IeGsEq</string>
</dict>
</dict>
<key>INIntentResponse</key>
<dict>
<key>INIntentResponseCodes</key>
<array>
<dict>
<key>INIntentResponseCodeName</key>
<string>success</string>
<key>INIntentResponseCodeSuccess</key>
<true/>
</dict>
<dict>
<key>INIntentResponseCodeName</key>
<string>failure</string>
</dict>
</array>
</dict>
<key>INIntentTitle</key>
<string>Disable VPN</string>
<key>INIntentTitleID</key>
<string>1ZRTCZ</string>
<key>INIntentType</key>
<string>Custom</string>
<key>INIntentVerb</key>
<string>Do</string>
</dict>
<dict>
<key>INIntentCategory</key>
<string>generic</string>
<key>INIntentDescription</key>
<string>Removes current Wi-Fi from trusted networks</string>
<key>INIntentDescriptionID</key>
<string>7eoAss</string>
<key>INIntentName</key>
<string>UntrustCurrentNetwork</string>
<key>INIntentParameterCombinations</key>
<dict>
<key></key>
<dict>
<key>INIntentParameterCombinationIsPrimary</key>
<true/>
<key>INIntentParameterCombinationSupportsBackgroundExecution</key>
<true/>
<key>INIntentParameterCombinationTitle</key>
<string>Untrust current Wi-Fi</string>
<key>INIntentParameterCombinationTitleID</key>
<string>0Wu9nb</string>
</dict>
</dict>
<key>INIntentResponse</key>
<dict>
<key>INIntentResponseCodes</key>
<array>
<dict>
<key>INIntentResponseCodeName</key>
<string>success</string>
<key>INIntentResponseCodeSuccess</key>
<true/>
</dict>
<dict>
<key>INIntentResponseCodeName</key>
<string>failure</string>
</dict>
</array>
</dict>
<key>INIntentTitle</key>
<string>Untrust current Wi-Fi</string>
<key>INIntentTitleID</key>
<string>rd1T8p</string>
<key>INIntentType</key>
<string>Custom</string>
<key>INIntentVerb</key>
<string>Do</string>
</dict>
<dict>
<key>INIntentCategory</key>
<string>generic</string>
<key>INIntentDescription</key>
<string>Adds cellular to trusted networks</string>
<key>INIntentDescriptionID</key>
<string>9GpJt5</string>
<key>INIntentName</key>
<string>TrustCellularNetwork</string>
<key>INIntentParameterCombinations</key>
<dict>
<key></key>
<dict>
<key>INIntentParameterCombinationIsPrimary</key>
<true/>
<key>INIntentParameterCombinationSupportsBackgroundExecution</key>
<true/>
<key>INIntentParameterCombinationTitle</key>
<string>Trust cellular network</string>
<key>INIntentParameterCombinationTitleID</key>
<string>NWWgCl</string>
</dict>
</dict>
<key>INIntentResponse</key>
<dict>
<key>INIntentResponseCodes</key>
<array>
<dict>
<key>INIntentResponseCodeName</key>
<string>success</string>
<key>INIntentResponseCodeSuccess</key>
<true/>
</dict>
<dict>
<key>INIntentResponseCodeName</key>
<string>failure</string>
</dict>
</array>
</dict>
<key>INIntentTitle</key>
<string>Trust cellular network</string>
<key>INIntentTitleID</key>
<string>H4taev</string>
<key>INIntentType</key>
<string>Custom</string>
<key>INIntentVerb</key>
<string>Do</string>
</dict>
<dict>
<key>INIntentCategory</key>
<string>generic</string>
<key>INIntentDescription</key>
<string>Removes cellular from trusted networks</string>
<key>INIntentDescriptionID</key>
<string>0jRWn5</string>
<key>INIntentName</key>
<string>UntrustCellularNetwork</string>
<key>INIntentParameterCombinations</key>
<dict>
<key></key>
<dict>
<key>INIntentParameterCombinationIsPrimary</key>
<true/>
<key>INIntentParameterCombinationSupportsBackgroundExecution</key>
<true/>
<key>INIntentParameterCombinationTitle</key>
<string>Untrust cellular network</string>
<key>INIntentParameterCombinationTitleID</key>
<string>ggzKA2</string>
</dict>
</dict>
<key>INIntentResponse</key>
<dict>
<key>INIntentResponseCodes</key>
<array>
<dict>
<key>INIntentResponseCodeName</key>
<string>success</string>
<key>INIntentResponseCodeSuccess</key>
<true/>
</dict>
<dict>
<key>INIntentResponseCodeName</key>
<string>failure</string>
</dict>
</array>
</dict>
<key>INIntentTitle</key>
<string>Untrust cellular network</string>
<key>INIntentTitleID</key>
<string>wB1iYX</string>
<key>INIntentType</key>
<string>Custom</string>
<key>INIntentVerb</key>
<string>Do</string>
</dict>
<dict>
<key>INIntentCategory</key>
<string>generic</string>
<key>INIntentDescription</key>
<string>Connects to a specific location of a provider profile</string>
<key>INIntentDescriptionID</key>
<string>KjkCfU</string>
<key>INIntentLastParameterTag</key>
<integer>4</integer>
<key>INIntentName</key>
<string>MoveToLocation</string>
<key>INIntentParameterCombinations</key>
<dict>
<key>serverName,providerFullName,serverId,profileId</key>
<dict>
<key>INIntentParameterCombinationSubtitle</key>
<string>With ${providerFullName} provider</string>
<key>INIntentParameterCombinationSubtitleID</key>
<string>OeVNIO</string>
<key>INIntentParameterCombinationSupportsBackgroundExecution</key>
<true/>
<key>INIntentParameterCombinationTitle</key>
<string>Connect to ${serverName}</string>
<key>INIntentParameterCombinationTitleID</key>
<string>nzeF6m</string>
</dict>
</dict>
<key>INIntentParameters</key>
<array>
<dict>
<key>INIntentParameterDisplayPriority</key>
<integer>1</integer>
<key>INIntentParameterMetadata</key>
<dict>
<key>INIntentParameterMetadataCapitalization</key>
<string>Sentences</string>
</dict>
<key>INIntentParameterName</key>
<string>profileId</string>
<key>INIntentParameterTag</key>
<integer>2</integer>
<key>INIntentParameterType</key>
<string>String</string>
</dict>
<dict>
<key>INIntentParameterDisplayPriority</key>
<integer>2</integer>
<key>INIntentParameterMetadata</key>
<dict>
<key>INIntentParameterMetadataCapitalization</key>
<string>Sentences</string>
<key>INIntentParameterMetadataDefaultValueID</key>
<string>Cf6h1r</string>
</dict>
<key>INIntentParameterName</key>
<string>providerFullName</string>
<key>INIntentParameterTag</key>
<integer>4</integer>
<key>INIntentParameterType</key>
<string>String</string>
</dict>
<dict>
<key>INIntentParameterDisplayPriority</key>
<integer>3</integer>
<key>INIntentParameterMetadata</key>
<dict>
<key>INIntentParameterMetadataCapitalization</key>
<string>Sentences</string>
</dict>
<key>INIntentParameterName</key>
<string>serverId</string>
<key>INIntentParameterTag</key>
<integer>3</integer>
<key>INIntentParameterType</key>
<string>String</string>
</dict>
<dict>
<key>INIntentParameterDisplayPriority</key>
<integer>4</integer>
<key>INIntentParameterMetadata</key>
<dict>
<key>INIntentParameterMetadataCapitalization</key>
<string>Sentences</string>
</dict>
<key>INIntentParameterName</key>
<string>serverName</string>
<key>INIntentParameterTag</key>
<integer>1</integer>
<key>INIntentParameterType</key>
<string>String</string>
</dict>
</array>
<key>INIntentResponse</key>
<dict>
<key>INIntentResponseCodes</key>
<array>
<dict>
<key>INIntentResponseCodeName</key>
<string>success</string>
<key>INIntentResponseCodeSuccess</key>
<true/>
</dict>
<dict>
<key>INIntentResponseCodeName</key>
<string>failure</string>
</dict>
</array>
</dict>
<key>INIntentTitle</key>
<string>Connect to provider location</string>
<key>INIntentTitleID</key>
<string>qo3Szz</string>
<key>INIntentType</key>
<string>Custom</string>
<key>INIntentVerb</key>
<string>Go</string>
</dict>
<dict>
<key>INIntentCategory</key>
<string>generic</string>
<key>INIntentDescription</key>
<string>Enables the VPN service with the profile currently in use</string>
<key>INIntentDescriptionID</key>
<string>xY97Vu</string>
<key>INIntentName</key>
<string>EnableVPN</string>
<key>INIntentParameterCombinations</key>
<dict>
<key></key>
<dict>
<key>INIntentParameterCombinationIsPrimary</key>
<true/>
<key>INIntentParameterCombinationSubtitle</key>
<string>With profile in use</string>
<key>INIntentParameterCombinationSubtitleID</key>
<string>NCoK9B</string>
<key>INIntentParameterCombinationSupportsBackgroundExecution</key>
<true/>
<key>INIntentParameterCombinationTitle</key>
<string>Enable VPN</string>
<key>INIntentParameterCombinationTitleID</key>
<string>yesvFP</string>
</dict>
</dict>
<key>INIntentResponse</key>
<dict>
<key>INIntentResponseCodes</key>
<array>
<dict>
<key>INIntentResponseCodeName</key>
<string>success</string>
<key>INIntentResponseCodeSuccess</key>
<true/>
</dict>
<dict>
<key>INIntentResponseCodeName</key>
<string>failure</string>
</dict>
</array>
</dict>
<key>INIntentTitle</key>
<string>Enable VPN</string>
<key>INIntentTitleID</key>
<string>lQ6ziK</string>
<key>INIntentType</key>
<string>Custom</string>
<key>INIntentVerb</key>
<string>Do</string>
</dict>
</array>
<key>INTypes</key>
<array/>
</dict>
</plist>

View File

@ -1,161 +0,0 @@
//
// IntentDispatcher+Activities.swift
// Passepartout
//
// Created by Davide De Rosa on 3/30/22.
// Copyright (c) 2024 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/>.
//
#if !os(tvOS)
import Foundation
import Intents
import PassepartoutLibrary
@MainActor
extension IntentDispatcher {
typealias VPNIntentActivity = IntentActivity<VPNManager>
static let enableVPN = VPNIntentActivity(name: Constants.Activities.enableVPN) { _, vpnManager in
pp_log.info("Enabling VPN...")
Task {
do {
try await vpnManager.connectWithActiveProfile(toServer: nil)
} catch {
pp_log.error("Unable to connect with active profile: \(error)")
ErrorHandler.shared.handle(error)
}
}
}
static let disableVPN = VPNIntentActivity(name: Constants.Activities.disableVPN) { _, vpnManager in
pp_log.info("Disabling VPN...")
Task {
await vpnManager.disable()
}
}
static let connectVPN = VPNIntentActivity(name: Constants.Activities.connectVPN) { activity, vpnManager in
pp_log.info("Connecting VPN...")
guard let intent = activity.interaction?.intent as? ConnectVPNIntent else {
assertionFailure("Not a ConnectVPNIntent?")
return
}
guard let uuid = intent.profileId, let profileId = UUID(uuidString: uuid) else {
assertionFailure("Profile id is not valid")
if let interactionIdentifier = activity.interaction?.identifier {
INInteraction.delete(with: [interactionIdentifier], completion: nil)
}
return
}
Task {
do {
_ = try await vpnManager.connect(with: profileId)
} catch {
pp_log.error("Unable to connect with profile \(profileId): \(error)")
ErrorHandler.shared.handle(error)
}
}
}
static let moveToLocation = VPNIntentActivity(name: Constants.Activities.moveToLocation) { activity, vpnManager in
pp_log.info("Moving to VPN location...")
guard let intent = activity.interaction?.intent as? MoveToLocationIntent else {
assertionFailure("Not a MoveToLocationIntent?")
return
}
guard let uuid = intent.profileId, let profileId = UUID(uuidString: uuid) else {
if let interactionIdentifier = activity.interaction?.identifier {
INInteraction.delete(with: [interactionIdentifier], completion: nil)
}
return
}
guard let newServerId = intent.serverId else {
assertionFailure("Missing serverId")
if let interactionIdentifier = activity.interaction?.identifier {
INInteraction.delete(with: [interactionIdentifier], completion: nil)
}
return
}
Task {
do {
_ = try await vpnManager.connect(with: profileId, toServer: newServerId)
} catch {
pp_log.error("Unable to connect with profile \(profileId): \(error)")
ErrorHandler.shared.handle(error)
}
}
}
static let trustCellularNetwork = VPNIntentActivity(name: Constants.Activities.trustCellularNetwork) { _, vpnManager in
pp_log.info("Trusting mobile network...")
handleCellularNetwork(true, vpnManager)
}
static let trustCurrentNetwork = VPNIntentActivity(name: Constants.Activities.trustCurrentNetwork) { _, vpnManager in
pp_log.info("Trusting current Wi-Fi...")
handleCurrentNetwork(true, vpnManager)
}
static let untrustCellularNetwork = VPNIntentActivity(name: Constants.Activities.untrustCellularNetwork) { _, vpnManager in
pp_log.info("Untrusting mobile network...")
handleCellularNetwork(false, vpnManager)
}
static let untrustCurrentNetwork = VPNIntentActivity(name: Constants.Activities.untrustCurrentNetwork) { _, vpnManager in
pp_log.info("Untrusting current Wi-Fi...")
handleCurrentNetwork(false, vpnManager)
}
private static func handleCellularNetwork(_ trust: Bool, _ vpnManager: VPNManager) {
Task {
do {
try await vpnManager.modifyActiveProfile {
$0.onDemand.withMobileNetwork = trust
}
} catch {
pp_log.error("Unable to modify cellular trust: \(error)")
ErrorHandler.shared.handle(error)
}
}
}
private static func handleCurrentNetwork(_ trust: Bool, _ vpnManager: VPNManager) {
Task {
guard let ssid = await Utils.currentWifiSSID() else {
pp_log.warning("Not connected to any Wi-Fi or no permission to read location (needs 'While Using' or 'Always')")
return
}
do {
try await vpnManager.modifyActiveProfile {
pp_log.info("Wi-Fi SSID: \(ssid)")
$0.onDemand.withSSIDs[ssid] = trust
}
} catch {
pp_log.error("Unable to modify Wi-Fi trust: \(error)")
ErrorHandler.shared.handle(error)
}
}
}
}
#endif

View File

@ -1,161 +0,0 @@
//
// IntentDispatcher.swift
// Passepartout
//
// Created by Davide De Rosa on 3/8/19.
// Copyright (c) 2024 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/>.
//
#if !os(tvOS)
import Foundation
import Intents
import PassepartoutLibrary
@MainActor
final class IntentDispatcher {
private struct Groups {
static let vpn = "VPN"
static let trust = "Trust"
}
// MARK: Intents
static func intentConnect(header: Profile.Header) -> ConnectVPNIntent {
let intent = ConnectVPNIntent()
intent.profileId = header.id.uuidString
intent.profileName = header.name
return intent
}
static func intentMoveTo(header: Profile.Header, providerFullName: String, server: ProviderServer) -> MoveToLocationIntent {
let intent = MoveToLocationIntent()
intent.profileId = header.id.uuidString
intent.providerFullName = providerFullName
intent.serverId = server.id
intent.serverName = server.localizedDescription(style: .longWithCategory(withCategory: false))
return intent
}
static func intentEnable() -> EnableVPNIntent {
EnableVPNIntent()
}
static func intentDisable() -> DisableVPNIntent {
DisableVPNIntent()
}
static func intentTrustWiFi() -> TrustCurrentNetworkIntent {
TrustCurrentNetworkIntent()
}
static func intentUntrustWiFi() -> UntrustCurrentNetworkIntent {
UntrustCurrentNetworkIntent()
}
static func intentTrustCellular() -> TrustCellularNetworkIntent {
TrustCellularNetworkIntent()
}
static func intentUntrustCellular() -> UntrustCellularNetworkIntent {
UntrustCellularNetworkIntent()
}
// MARK: Donations
static func donateConnection(with profile: Profile, providerManager: ProviderManager) {
let genericIntent: INIntent
if let providerName = profile.header.providerName {
guard let provider = providerManager.provider(withName: providerName) else {
pp_log.warning("Intent provider not found")
return
}
guard let server = profile.providerServer(providerManager) else {
pp_log.warning("Intent server not found")
return
}
genericIntent = intentMoveTo(header: profile.header, providerFullName: provider.fullName, server: server)
} else {
genericIntent = intentConnect(header: profile.header)
}
let interaction = INInteraction(intent: genericIntent, response: nil)
interaction.groupIdentifier = profile.id.uuidString
interaction.donateAndLog()
}
static func donateEnableVPN() {
let interaction = INInteraction(intent: intentEnable(), response: nil)
interaction.groupIdentifier = Groups.vpn
interaction.donateAndLog()
}
static func donateDisableVPN() {
let interaction = INInteraction(intent: intentDisable(), response: nil)
interaction.groupIdentifier = Groups.vpn
interaction.donateAndLog()
}
static func donateTrustCurrentNetwork() {
let interaction = INInteraction(intent: intentTrustWiFi(), response: nil)
interaction.groupIdentifier = Groups.trust
interaction.donateAndLog()
}
static func donateUntrustCurrentNetwork() {
let interaction = INInteraction(intent: intentUntrustWiFi(), response: nil)
interaction.groupIdentifier = Groups.trust
interaction.donateAndLog()
}
static func donateTrustCellularNetwork() {
let interaction = INInteraction(intent: intentTrustCellular(), response: nil)
interaction.groupIdentifier = Groups.trust
interaction.donateAndLog()
}
static func donateUntrustCellularNetwork() {
let interaction = INInteraction(intent: intentUntrustCellular(), response: nil)
interaction.groupIdentifier = Groups.trust
interaction.donateAndLog()
}
static func forgetProfile(withHeader header: Profile.Header) {
INInteraction.delete(with: header.id.uuidString) { (error) in
if let error = error {
pp_log.warning("Unable to forget interactions: \(error)")
return
}
pp_log.debug("Removed profile \(header.name) interactions")
}
}
}
private extension INInteraction {
func donateAndLog() {
donate { (error) in
if let error = error {
pp_log.error("Unable to donate interaction: \(error)")
}
pp_log.debug("Donated \(self.intent)")
}
}
}
#endif

View File

@ -1,52 +0,0 @@
//
// Picker+Network.swift
// Passepartout
//
// Created by Davide De Rosa on 2/26/22.
// Copyright (c) 2024 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 PassepartoutLibrary
import TunnelKitCore
extension Network.DNSSettings {
static func availableConfigurationTypes(forVPNProtocol vpnProtocol: VPNProtocolType) -> [ConfigurationType] {
switch vpnProtocol {
case .openVPN:
return [.plain, .https, .tls, .disabled]
case .wireGuard:
return [.plain, .https, .tls, .disabled]
}
}
}
extension Network.ProxySettings {
static let availableConfigurationTypes: [ConfigurationType] = [
.manual,
.pac,
.disabled
]
}
extension Network.MTUSettings {
static let availableBytes: [Int] = [0, 1500, 1400, 1300, 1200]
}

View File

@ -1,63 +0,0 @@
//
// Picker+OpenVPN.swift
// Passepartout
//
// Created by Davide De Rosa on 6/22/19.
// Copyright (c) 2024 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 TunnelKitOpenVPN
extension OpenVPN.Cipher {
static let available: [OpenVPN.Cipher] = [
.aes256gcm,
.aes192gcm,
.aes128gcm,
.aes256cbc,
.aes192cbc,
.aes128cbc
]
}
extension OpenVPN.Digest {
static let available: [OpenVPN.Digest] = [
.sha1,
.sha224,
.sha256,
.sha384,
.sha512
]
}
extension OpenVPN.CompressionFraming {
static let available: [OpenVPN.CompressionFraming] = [
.disabled,
.compLZO,
.compress
]
}
extension OpenVPN.CompressionAlgorithm {
static let available: [OpenVPN.CompressionAlgorithm] = [
.disabled,
.LZO
]
}

View File

@ -1,45 +0,0 @@
"0jRWn5" = "Entfernt Mobilfunknetz von vertrauten Netzwerken";
"IeGsEq" = "VPN deaktivieren";
"1ZRTCZ" = "VPN deaktivieren";
"66bZBE" = "Mit Anbieter ${providerFullName}";
"7eoAss" = "Entferne aktuelles WLAN von vertrauten Netzwerken";
"9GpJt5" = "Fügt Mobilnetz zu vertrauten Netzwerken hinzu";
"BKxs8X" = "Fügt aktuelles WLAN zu vertrauten Netzwerken hinzu";
"NWWgCl" = "Mobilfunknetz vertrauen";
"H4taev" = "Mobilfunknetz vertrauen";
"KjkCfU" = "Connects to a specific location of a provider profile";
"LA99yM" = "Verbinde mit VPN";
"U6o81V" = "Verbinde mit ${profileName}";
"WnTPFg" = "Verbinde mit ${serverName}";
"eQ1yzr" = "Deaktiviert den VPN-Dienst";
"eXXb2z" = "Verbindet mit einem Hostprofil";
"yesvFP" = "Aktiviere VPN";
"lQ6ziK" = "Aktiviere VPN";
"POyDPM" = "Vertraue aktuellem WLAN";
"m2E7SI" = "Vertraue aktuellem WLAN";
"qo3Szz" = "Verbinde mit Anbieter-Ort";
"0Wu9nb" = "Aktuellem WLAN nicht vertrauen";
"rd1T8p" = "Aktuellem WLAN nicht vertrauen";
"ggzKA2" = "Mobilfunknetz nicht vertrauen";
"wB1iYX" = "Mobilfunknetz nicht vertrauen";
"xY97Vu" = "Aktiviert den VPN-Dienst mit dem derzeitig benutzten Profil";
"NCoK9B" = "Mit dem benutzten Profil";

View File

@ -1,45 +0,0 @@
"0jRWn5" = "Αφαιρεί το κινητό δίκτυο από τα αξιόπιστα δίκτυα";
"IeGsEq" = "Απενεργοποίηση VPN";
"1ZRTCZ" = "Απενεργοποίηση VPN";
"66bZBE" = "Με ${providerFullName} πάροχο";
"7eoAss" = "Αφαίρεση συνδεδεμένου Wi-Fi από τα έμπιστα δίκτυα";
"9GpJt5" = "Προσθέτει το κινητό δίκτυο στα αξιόπιστα δίκτυα";
"BKxs8X" = "Προσθήκη τρέχων Wi-Fi στα έμπιστα δίκτυα";
"NWWgCl" = "Αξιόπιστο Δίκτυο κινητής τηλεφωνίας";
"H4taev" = "Αξιόπιστο Δίκτυο κινητής τηλεφωνίας";
"KjkCfU" = "Συνδέετε σε μια συγκεκριμένη τοποθεσία ενός προφίλ παρόχου";
"LA99yM" = "Σύνδεση VPN";
"U6o81V" = "Σύνδεση στο ${profileName}";
"WnTPFg" = "Σύνδεση σε ${serverName}";
"eQ1yzr" = "Απενεργοποίηση υπηρεσίας VPN";
"eXXb2z" = "Συνδέεται σε ένα προφίλ διακομιστή";
"yesvFP" = "Ενεργοποίηση VPN";
"lQ6ziK" = "Ενεργοποίηση VPN";
"POyDPM" = "Εμπιστευθείτε το τρέχον Wi-Fi";
"m2E7SI" = "Εμπιστευθείτε το τρέχον Wi-Fi";
"qo3Szz" = "Συνδεθείτε με τη θέση του παρόχου";
"0Wu9nb" = "Μην εμπιστευθείτε το τρέχον Wi-Fi";
"rd1T8p" = "Μην εμπιστευθείτε το τρέχον Wi-Fi";
"ggzKA2" = "Μη αξιόπιστο κινητό δίκτυο";
"wB1iYX" = "Μη αξιόπιστο κινητό δίκτυο";
"xY97Vu" = "Ενεργοποιεί την υπηρεσία VPN με το προφίλ που χρησιμοποιείται αυτήν τη στιγμή";
"NCoK9B" = "Με προφίλ σε χρήση";

View File

@ -1,45 +0,0 @@
"0jRWn5" = "Removes cellular from trusted networks";
"IeGsEq" = "Disable VPN";
"1ZRTCZ" = "Disable VPN";
"66bZBE" = "With ${providerFullName} provider";
"7eoAss" = "Removes current Wi-Fi from trusted networks";
"9GpJt5" = "Adds cellular to trusted networks";
"BKxs8X" = "Adds current Wi-Fi to trusted networks";
"NWWgCl" = "Trust cellular network";
"H4taev" = "Trust cellular network";
"KjkCfU" = "Connects to a specific location of a provider profile";
"LA99yM" = "Connect to VPN";
"U6o81V" = "Connect to ${profileName}";
"WnTPFg" = "Connect to ${serverName}";
"eQ1yzr" = "Disables the VPN service";
"eXXb2z" = "Connects to a host profile";
"yesvFP" = "Enable VPN";
"lQ6ziK" = "Enable VPN";
"POyDPM" = "Trust current Wi-Fi";
"m2E7SI" = "Trust current Wi-Fi";
"qo3Szz" = "Connect to provider location";
"0Wu9nb" = "Untrust current Wi-Fi";
"rd1T8p" = "Untrust current Wi-Fi";
"ggzKA2" = "Untrust cellular network";
"wB1iYX" = "Untrust cellular network";
"xY97Vu" = "Enables the VPN service with the profile currently in use";
"NCoK9B" = "With profile in use";

View File

@ -1,45 +0,0 @@
"0jRWn5" = "Borra la red móvil de las redes de confianza";
"IeGsEq" = "Deshabilitar VPN";
"1ZRTCZ" = "Deshabilitar VPN";
"66bZBE" = "Con el proveedor ${providerFullName}";
"7eoAss" = "Borra el Wi-Fi en uso de las redes de confianza";
"9GpJt5" = "Añade la red móvil a las redes de confianza";
"BKxs8X" = "Añade el Wi-Fi en uso a las redes de confianza";
"NWWgCl" = "Añadir red móvil de confianza";
"H4taev" = "Añadir red móvil de confianza";
"KjkCfU" = "Conecta con una región específica de un proveedor";
"LA99yM" = "Conectar con el VPN";
"U6o81V" = "Conectar con ${profileName}";
"WnTPFg" = "Conectar con ${serverName}";
"eQ1yzr" = "Deshabilita el servicio VPN";
"eXXb2z" = "Conecta con un host";
"yesvFP" = "Habilitar VPN";
"lQ6ziK" = "Habilitar VPN";
"POyDPM" = "Añadir Wi-Fi de confianza";
"m2E7SI" = "Añadir Wi-Fi de confianza";
"qo3Szz" = "Conectar con una región del proveedor";
"0Wu9nb" = "Borrar Wi-Fi de confianza";
"rd1T8p" = "Borrar Wi-Fi de confianza";
"ggzKA2" = "Borrar red móvil de confianza";
"wB1iYX" = "Borrar red móvil de confianza";
"xY97Vu" = "Habilita el servicio VPN con el perfil en uso";
"NCoK9B" = "Con el perfil en uso";

View File

@ -1,45 +0,0 @@
"0jRWn5" = "Supprime le réseau cellulaire des réseaux de confiance";
"IeGsEq" = "Désactive VPN";
"1ZRTCZ" = "Désactive VPN";
"66bZBE" = "Avec ${providerFullName} fournisseur";
"7eoAss" = "Supprime le présent réseaux Wi-Fi des réseaux de confiance ";
"9GpJt5" = "Ajoutes le réseau cellulaire aux réseaux de confiance";
"BKxs8X" = "Ajoutes le présent réseau Wi-Fi aux réseaux de confiance";
"NWWgCl" = "Faire confiance au réseau cellulaire";
"H4taev" = "Faire confiance au réseau cellulaire";
"KjkCfU" = "Connecter à une localization spécifique d'un profile de fournisseur";
"LA99yM" = "Se connecter au VPN";
"U6o81V" = "Se connecter à ${profileName}";
"WnTPFg" = "Se connecter à ${serverName}";
"eQ1yzr" = "Désactives le service VPN";
"eXXb2z" = "Connectes à un profile hôte";
"yesvFP" = "Activer VPN";
"lQ6ziK" = "Activer VPN";
"POyDPM" = "Faire confiance au présent réseau Wi-Fi";
"m2E7SI" = "Faire confiance au présent réseau Wi-Fi";
"qo3Szz" = "Se connecter à la localisation du fournisseur";
"0Wu9nb" = "Ne plus faire confiance au présent réseau Wi-Fi";
"rd1T8p" = "Ne plus faire confiance au présent réseau Wi-Fi";
"ggzKA2" = "Faire confiance au présent réseau cellulaire";
"wB1iYX" = "Faire confiance au présent réseau cellulaire";
"xY97Vu" = "Activer le service VPN avec le profile présentement utilisé";
"NCoK9B" = "Avec le profile utilisé";

View File

@ -1,45 +0,0 @@
"0jRWn5" = "Rimuove la rete mobile dalle reti sicure";
"IeGsEq" = "Disabilita VPN";
"1ZRTCZ" = "Disabilita VPN";
"66bZBE" = "Con il provider ${providerFullName}";
"7eoAss" = "Rimuove la Wi-Fi corrente dalle reti sicure";
"9GpJt5" = "Aggiunge la rete mobile alle reti sicure";
"BKxs8X" = "Aggiunge la Wi-Fi corrente alle reti sicure";
"NWWgCl" = "Aggiungi rete mobile sicura";
"H4taev" = "Aggiungi rete mobile sicura";
"KjkCfU" = "Avvia una connessione ad una regione specifica di un provider";
"LA99yM" = "Connetti alla VPN";
"U6o81V" = "Connettiti a ${profileName}";
"WnTPFg" = "Connettiti in ${serverName}";
"eQ1yzr" = "Disabilita il servizio VPN";
"eXXb2z" = "Avvia la connessione ad un host";
"yesvFP" = "Abilita VPN";
"lQ6ziK" = "Abilita VPN";
"POyDPM" = "Aggiungi Wi-Fi sicura";
"m2E7SI" = "Aggiungi Wi-Fi sicura";
"qo3Szz" = "Connettiti a una regione del provider";
"0Wu9nb" = "Rimuovi Wi-Fi sicura";
"rd1T8p" = "Rimuovi Wi-Fi sicura";
"ggzKA2" = "Rimuovi rete mobile sicura";
"wB1iYX" = "Rimuovi rete mobile sicura";
"xY97Vu" = "Abilita il servizio VPN con il profilo attualmente in uso";
"NCoK9B" = "Con il profilo in uso";

View File

@ -1,45 +0,0 @@
"0jRWn5" = "Verwijder Mobielnetwerk van vertrouwde netwerken";
"IeGsEq" = "Disable VPN";
"1ZRTCZ" = "Disable VPN";
"66bZBE" = "Met ${providerFullName} aanbieder";
"7eoAss" = "Verwijder huidige Wi-Fi van vertrouwde netwerken";
"9GpJt5" = "Voeg Mobielnetwerk to aan vertrouwde netwerken";
"BKxs8X" = "Voeg huidig Wi-Fi toe aan vertrouwde netwerken";
"NWWgCl" = "Vertrouw mobiel netwerk";
"H4taev" = "Vertrouw mobiel netwerk";
"KjkCfU" = "Maak verbinding met een specifieke lokatie van een aanbieder profiel";
"LA99yM" = "Verbind VPN";
"U6o81V" = "Verbind met ${profileName}";
"WnTPFg" = "Verbind met ${serverName}";
"eQ1yzr" = "Schakel VPN service uit";
"eXXb2z" = "Verbind met een host profiel";
"yesvFP" = "Schakel VPN in";
"lQ6ziK" = "Schakel VPN in";
"POyDPM" = "Vertrouw huidig Wi-Fi netwerk";
"m2E7SI" = "Vertrouw huidig Wi-Fi netwerk";
"qo3Szz" = "Maak verbinding met de locatie van de aanbieder";
"0Wu9nb" = "Wantrouw huidig Wi-Fi netwerk";
"rd1T8p" = "Wantrouw huidig Wi-Fi netwerk";
"ggzKA2" = "Wantrouw modbiel netwerk";
"wB1iYX" = "Wantrouw modbiel netwerk";
"xY97Vu" = "Schakel de VPN-service in met het profiel dat momenteel in gebruik is";
"NCoK9B" = "Met het profiel dat momenteel in gebruik is";

View File

@ -1,45 +0,0 @@
"0jRWn5" = "Usuwa dane komórkowe z zaufanych sieci";
"IeGsEq" = "Wyłącz VPN";
"1ZRTCZ" = "Wyłącz VPN";
"66bZBE" = "Z usługodawcą ${providerFullName}";
"7eoAss" = "Usuwa obecnie połączoną sieć Wi-Fi z zaufanych sieci";
"9GpJt5" = "Dodaje dane komórkowe do zaufanych sieci";
"BKxs8X" = "Dodaje obecnie połączoną sieć Wi-Fi do zaufanych sieci";
"NWWgCl" = "Ufaj danym komórkowym";
"H4taev" = "Ufaj danym komórkowym";
"KjkCfU" = "Łączy z wybraną lokalizacją profilu usługodawcy";
"LA99yM" = "Połącz z VPN";
"U6o81V" = "Połącz z ${profileName}";
"WnTPFg" = "Połącz z ${serverName}";
"eQ1yzr" = "Wyłącza VPN";
"eXXb2z" = "Łączy z profilem hosta";
"yesvFP" = "Włącz VPN";
"lQ6ziK" = "Włącz VPN";
"POyDPM" = "Zaufaj obecnie połączonej sieci Wi-Fi";
"m2E7SI" = "Zaufaj obecnie połączonej sieci Wi-Fi";
"qo3Szz" = "Połącz z lokalizacją usługodawcy";
"0Wu9nb" = "Nie ufaj obecnie połączonej sieci Wi-Fi";
"rd1T8p" = "Nie ufaj obecnie połączonej sieci Wi-Fi";
"ggzKA2" = "Nie ufaj danym komórkowym";
"wB1iYX" = "Nie ufaj danym komórkowym";
"xY97Vu" = "Włącza VPN używając wybranego obecnie profilu";
"NCoK9B" = "Z profilem w użyciu";

View File

@ -1,45 +0,0 @@
"0jRWn5" = "Remover celular de conexões seguras";
"IeGsEq" = "Desativar VPN";
"1ZRTCZ" = "Desativar VPN";
"66bZBE" = "Com o provedor ${providerFullName}";
"7eoAss" = "Remover Wi-Fi atual de conexões seguras";
"9GpJt5" = "Adicionar celular em conexões seguras";
"BKxs8X" = "Adicionar Wi-Fi atual em conexões seguras";
"NWWgCl" = "Confiar em rede celular";
"H4taev" = "Confiar em rede celular";
"KjkCfU" = "Conectar em uma localização específica de um provedor";
"LA99yM" = "Conectar VPN";
"U6o81V" = "Conectar ${profileName}";
"WnTPFg" = "Conectar ${serverName}";
"eQ1yzr" = "Desabilitar serviço de VPN";
"eXXb2z" = "Conectar em um host";
"yesvFP" = "Ativar VPN";
"lQ6ziK" = "Ativar VPN";
"POyDPM" = "Confiar na Wi-Fi atual";
"m2E7SI" = "Confiar na Wi-Fi atual";
"qo3Szz" = "Conectar em uma região do provedor";
"0Wu9nb" = "Não confiar na Wi-Fi atual";
"rd1T8p" = "Não confiar na Wi-Fi atual";
"ggzKA2" = "Não confiar na conexão celular";
"wB1iYX" = "Não confiar na conexão celular";
"xY97Vu" = "Ativar o serviço VPN no perfil em uso";
"NCoK9B" = "Com o perfil em uso";

View File

@ -1,45 +0,0 @@
"0jRWn5" = "Удаляет мобильную сеть из доверенных подключений";
"IeGsEq" = "Отключить VPN";
"1ZRTCZ" = "Отключить VPN";
"66bZBE" = "С ${providerFullName} провайдером";
"7eoAss" = "Удаляет текущий Wi-Fi из доверенных подключений";
"9GpJt5" = "Добавляет мобильную сеть в доверенные подключения";
"BKxs8X" = "Добавляет текущий  Wi-Fi в доверенные подключения";
"NWWgCl" = "Доверять мобильной сети";
"H4taev" = "Доверять мобильной сети";
"KjkCfU" = "Подключиться к конкретному местоположению провайдера";
"LA99yM" = "Подключиться к VPN";
"U6o81V" = "Подключиться к ${profileName}";
"WnTPFg" = "Подключиться к ${serverName}";
"eQ1yzr" = "Отключить этот VPN сервис";
"eXXb2z" = "Подключается к хост профилю";
"yesvFP" = "Включить VPN";
"lQ6ziK" = "Включить VPN";
"POyDPM" = "Доверять текущему Wi-Fi";
"m2E7SI" = "Доверять текущему Wi-Fi";
"qo3Szz" = "Подключиться к местоположению провайдера";
"0Wu9nb" = "Не доверять текущему Wi-Fi";
"rd1T8p" = "Не доверять текущему Wi-Fi";
"ggzKA2" = "Не доверять мобильной сети";
"wB1iYX" = "Не доверять мобильной сети";
"xY97Vu" = "Включает VPN с используемым профилем";
"NCoK9B" = "С используемым профилем";

View File

@ -1,45 +0,0 @@
"0jRWn5" = "Tar bort cellular från betrodda nätverk";
"IeGsEq" = "Avstäng VPN";
"1ZRTCZ" = "Avstäng VPN";
"66bZBE" = "Med ${providerFullName} leverantör";
"7eoAss" = "Tar bort nuvarande Wi-Fi från betrodda nätverk";
"9GpJt5" = "Tillsätter cellular till lita betrodda nätverk";
"BKxs8X" = "Tillsätter nuvarande Wi-Fi till betrodda nätverk";
"NWWgCl" = "Lita på cellular nätverk";
"H4taev" = "Lita på cellular nätverk";
"KjkCfU" = "Koppla till en specifik plats från en leverantör profil";
"LA99yM" = "Koppla till VPN";
"U6o81V" = "Koppla till ${profileName}";
"WnTPFg" = "Koppla till ${serverName}";
"eQ1yzr" = "Avstäng VPN service";
"eXXb2z" = "Koppla till en host profil";
"yesvFP" = "Avstäng VPN";
"lQ6ziK" = "Avstäng VPN";
"POyDPM" = "lita på närvarande Wi-Fi";
"m2E7SI" = "lita på närvarande Wi-Fi";
"qo3Szz" = "Koppla till provider plats";
"0Wu9nb" = "Untrust närvarande Wi-Fi";
"rd1T8p" = "Untrust närvarande Wi-Fi";
"ggzKA2" = "Untrust cellular nätverk";
"wB1iYX" = "Untrust cellular nätverk";
"xY97Vu" = "På-sätter VPN service med närvarande profil";
"NCoK9B" = "Med profil i andvänding";

View File

@ -1,45 +0,0 @@
"0jRWn5" = "Видаляє мобільну мережу з довірених підключень";
"IeGsEq" = "Вимкнути VPN";
"1ZRTCZ" = "Вимкнути VPN";
"66bZBE" = "З ${providerFullName} провайдером";
"7eoAss" = "Видаляє поточний Wi-Fi з довірених підключень";
"9GpJt5" = "Додає мобільну мережу у довірені підключеня";
"BKxs8X" = "Додає поточний Wi-Fi у довірені підключеня";
"NWWgCl" = "Довіряти мобільній мережі";
"H4taev" = "Довіряти мобільній мережі";
"KjkCfU" = "Підключитися до конкретного розташування провайдеру";
"LA99yM" = "Підключитися до VPN";
"U6o81V" = "Підключитися до ${profileName}";
"WnTPFg" = "Підключитися до ${serverName}";
"eQ1yzr" = "Відключити цей VPN сервіс";
"eXXb2z" = "Підключитися до хост профілю";
"yesvFP" = "Увімкнути VPN";
"lQ6ziK" = "Увімкнути VPN";
"POyDPM" = "Довіряти поточному Wi-Fi";
"m2E7SI" = "Довіряти поточному Wi-Fi";
"qo3Szz" = "Підключитися до розташування провайдеру";
"0Wu9nb" = "Не довіряти поточному Wi-Fi";
"rd1T8p" = "Не довіряти поточному Wi-Fi";
"ggzKA2" = "Не довіряти мобільній мережі";
"wB1iYX" = "Не довіряти мобільній мережі";
"xY97Vu" = "Вмикає VPN з профілем, що використовується";
"NCoK9B" = "З профілем, що використовується";

View File

@ -1,45 +0,0 @@
"0jRWn5" = "从可信网络中移除蜂窝网络";
"IeGsEq" = "禁用VPN";
"1ZRTCZ" = "禁用VPN";
"66bZBE" = "使用 ${providerFullName} 提供商配置";
"7eoAss" = "从可信网络中移除当前Wi-Fi";
"9GpJt5" = "添加蜂窝网络到可信网络中";
"BKxs8X" = "添加当前Wi-Fi到可信网络中";
"NWWgCl" = "信任蜂窝网络";
"H4taev" = "信任蜂窝网络";
"KjkCfU" = "连接到指定地区的提供商配置";
"LA99yM" = "连接到VPN";
"U6o81V" = "连接到${profileId}";
"WnTPFg" = "连接到${serverName}";
"eQ1yzr" = "禁用VPN服务";
"eXXb2z" = "连接到主机配置";
"yesvFP" = "启用VPN";
"lQ6ziK" = "启用VPN";
"POyDPM" = "信任当前Wi-Fi";
"m2E7SI" = "信任当前Wi-Fi";
"qo3Szz" = "连接到提供商的地区";
"0Wu9nb" = "不信任当前Wi-Fi";
"rd1T8p" = "不信任当前Wi-Fi";
"ggzKA2" = "不信任当前蜂窝网络";
"wB1iYX" = "不信任当前蜂窝网络";
"xY97Vu" = "使用当前配置启用VPN服务";
"NCoK9B" = "该配置在被使用";

View File

@ -1,123 +0,0 @@
//
// PassepartoutProviders+Extensions.swift
// Passepartout
//
// Created by Davide De Rosa on 11/4/21.
// Copyright (c) 2024 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 PassepartoutLibrary
extension ProviderMetadata: Identifiable, Comparable, Hashable {
public var id: String {
name
}
public static func == (lhs: Self, rhs: Self) -> Bool {
lhs.name == rhs.name
}
public static func < (lhs: Self, rhs: Self) -> Bool {
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 {
lhs.name.lowercased() == rhs.name.lowercased()
}
public static func < (lhs: Self, rhs: Self) -> Bool {
lhs.name.lowercased() < rhs.name.lowercased()
}
}
extension ProviderLocation: Comparable {
public static func == (lhs: Self, rhs: Self) -> Bool {
lhs.countryCode == rhs.countryCode
}
public static func < (lhs: Self, rhs: Self) -> Bool {
lhs.localizedDescription(style: .country) < rhs.localizedDescription(style: .country)
}
}
extension ProviderServer: Comparable {
public static func == (lhs: Self, rhs: Self) -> Bool {
lhs.id == rhs.id
}
// "Default" comes first (nil localizedName)
public static func < (lhs: Self, rhs: Self) -> Bool {
guard lhs.localizedName != rhs.localizedName else {
guard let li = lhs.serverIndex else {
return true
}
guard let ri = rhs.serverIndex else {
return false
}
guard li != ri else {
guard lhs.apiId != rhs.apiId else {
return lhs.tags?.joined() ?? "" < rhs.tags?.joined() ?? ""
}
return lhs.apiId < rhs.apiId
}
return li < ri
}
guard let ld = lhs.localizedName else {
return true
}
guard let rd = rhs.localizedName else {
return false
}
return ld < rd
}
}
extension ProviderServer.Preset: Comparable {
public static func == (lhs: Self, rhs: Self) -> Bool {
lhs.name == rhs.name
}
public static func < (lhs: Self, rhs: Self) -> Bool {
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)
}
}

View File

@ -1,82 +0,0 @@
//
// TunnelKit+Extensions.swift
// Passepartout
//
// Created by Davide De Rosa on 3/12/22.
// Copyright (c) 2024 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 {
[address, proto.port.description, proto.socketType.rawValue].joined(separator: ":")
}
}
extension Endpoint: Comparable {
public static func < (lhs: Self, rhs: Self) -> Bool {
guard lhs.address != rhs.address else {
return lhs.proto < rhs.proto
}
guard lhs.isHostname == rhs.isHostname else {
return lhs.isHostname
}
return lhs.address < rhs.address
}
}
extension Endpoint: Hashable {
}
extension EndpointProtocol: Comparable {
public static func < (lhs: Self, rhs: Self) -> Bool {
guard lhs.socketType != rhs.socketType else {
return lhs.port < rhs.port
}
return lhs.socketType.orderValue < rhs.socketType.orderValue
}
}
private extension SocketType {
var orderValue: Int {
switch self {
case .udp: return 1
case .udp4: return 2
case .udp6: return 3
case .tcp: return 4
case .tcp4: return 5
case .tcp6: return 6
}
}
}
extension IPv4Settings.Route: Identifiable {
public var id: String {
[destination, mask, gateway ?? "*"].joined(separator: ":")
}
}
extension IPv6Settings.Route: Identifiable {
public var id: String {
[destination, prefixLength.description, gateway ?? "*"].joined(separator: ":")
}
}

View File

@ -1,6 +0,0 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -1,9 +0,0 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"provides-namespace" : true
}
}

View File

@ -1,22 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "ad@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "ad@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 960 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -1,22 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "ae@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "ae@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 B

View File

@ -1,22 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "af@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "af@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -1,22 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "ag@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "ag@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -1,22 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "ai@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "ai@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -1,22 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "al@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "al@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -1,22 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "am@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "am@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 B

View File

@ -1,22 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "ao@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "ao@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 785 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,22 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "aq@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "aq@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 918 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,22 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "ar@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "ar@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 565 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1,22 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "as@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "as@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -1,22 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "at@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "at@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 B

View File

@ -1,22 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "au@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "au@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -1,22 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "aw@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "aw@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 909 B

Some files were not shown because too many files have changed in this diff Show More