|
@ -1 +0,0 @@
|
|||
1130
|
|
@ -1 +0,0 @@
|
|||
3630
|
|
@ -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
|
|
@ -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
|
|
@ -2,10 +2,8 @@ name: Release
|
|||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
paths:
|
||||
- ".beta-build"
|
||||
tags:
|
||||
- "builds/*"
|
||||
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
@ -13,172 +11,47 @@ env:
|
|||
FASTLANE_USERNAME: ${{ secrets.FASTLANE_USERNAME }}
|
||||
FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build_upload:
|
||||
name: Upload to ASC
|
||||
runs-on: macos-13
|
||||
runs-on: macos-14
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
name: ["iOS", "macOS", "tvOS"]
|
||||
#name: ["iOS", "macOS", "tvOS"]
|
||||
name: ["iOS", "macOS"]
|
||||
include:
|
||||
- name: "iOS"
|
||||
platform: "ios"
|
||||
use_version: true
|
||||
- name: "macOS"
|
||||
platform: "mac"
|
||||
- name: "tvOS"
|
||||
platform: "tvos"
|
||||
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 }}
|
||||
GYM_OUTPUT_DIRECTORY: "dist/${{ matrix.platform }}"
|
||||
platform: "macos"
|
||||
#- name: "tvOS"
|
||||
# platform: "tvos"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/checkout@v4
|
||||
- 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
|
||||
- name: Access private repositories
|
||||
env:
|
||||
PILOT_USERNAME: ${{ secrets.PILOT_USERNAME }}
|
||||
PILOT_GROUPS: ${{ secrets.PILOT_GROUPS }}
|
||||
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:
|
||||
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 }}
|
||||
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 }}
|
||||
PILOT_GROUPS: ${{ vars.PILOT_GROUPS }}
|
||||
run: |
|
||||
if [ $PLATFORM == "mac" ]; then
|
||||
export PILOT_PKG="$GYM_OUTPUT_DIRECTORY/Passepartout.pkg"
|
||||
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 }}
|
||||
ci/recognize-match-hostname.sh
|
||||
bundle exec fastlane --env ${{ matrix.platform }} beta
|
||||
|
|
|
@ -4,36 +4,35 @@ on:
|
|||
pull_request:
|
||||
types: [ opened, synchronize ]
|
||||
paths-ignore:
|
||||
- '.beta-*'
|
||||
- '.env.*'
|
||||
- '**/*.md'
|
||||
- '**/*.sh'
|
||||
- '**/*.yml'
|
||||
- 'Passepartout/App/fastlane/**'
|
||||
- 'fastlane/**'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
run_tests:
|
||||
name: Run tests
|
||||
runs-on: macos-13
|
||||
runs-on: macos-14
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: "15.1"
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
bundler-cache: true
|
||||
- uses: actions/setup-go@v4
|
||||
- uses: maxim-lobanov/setup-xcode@v1
|
||||
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
|
||||
run: |
|
||||
cd PassepartoutLibrary
|
||||
cd Passepartout/Library
|
||||
swift test
|
||||
|
|
|
@ -2,21 +2,19 @@
|
|||
*.swp
|
||||
*.pbxuser
|
||||
**/xcuserdata
|
||||
Pods
|
||||
**/fastlane/**/*.html
|
||||
**/fastlane/README.md
|
||||
**/fastlane/report.xml
|
||||
**/fastlane/test_output
|
||||
**/fastlane/*/metadata/review_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/
|
||||
dist/
|
||||
/iap
|
||||
templates/
|
||||
vendor/
|
||||
Preview.html
|
||||
default.profraw
|
||||
.build
|
||||
.bundle
|
||||
.env.secret*
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
[submodule "PassepartoutLibrary/Sources/PassepartoutServices/API"]
|
||||
path = PassepartoutLibrary/Sources/PassepartoutProvidersImpl/API
|
||||
url = https://github.com/passepartoutvpn/api
|
|
@ -1,7 +1,9 @@
|
|||
included:
|
||||
- Passepartout
|
||||
- PassepartoutLibrary/Sources
|
||||
- PassepartoutLibrary/Tests
|
||||
- Passepartout/App
|
||||
- Passepartout/Library/Sources
|
||||
- Passepartout/Library/Tests
|
||||
- Passepartout/Shared
|
||||
- Passepartout/Tunnel
|
||||
analyzer_rules:
|
||||
- unused_declaration
|
||||
- unused_import
|
||||
|
@ -14,5 +16,6 @@ disabled_rules:
|
|||
- function_body_length
|
||||
- identifier_name
|
||||
- line_length
|
||||
- inclusive_language
|
||||
- nesting
|
||||
- todo
|
||||
|
|
|
@ -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.
|
|
@ -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.
|
169
CHANGELOG.md
|
@ -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)
|
2
Gemfile
|
@ -1,6 +1,6 @@
|
|||
source "https://rubygems.org"
|
||||
|
||||
gem "fastlane"
|
||||
gem "fastlane", ">= 2.2.0", :github => "keeshux/fastlane", :branch => "bugfix/build-multiplatform-for-ipa-pkg"
|
||||
gem "dotenv"
|
||||
|
||||
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
|
||||
|
|
178
Gemfile.lock
|
@ -1,74 +1,9 @@
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
GIT
|
||||
remote: https://github.com/keeshux/fastlane.git
|
||||
revision: d08c54ec635ea28fe797d76a56af8a83548ecc96
|
||||
branch: bugfix/build-multiplatform-for-ipa-pkg
|
||||
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.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)
|
||||
fastlane (2.221.1)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.8, < 3.0.0)
|
||||
artifactory (~> 3.0)
|
||||
|
@ -109,6 +44,83 @@ GEM
|
|||
xcodeproj (>= 1.13.0, < 2.0.0)
|
||||
xcpretty (~> 0.3.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)
|
||||
google-apis-androidpublisher_v3 (0.54.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
|
@ -149,22 +161,37 @@ GEM
|
|||
highline (2.0.3)
|
||||
http-cookie (1.0.7)
|
||||
domain_name (~> 0.5)
|
||||
httparty (0.22.0)
|
||||
csv
|
||||
mini_mime (>= 1.0.0)
|
||||
multi_xml (>= 0.5.2)
|
||||
httpclient (2.8.3)
|
||||
jmespath (1.6.2)
|
||||
json (2.7.2)
|
||||
jwt (2.9.0)
|
||||
base64
|
||||
loco_strings (0.1.4.1)
|
||||
nokogiri (~> 1.13, >= 1.13.8)
|
||||
mini_magick (4.13.2)
|
||||
mini_mime (1.1.5)
|
||||
mini_portile2 (2.8.7)
|
||||
multi_json (1.15.0)
|
||||
multi_xml (0.7.1)
|
||||
bigdecimal (~> 3.1)
|
||||
multipart-post (2.4.1)
|
||||
nanaimo (0.3.0)
|
||||
naturally (2.2.1)
|
||||
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)
|
||||
os (1.1.4)
|
||||
plist (3.7.1)
|
||||
public_suffix (6.0.1)
|
||||
racc (1.8.1)
|
||||
rake (13.2.1)
|
||||
representable (3.2.0)
|
||||
declarative (< 0.1.0)
|
||||
|
@ -173,6 +200,8 @@ GEM
|
|||
retriable (3.1.2)
|
||||
rexml (3.3.7)
|
||||
rouge (2.0.7)
|
||||
ruby-openai (3.7.0)
|
||||
httparty (>= 0.18.1)
|
||||
ruby2_keywords (0.0.5)
|
||||
rubyzip (2.3.2)
|
||||
security (0.1.5)
|
||||
|
@ -209,12 +238,13 @@ GEM
|
|||
|
||||
PLATFORMS
|
||||
arm64-darwin-23
|
||||
x86_64-darwin-21
|
||||
x86_64-linux
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
dotenv
|
||||
fastlane
|
||||
fastlane (>= 2.2.0)!
|
||||
fastlane-plugin-translate_gpt
|
||||
fastlane-plugin-versioning
|
||||
|
||||
BUNDLED WITH
|
||||
2.5.17
|
||||
2.5.14
|
||||
|
|
|
@ -1,12 +1,21 @@
|
|||
{
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "generic-json-swift",
|
||||
"identity" : "dtfoundation",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/zoul/generic-json-swift",
|
||||
"location" : "https://github.com/Cocoanetics/DTFoundation.git",
|
||||
"state" : {
|
||||
"revision" : "0a06575f4038b504e78ac330913d920f1630f510",
|
||||
"version" : "2.0.2"
|
||||
"revision" : "76062513434421cb6c8a1ae1d4f8368a7ebc2da3",
|
||||
"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",
|
||||
"location" : "https://github.com/passepartoutvpn/openssl-apple",
|
||||
"state" : {
|
||||
"revision" : "026702febcaebcbf9ea68f2fa66b017eba998cdf",
|
||||
"version" : "3.2.105"
|
||||
"revision" : "0edc07c7a0e4ec2ca0f448dd68314241ccc925b3",
|
||||
"version" : "3.2.107"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swiftybeaver",
|
||||
"identity" : "passepartoutkit",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/SwiftyBeaver/SwiftyBeaver",
|
||||
"location" : "git@github.com:passepartoutvpn/passepartoutkit",
|
||||
"state" : {
|
||||
"revision" : "12b5acf96d98f91d50de447369bd18df74600f1a",
|
||||
"version" : "1.9.6"
|
||||
"revision" : "2c32459d6a669e8feed0e6ea2d1250ef72364aa3",
|
||||
"version" : "0.7.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "tunnelkit",
|
||||
"identity" : "passepartoutkit-openvpn-openssl",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/passepartoutvpn/tunnelkit",
|
||||
"location" : "git@github.com:passepartoutvpn/passepartoutkit-openvpn-openssl",
|
||||
"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",
|
||||
"location" : "https://github.com/passepartoutvpn/wireguard-apple",
|
||||
"state" : {
|
||||
"revision" : "b79f0f150356d8200a64922ecf041dd020140aa0"
|
||||
"revision" : "a896f784bc5ed94f29d97e376be5cfa08d4a5d44",
|
||||
"version" : "1.1.1"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1510"
|
||||
LastUpgradeVersion = "1540"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -14,54 +14,12 @@
|
|||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0E57F63720C83FC5008323CF"
|
||||
BlueprintIdentifier = "0E06D18E2B87629100176E1D"
|
||||
BuildableName = "Passepartout.app"
|
||||
BlueprintName = "Passepartout"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</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>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
|
@ -70,21 +28,11 @@
|
|||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0E57F63720C83FC5008323CF"
|
||||
BuildableName = "Passepartout.app"
|
||||
BlueprintName = "Passepartout"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = "it"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
@ -95,7 +43,7 @@
|
|||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0E57F63720C83FC5008323CF"
|
||||
BlueprintIdentifier = "0E06D18E2B87629100176E1D"
|
||||
BuildableName = "Passepartout.app"
|
||||
BlueprintName = "Passepartout"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
|
@ -103,35 +51,33 @@
|
|||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "-com.apple.CoreData.SQLDebug 0"
|
||||
isEnabled = "YES">
|
||||
argument = "-com.apple.CoreData.SQLDebug 1"
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "-com.apple.CoreData.Logging.stderr 0 "
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "-com.apple.CoreData.CloudKitDebug 0"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "-com.apple.CoreData.ConcurrencyDebug 0"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "-com.apple.CoreData.MigrationDebug 0"
|
||||
argument = " -com.apple.CoreData.ConcurrencyDebug 1"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "APP_TYPE"
|
||||
value = "0"
|
||||
key = "SQLITE_ENABLE_THREAD_ASSERTIONS"
|
||||
value = "1"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
<EnvironmentVariable
|
||||
key = "LOG_LEVEL"
|
||||
value = "0"
|
||||
key = "SQLITE_ENABLE_FILE_ASSERTIONS"
|
||||
value = "1"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
<EnvironmentVariable
|
||||
key = "SQLITE_AUTO_TRACE"
|
||||
value = "1"
|
||||
isEnabled = "NO">
|
||||
</EnvironmentVariable>
|
||||
<EnvironmentVariable
|
||||
key = "CUSTOM_USER_LEVEL"
|
||||
value = "2"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
|
@ -146,7 +92,7 @@
|
|||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0E57F63720C83FC5008323CF"
|
||||
BlueprintIdentifier = "0E06D18E2B87629100176E1D"
|
||||
BuildableName = "Passepartout.app"
|
||||
BlueprintName = "Passepartout"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1510"
|
||||
version = "1.3">
|
||||
LastUpgradeVersion = "1540"
|
||||
wasCreatedForAppExtension = "YES"
|
||||
version = "2.0">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
|
@ -14,9 +15,23 @@
|
|||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0E41BD96286711C3006346B4"
|
||||
BuildableName = "PassepartoutLauncher.app"
|
||||
BlueprintName = "PassepartoutLauncher"
|
||||
BlueprintIdentifier = "0EC332C72B8A1808000B9C2F"
|
||||
BuildableName = "PassepartoutTunnel.appex"
|
||||
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">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
|
@ -26,27 +41,28 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
selectedDebuggerIdentifier = ""
|
||||
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||
launchStyle = "0"
|
||||
askForAppToLaunch = "Yes"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
allowLocationSimulation = "YES"
|
||||
launchAutomaticallySubstyle = "2">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0E41BD96286711C3006346B4"
|
||||
BuildableName = "PassepartoutLauncher.app"
|
||||
BlueprintName = "PassepartoutLauncher"
|
||||
BlueprintIdentifier = "0E06D18E2B87629100176E1D"
|
||||
BuildableName = "Passepartout.app"
|
||||
BlueprintName = "Passepartout"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
|
@ -56,14 +72,16 @@
|
|||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
debugDocumentVersioning = "YES"
|
||||
askForAppToLaunch = "Yes"
|
||||
launchAutomaticallySubstyle = "2">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0E41BD96286711C3006346B4"
|
||||
BuildableName = "PassepartoutLauncher.app"
|
||||
BlueprintName = "PassepartoutLauncher"
|
||||
BlueprintIdentifier = "0E06D18E2B87629100176E1D"
|
||||
BuildableName = "Passepartout.app"
|
||||
BlueprintName = "Passepartout"
|
||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
|
@ -2,40 +2,29 @@
|
|||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>aps-environment</key>
|
||||
<string>development</string>
|
||||
<key>com.apple.developer.icloud-container-identifiers</key>
|
||||
<array>
|
||||
<string>iCloud.com.algoritmico.Passepartout</string>
|
||||
<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>
|
||||
<array>
|
||||
<string>packet-tunnel-provider</string>
|
||||
</array>
|
||||
<key>com.apple.developer.networking.wifi-info</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.siri</key>
|
||||
<true/>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.$(CFG_GROUP_ID)</string>
|
||||
<string>$(CFG_GROUP_ID)</string>
|
||||
</array>
|
||||
<key>com.apple.security.files.user-selected.read-write</key>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
<key>com.apple.security.personal-information.location</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$(AppIdentifierPrefix)group.com.algoritmico.Passepartout</string>
|
||||
<string>$(AppIdentifierPrefix)$(CFG_GROUP_ID)</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -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>
|
|
@ -2,7 +2,7 @@
|
|||
// AppDelegate.swift
|
||||
// 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.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
|
@ -23,37 +23,31 @@
|
|||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import PassepartoutLibrary
|
||||
#if os(iOS)
|
||||
|
||||
import UIKit
|
||||
|
||||
final class AppDelegate: UIResponder, UIApplicationDelegate, ObservableObject {
|
||||
private let mac = MacBundle.shared
|
||||
final class AppDelegate: NSObject, UIApplicationDelegate {
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
|
||||
#if targetEnvironment(macCatalyst)
|
||||
mac.configure()
|
||||
mac.menu.install()
|
||||
if mac.utils.isStartedByLauncher {
|
||||
mac.utils.sendAppToBackground()
|
||||
}
|
||||
#endif
|
||||
return true
|
||||
#else
|
||||
|
||||
import AppKit
|
||||
import CommonLibrary
|
||||
import PassepartoutKit
|
||||
|
||||
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 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)
|
||||
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,15 +1,6 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x68",
|
||||
"green" : "0x9C",
|
||||
"red" : "0xD6"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
|
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 62 KiB |
|
@ -47,12 +47,13 @@
|
|||
"size" : "256x256"
|
||||
},
|
||||
{
|
||||
"filename" : "AppIcon-mac.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "512x512"
|
||||
},
|
||||
{
|
||||
"filename" : "AppIcon-mac.png",
|
||||
"filename" : "AppIcon-mac@2x.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "512x512"
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
]
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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())
|
||||
}
|
||||
}
|
|
@ -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}}}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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
|
|
@ -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
|
|
@ -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]
|
||||
}
|
|
@ -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
|
||||
]
|
||||
}
|
|
@ -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";
|
|
@ -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" = "Με προφίλ σε χρήση";
|
|
@ -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";
|
|
@ -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";
|
|
@ -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é";
|
|
@ -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";
|
|
@ -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";
|
|
@ -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";
|
|
@ -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";
|
|
@ -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" = "С используемым профилем";
|
|
@ -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";
|
|
@ -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" = "З профілем, що використовується";
|
|
@ -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" = "该配置在被使用";
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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: ":")
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"provides-namespace" : true
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 960 B |
Before Width: | Height: | Size: 1.7 KiB |
|
@ -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"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 182 B |
Before Width: | Height: | Size: 216 B |
|
@ -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"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.9 KiB |
|
@ -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"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 2.1 KiB |
|
@ -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"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 3.4 KiB |
|
@ -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"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 2.4 KiB |
|
@ -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"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 164 B |
Before Width: | Height: | Size: 187 B |
|
@ -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"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 785 B |
Before Width: | Height: | Size: 1.2 KiB |
|
@ -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"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 918 B |
Before Width: | Height: | Size: 1.3 KiB |
|
@ -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"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 565 B |
Before Width: | Height: | Size: 1.0 KiB |
|
@ -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"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 3.3 KiB |
|
@ -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"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 175 B |
Before Width: | Height: | Size: 199 B |
|
@ -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"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 3.3 KiB |
|
@ -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"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 631 B |
Before Width: | Height: | Size: 909 B |