|
@ -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:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
tags:
|
||||||
- "master"
|
- "builds/*"
|
||||||
paths:
|
|
||||||
- ".beta-build"
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
@ -13,172 +11,47 @@ env:
|
||||||
FASTLANE_USERNAME: ${{ secrets.FASTLANE_USERNAME }}
|
FASTLANE_USERNAME: ${{ secrets.FASTLANE_USERNAME }}
|
||||||
FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }}
|
FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }}
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_upload:
|
build_upload:
|
||||||
name: Upload to ASC
|
name: Upload to ASC
|
||||||
runs-on: macos-13
|
runs-on: macos-14
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: true
|
fail-fast: true
|
||||||
matrix:
|
matrix:
|
||||||
name: ["iOS", "macOS", "tvOS"]
|
#name: ["iOS", "macOS", "tvOS"]
|
||||||
|
name: ["iOS", "macOS"]
|
||||||
include:
|
include:
|
||||||
- name: "iOS"
|
- name: "iOS"
|
||||||
platform: "ios"
|
platform: "ios"
|
||||||
use_version: true
|
|
||||||
- name: "macOS"
|
- name: "macOS"
|
||||||
platform: "mac"
|
platform: "macos"
|
||||||
- name: "tvOS"
|
#- name: "tvOS"
|
||||||
platform: "tvos"
|
# platform: "tvos"
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: ruby/setup-ruby@v1
|
||||||
|
with:
|
||||||
|
bundler-cache: true
|
||||||
|
- name: Access private repositories
|
||||||
|
env:
|
||||||
|
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||||
|
run: |
|
||||||
|
git config --global url.https://$ACCESS_TOKEN@github.com/.insteadOf git@github.com:
|
||||||
|
- name: Upload ${{ matrix.name }} app
|
||||||
|
id: upload_app
|
||||||
|
timeout-minutes: 15
|
||||||
env:
|
env:
|
||||||
PLATFORM: ${{ matrix.platform }}
|
|
||||||
MATCH_USERNAME: ${{ secrets.MATCH_USERNAME }}
|
MATCH_USERNAME: ${{ secrets.MATCH_USERNAME }}
|
||||||
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
|
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
|
||||||
MATCH_GIT_URL: ${{ secrets.MATCH_GIT_URL }}
|
MATCH_GIT_URL: ${{ secrets.MATCH_GIT_URL }}
|
||||||
MATCH_GIT_PRIVATE_KEY: ${{ secrets.MATCH_GIT_PRIVATE_KEY }}
|
MATCH_GIT_PRIVATE_KEY: ${{ secrets.MATCH_GIT_PRIVATE_KEY }}
|
||||||
GYM_OUTPUT_DIRECTORY: "dist/${{ matrix.platform }}"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
- uses: ruby/setup-ruby@v1
|
|
||||||
with:
|
|
||||||
bundler-cache: true
|
|
||||||
- uses: actions/setup-go@v4
|
|
||||||
with:
|
|
||||||
go-version: "^1.17"
|
|
||||||
- uses: maxim-lobanov/setup-xcode@v1
|
|
||||||
with:
|
|
||||||
xcode-version: "latest-stable"
|
|
||||||
- name: Store app version
|
|
||||||
id: app_version
|
|
||||||
if: ${{ matrix.use_version }}
|
|
||||||
run: |
|
|
||||||
VERSION=`ci/version-number.sh $PLATFORM`
|
|
||||||
BUILD=`ci/build-number.sh $PLATFORM`
|
|
||||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
||||||
echo "build=$BUILD" >> $GITHUB_OUTPUT
|
|
||||||
- name: Preinstall certificates (SSH)
|
|
||||||
run: |
|
|
||||||
scripts/ci/recognize-match-hostname.sh
|
|
||||||
bundle exec fastlane --env ${{ matrix.platform }} match development
|
|
||||||
# - name: Run tests
|
|
||||||
# run: |
|
|
||||||
# cd PassepartoutLibrary
|
|
||||||
# swift test
|
|
||||||
- name: Build ${{ matrix.name }} app
|
|
||||||
timeout-minutes: 15
|
|
||||||
run: |
|
|
||||||
bundle exec fastlane --env $PLATFORM,beta test_and_build_app test:false
|
|
||||||
- name: Submit to TestFlight
|
|
||||||
env:
|
|
||||||
PILOT_USERNAME: ${{ secrets.PILOT_USERNAME }}
|
|
||||||
PILOT_GROUPS: ${{ secrets.PILOT_GROUPS }}
|
|
||||||
PILOT_BETA_APP_FEEDBACK: ${{ secrets.PILOT_BETA_APP_FEEDBACK }}
|
PILOT_BETA_APP_FEEDBACK: ${{ secrets.PILOT_BETA_APP_FEEDBACK }}
|
||||||
PILOT_BETA_APP_REVIEW_INFO: ${{ secrets.PILOT_BETA_APP_REVIEW_INFO }}
|
PILOT_BETA_APP_REVIEW_INFO: ${{ secrets.PILOT_BETA_APP_REVIEW_INFO }}
|
||||||
PILOT_NOTIFY_EXTERNAL_TESTERS: ${{ secrets.PILOT_NOTIFY_EXTERNAL_TESTERS }}
|
PILOT_GROUPS: ${{ vars.PILOT_GROUPS }}
|
||||||
CHANGELOG_PREFACE: ${{ secrets.CHANGELOG_PREFACE }}
|
|
||||||
run: |
|
run: |
|
||||||
if [ $PLATFORM == "mac" ]; then
|
ci/recognize-match-hostname.sh
|
||||||
export PILOT_PKG="$GYM_OUTPUT_DIRECTORY/Passepartout.pkg"
|
bundle exec fastlane --env ${{ matrix.platform }} beta
|
||||||
else
|
|
||||||
export PILOT_IPA="$GYM_OUTPUT_DIRECTORY/Passepartout.ipa"
|
|
||||||
fi
|
|
||||||
export PILOT_CHANGELOG=`ci/build-changelog.sh $PLATFORM`
|
|
||||||
bundle exec fastlane --env $PLATFORM,beta run pilot
|
|
||||||
outputs:
|
|
||||||
version: ${{ steps.app_version.outputs.version }}
|
|
||||||
build: ${{ steps.app_version.outputs.build }}
|
|
||||||
distribute_public_beta:
|
|
||||||
name: Distribute Public Beta
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build_upload
|
|
||||||
environment:
|
|
||||||
name: public_beta
|
|
||||||
url: "https://testflight.apple.com/join/K71mtLjZ"
|
|
||||||
env:
|
|
||||||
PILOT_APP_VERSION: ${{ needs.build_upload.outputs.version }}
|
|
||||||
PILOT_BUILD_NUMBER: ${{ needs.build_upload.outputs.build }}
|
|
||||||
PILOT_USERNAME: ${{ secrets.PILOT_USERNAME }}
|
|
||||||
PILOT_GROUPS: ${{ secrets.PILOT_GROUPS }}
|
|
||||||
PILOT_NOTIFY_EXTERNAL_TESTERS: ${{ secrets.PILOT_NOTIFY_EXTERNAL_TESTERS }}
|
|
||||||
PILOT_DISTRIBUTE_ONLY: true
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
- uses: ruby/setup-ruby@v1
|
|
||||||
with:
|
|
||||||
bundler-cache: true
|
|
||||||
- name: Publish on TestFlight (iOS)
|
|
||||||
run: |
|
|
||||||
bundle exec fastlane --env ios,beta run pilot
|
|
||||||
- name: Publish on TestFlight (macOS)
|
|
||||||
run: |
|
|
||||||
bundle exec fastlane --env mac,beta run pilot
|
|
||||||
- name: Publish on TestFlight (tvOS)
|
|
||||||
run: |
|
|
||||||
bundle exec fastlane --env tvos,beta run pilot
|
|
||||||
submit_for_app_review:
|
|
||||||
name: Submit to App Review
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build_upload
|
|
||||||
environment:
|
|
||||||
name: app_review
|
|
||||||
env:
|
|
||||||
DELIVER_USERNAME: ${{ secrets.DELIVER_USERNAME }}
|
|
||||||
DELIVER_APP_VERSION: ${{ needs.build_upload.outputs.version }}
|
|
||||||
DELIVER_BUILD_NUMBER: ${{ needs.build_upload.outputs.build }}
|
|
||||||
DELIVER_FORCE: true
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
- uses: ruby/setup-ruby@v1
|
|
||||||
with:
|
|
||||||
bundler-cache: true
|
|
||||||
- name: Submit for App Review (iOS)
|
|
||||||
run: |
|
|
||||||
bundle exec fastlane --env ios deliver_review add_id_info_uses_idfa:false
|
|
||||||
- name: Submit for App Review (macOS)
|
|
||||||
run: |
|
|
||||||
bundle exec fastlane --env mac deliver_review add_id_info_uses_idfa:false
|
|
||||||
- name: Submit for App Review (tvOS)
|
|
||||||
run: |
|
|
||||||
bundle exec fastlane --env tvos deliver_review add_id_info_uses_idfa:false
|
|
||||||
publish_to_app_store:
|
|
||||||
name: Publish to App Store
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [build_upload, submit_for_app_review]
|
|
||||||
environment:
|
|
||||||
name: app_store
|
|
||||||
env:
|
|
||||||
TAG_NAME: ${{ needs.build_upload.outputs.version }}
|
|
||||||
RELEASE_NOTES: release-notes.txt
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
- name: Import GPG key
|
|
||||||
uses: crazy-max/ghaction-import-gpg@v5
|
|
||||||
with:
|
|
||||||
gpg_private_key: ${{ secrets.GPG_KEY }}
|
|
||||||
passphrase: ${{ secrets.GPG_PASSPHRASE }}
|
|
||||||
git_user_signingkey: true
|
|
||||||
git_commit_gpgsign: true
|
|
||||||
git_tag_gpgsign: true
|
|
||||||
git_push_gpgsign: false
|
|
||||||
- name: Tag release
|
|
||||||
run: |
|
|
||||||
scripts/ci/tag-release.sh $TAG_NAME
|
|
||||||
git push --tags
|
|
||||||
- name: Assemble notes
|
|
||||||
run: |
|
|
||||||
scripts/ci/release-notes.sh $TAG_NAME >$RELEASE_NOTES
|
|
||||||
- name: Publish release
|
|
||||||
uses: softprops/action-gh-release@v1
|
|
||||||
with:
|
|
||||||
tag_name: "v${{ env.TAG_NAME }}"
|
|
||||||
body_path: ${{ env.RELEASE_NOTES }}
|
|
||||||
draft: true
|
|
||||||
files: |
|
|
||||||
${{ env.RELEASE_NOTES }}
|
|
||||||
|
|
|
@ -4,36 +4,35 @@ on:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [ opened, synchronize ]
|
types: [ opened, synchronize ]
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '.beta-*'
|
|
||||||
- '.env.*'
|
- '.env.*'
|
||||||
- '**/*.md'
|
- '**/*.md'
|
||||||
- '**/*.sh'
|
- '**/*.sh'
|
||||||
- '**/*.yml'
|
- '**/*.yml'
|
||||||
- 'Passepartout/App/fastlane/**'
|
- 'fastlane/**'
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
run_tests:
|
run_tests:
|
||||||
name: Run tests
|
name: Run tests
|
||||||
runs-on: macos-13
|
runs-on: macos-14
|
||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
- uses: maxim-lobanov/setup-xcode@v1
|
|
||||||
with:
|
|
||||||
xcode-version: "15.1"
|
|
||||||
- uses: ruby/setup-ruby@v1
|
- uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
bundler-cache: true
|
bundler-cache: true
|
||||||
- uses: actions/setup-go@v4
|
- uses: maxim-lobanov/setup-xcode@v1
|
||||||
with:
|
with:
|
||||||
go-version: "^1.17"
|
xcode-version: 15.4
|
||||||
|
- name: Access private repositories
|
||||||
|
env:
|
||||||
|
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||||
|
run: |
|
||||||
|
git config --global url.https://$ACCESS_TOKEN@github.com/.insteadOf git@github.com:
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: |
|
run: |
|
||||||
cd PassepartoutLibrary
|
cd Passepartout/Library
|
||||||
swift test
|
swift test
|
||||||
|
|
|
@ -2,21 +2,19 @@
|
||||||
*.swp
|
*.swp
|
||||||
*.pbxuser
|
*.pbxuser
|
||||||
**/xcuserdata
|
**/xcuserdata
|
||||||
Pods
|
|
||||||
**/fastlane/**/*.html
|
**/fastlane/**/*.html
|
||||||
**/fastlane/README.md
|
**/fastlane/README.md
|
||||||
**/fastlane/report.xml
|
**/fastlane/report.xml
|
||||||
**/fastlane/test_output
|
**/fastlane/test_output
|
||||||
**/fastlane/*/metadata/review_information
|
**/fastlane/*/metadata/review_information
|
||||||
**/fastlane/*/metadata/trade_representative_contact_information
|
**/fastlane/*/metadata/trade_representative_contact_information
|
||||||
dist/
|
|
||||||
iap/
|
|
||||||
templates/
|
|
||||||
.env.secret*
|
|
||||||
Preview.html
|
|
||||||
passepartout-translations.zip
|
|
||||||
default.profraw
|
|
||||||
asc-key.json
|
|
||||||
.bundle
|
|
||||||
vendor/
|
|
||||||
build/
|
build/
|
||||||
|
dist/
|
||||||
|
/iap
|
||||||
|
templates/
|
||||||
|
vendor/
|
||||||
|
Preview.html
|
||||||
|
default.profraw
|
||||||
|
.build
|
||||||
|
.bundle
|
||||||
|
.env.secret*
|
||||||
|
|
|
@ -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:
|
included:
|
||||||
- Passepartout
|
- Passepartout/App
|
||||||
- PassepartoutLibrary/Sources
|
- Passepartout/Library/Sources
|
||||||
- PassepartoutLibrary/Tests
|
- Passepartout/Library/Tests
|
||||||
|
- Passepartout/Shared
|
||||||
|
- Passepartout/Tunnel
|
||||||
analyzer_rules:
|
analyzer_rules:
|
||||||
- unused_declaration
|
- unused_declaration
|
||||||
- unused_import
|
- unused_import
|
||||||
|
@ -14,5 +16,6 @@ disabled_rules:
|
||||||
- function_body_length
|
- function_body_length
|
||||||
- identifier_name
|
- identifier_name
|
||||||
- line_length
|
- line_length
|
||||||
|
- inclusive_language
|
||||||
- nesting
|
- nesting
|
||||||
- todo
|
- todo
|
||||||
|
|
|
@ -1,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"
|
source "https://rubygems.org"
|
||||||
|
|
||||||
gem "fastlane"
|
gem "fastlane", ">= 2.2.0", :github => "keeshux/fastlane", :branch => "bugfix/build-multiplatform-for-ipa-pkg"
|
||||||
gem "dotenv"
|
gem "dotenv"
|
||||||
|
|
||||||
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
|
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
|
||||||
|
|
178
Gemfile.lock
|
@ -1,74 +1,9 @@
|
||||||
GEM
|
GIT
|
||||||
remote: https://rubygems.org/
|
remote: https://github.com/keeshux/fastlane.git
|
||||||
|
revision: d08c54ec635ea28fe797d76a56af8a83548ecc96
|
||||||
|
branch: bugfix/build-multiplatform-for-ipa-pkg
|
||||||
specs:
|
specs:
|
||||||
CFPropertyList (3.0.7)
|
fastlane (2.221.1)
|
||||||
base64
|
|
||||||
nkf
|
|
||||||
rexml
|
|
||||||
addressable (2.8.7)
|
|
||||||
public_suffix (>= 2.0.2, < 7.0)
|
|
||||||
artifactory (3.0.17)
|
|
||||||
atomos (0.1.3)
|
|
||||||
aws-eventstream (1.3.0)
|
|
||||||
aws-partitions (1.977.0)
|
|
||||||
aws-sdk-core (3.207.0)
|
|
||||||
aws-eventstream (~> 1, >= 1.3.0)
|
|
||||||
aws-partitions (~> 1, >= 1.651.0)
|
|
||||||
aws-sigv4 (~> 1.9)
|
|
||||||
jmespath (~> 1, >= 1.6.1)
|
|
||||||
aws-sdk-kms (1.92.0)
|
|
||||||
aws-sdk-core (~> 3, >= 3.207.0)
|
|
||||||
aws-sigv4 (~> 1.5)
|
|
||||||
aws-sdk-s3 (1.164.0)
|
|
||||||
aws-sdk-core (~> 3, >= 3.207.0)
|
|
||||||
aws-sdk-kms (~> 1)
|
|
||||||
aws-sigv4 (~> 1.5)
|
|
||||||
aws-sigv4 (1.10.0)
|
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
|
||||||
babosa (1.0.4)
|
|
||||||
base64 (0.2.0)
|
|
||||||
claide (1.1.0)
|
|
||||||
colored (1.2)
|
|
||||||
colored2 (3.1.2)
|
|
||||||
commander (4.6.0)
|
|
||||||
highline (~> 2.0.0)
|
|
||||||
declarative (0.0.20)
|
|
||||||
digest-crc (0.6.5)
|
|
||||||
rake (>= 12.0.0, < 14.0.0)
|
|
||||||
domain_name (0.6.20240107)
|
|
||||||
dotenv (2.8.1)
|
|
||||||
emoji_regex (3.2.3)
|
|
||||||
excon (0.111.0)
|
|
||||||
faraday (1.10.4)
|
|
||||||
faraday-em_http (~> 1.0)
|
|
||||||
faraday-em_synchrony (~> 1.0)
|
|
||||||
faraday-excon (~> 1.1)
|
|
||||||
faraday-httpclient (~> 1.0)
|
|
||||||
faraday-multipart (~> 1.0)
|
|
||||||
faraday-net_http (~> 1.0)
|
|
||||||
faraday-net_http_persistent (~> 1.0)
|
|
||||||
faraday-patron (~> 1.0)
|
|
||||||
faraday-rack (~> 1.0)
|
|
||||||
faraday-retry (~> 1.0)
|
|
||||||
ruby2_keywords (>= 0.0.4)
|
|
||||||
faraday-cookie_jar (0.0.7)
|
|
||||||
faraday (>= 0.8.0)
|
|
||||||
http-cookie (~> 1.0.0)
|
|
||||||
faraday-em_http (1.0.0)
|
|
||||||
faraday-em_synchrony (1.0.0)
|
|
||||||
faraday-excon (1.1.0)
|
|
||||||
faraday-httpclient (1.0.1)
|
|
||||||
faraday-multipart (1.0.4)
|
|
||||||
multipart-post (~> 2)
|
|
||||||
faraday-net_http (1.0.2)
|
|
||||||
faraday-net_http_persistent (1.2.0)
|
|
||||||
faraday-patron (1.0.0)
|
|
||||||
faraday-rack (1.0.0)
|
|
||||||
faraday-retry (1.0.3)
|
|
||||||
faraday_middleware (1.2.0)
|
|
||||||
faraday (~> 1.0)
|
|
||||||
fastimage (2.3.1)
|
|
||||||
fastlane (2.222.0)
|
|
||||||
CFPropertyList (>= 2.3, < 4.0.0)
|
CFPropertyList (>= 2.3, < 4.0.0)
|
||||||
addressable (>= 2.8, < 3.0.0)
|
addressable (>= 2.8, < 3.0.0)
|
||||||
artifactory (~> 3.0)
|
artifactory (~> 3.0)
|
||||||
|
@ -109,6 +44,83 @@ GEM
|
||||||
xcodeproj (>= 1.13.0, < 2.0.0)
|
xcodeproj (>= 1.13.0, < 2.0.0)
|
||||||
xcpretty (~> 0.3.0)
|
xcpretty (~> 0.3.0)
|
||||||
xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
|
xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
|
||||||
|
|
||||||
|
GEM
|
||||||
|
remote: https://rubygems.org/
|
||||||
|
specs:
|
||||||
|
CFPropertyList (3.0.7)
|
||||||
|
base64
|
||||||
|
nkf
|
||||||
|
rexml
|
||||||
|
addressable (2.8.7)
|
||||||
|
public_suffix (>= 2.0.2, < 7.0)
|
||||||
|
artifactory (3.0.17)
|
||||||
|
atomos (0.1.3)
|
||||||
|
aws-eventstream (1.3.0)
|
||||||
|
aws-partitions (1.975.0)
|
||||||
|
aws-sdk-core (3.205.0)
|
||||||
|
aws-eventstream (~> 1, >= 1.3.0)
|
||||||
|
aws-partitions (~> 1, >= 1.651.0)
|
||||||
|
aws-sigv4 (~> 1.9)
|
||||||
|
jmespath (~> 1, >= 1.6.1)
|
||||||
|
aws-sdk-kms (1.91.0)
|
||||||
|
aws-sdk-core (~> 3, >= 3.205.0)
|
||||||
|
aws-sigv4 (~> 1.5)
|
||||||
|
aws-sdk-s3 (1.162.0)
|
||||||
|
aws-sdk-core (~> 3, >= 3.205.0)
|
||||||
|
aws-sdk-kms (~> 1)
|
||||||
|
aws-sigv4 (~> 1.5)
|
||||||
|
aws-sigv4 (1.9.1)
|
||||||
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
|
babosa (1.0.4)
|
||||||
|
base64 (0.2.0)
|
||||||
|
bigdecimal (3.1.8)
|
||||||
|
claide (1.1.0)
|
||||||
|
colored (1.2)
|
||||||
|
colored2 (3.1.2)
|
||||||
|
commander (4.6.0)
|
||||||
|
highline (~> 2.0.0)
|
||||||
|
csv (3.3.0)
|
||||||
|
declarative (0.0.20)
|
||||||
|
digest-crc (0.6.5)
|
||||||
|
rake (>= 12.0.0, < 14.0.0)
|
||||||
|
domain_name (0.6.20240107)
|
||||||
|
dotenv (2.8.1)
|
||||||
|
emoji_regex (3.2.3)
|
||||||
|
excon (0.111.0)
|
||||||
|
faraday (1.10.3)
|
||||||
|
faraday-em_http (~> 1.0)
|
||||||
|
faraday-em_synchrony (~> 1.0)
|
||||||
|
faraday-excon (~> 1.1)
|
||||||
|
faraday-httpclient (~> 1.0)
|
||||||
|
faraday-multipart (~> 1.0)
|
||||||
|
faraday-net_http (~> 1.0)
|
||||||
|
faraday-net_http_persistent (~> 1.0)
|
||||||
|
faraday-patron (~> 1.0)
|
||||||
|
faraday-rack (~> 1.0)
|
||||||
|
faraday-retry (~> 1.0)
|
||||||
|
ruby2_keywords (>= 0.0.4)
|
||||||
|
faraday-cookie_jar (0.0.7)
|
||||||
|
faraday (>= 0.8.0)
|
||||||
|
http-cookie (~> 1.0.0)
|
||||||
|
faraday-em_http (1.0.0)
|
||||||
|
faraday-em_synchrony (1.0.0)
|
||||||
|
faraday-excon (1.1.0)
|
||||||
|
faraday-httpclient (1.0.1)
|
||||||
|
faraday-multipart (1.0.4)
|
||||||
|
multipart-post (~> 2)
|
||||||
|
faraday-net_http (1.0.2)
|
||||||
|
faraday-net_http_persistent (1.2.0)
|
||||||
|
faraday-patron (1.0.0)
|
||||||
|
faraday-rack (1.0.0)
|
||||||
|
faraday-retry (1.0.3)
|
||||||
|
faraday_middleware (1.2.0)
|
||||||
|
faraday (~> 1.0)
|
||||||
|
fastimage (2.3.1)
|
||||||
|
fastlane-plugin-translate_gpt (0.1.8.2)
|
||||||
|
loco_strings (~> 0.1.4.1)
|
||||||
|
ruby-openai (~> 3.7)
|
||||||
|
fastlane-plugin-versioning (0.6.0)
|
||||||
gh_inspector (1.1.3)
|
gh_inspector (1.1.3)
|
||||||
google-apis-androidpublisher_v3 (0.54.0)
|
google-apis-androidpublisher_v3 (0.54.0)
|
||||||
google-apis-core (>= 0.11.0, < 2.a)
|
google-apis-core (>= 0.11.0, < 2.a)
|
||||||
|
@ -149,22 +161,37 @@ GEM
|
||||||
highline (2.0.3)
|
highline (2.0.3)
|
||||||
http-cookie (1.0.7)
|
http-cookie (1.0.7)
|
||||||
domain_name (~> 0.5)
|
domain_name (~> 0.5)
|
||||||
|
httparty (0.22.0)
|
||||||
|
csv
|
||||||
|
mini_mime (>= 1.0.0)
|
||||||
|
multi_xml (>= 0.5.2)
|
||||||
httpclient (2.8.3)
|
httpclient (2.8.3)
|
||||||
jmespath (1.6.2)
|
jmespath (1.6.2)
|
||||||
json (2.7.2)
|
json (2.7.2)
|
||||||
jwt (2.9.0)
|
jwt (2.9.0)
|
||||||
base64
|
base64
|
||||||
|
loco_strings (0.1.4.1)
|
||||||
|
nokogiri (~> 1.13, >= 1.13.8)
|
||||||
mini_magick (4.13.2)
|
mini_magick (4.13.2)
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
|
mini_portile2 (2.8.7)
|
||||||
multi_json (1.15.0)
|
multi_json (1.15.0)
|
||||||
|
multi_xml (0.7.1)
|
||||||
|
bigdecimal (~> 3.1)
|
||||||
multipart-post (2.4.1)
|
multipart-post (2.4.1)
|
||||||
nanaimo (0.3.0)
|
nanaimo (0.3.0)
|
||||||
naturally (2.2.1)
|
naturally (2.2.1)
|
||||||
nkf (0.2.0)
|
nkf (0.2.0)
|
||||||
|
nokogiri (1.16.7)
|
||||||
|
mini_portile2 (~> 2.8.2)
|
||||||
|
racc (~> 1.4)
|
||||||
|
nokogiri (1.16.7-arm64-darwin)
|
||||||
|
racc (~> 1.4)
|
||||||
optparse (0.5.0)
|
optparse (0.5.0)
|
||||||
os (1.1.4)
|
os (1.1.4)
|
||||||
plist (3.7.1)
|
plist (3.7.1)
|
||||||
public_suffix (6.0.1)
|
public_suffix (6.0.1)
|
||||||
|
racc (1.8.1)
|
||||||
rake (13.2.1)
|
rake (13.2.1)
|
||||||
representable (3.2.0)
|
representable (3.2.0)
|
||||||
declarative (< 0.1.0)
|
declarative (< 0.1.0)
|
||||||
|
@ -173,6 +200,8 @@ GEM
|
||||||
retriable (3.1.2)
|
retriable (3.1.2)
|
||||||
rexml (3.3.7)
|
rexml (3.3.7)
|
||||||
rouge (2.0.7)
|
rouge (2.0.7)
|
||||||
|
ruby-openai (3.7.0)
|
||||||
|
httparty (>= 0.18.1)
|
||||||
ruby2_keywords (0.0.5)
|
ruby2_keywords (0.0.5)
|
||||||
rubyzip (2.3.2)
|
rubyzip (2.3.2)
|
||||||
security (0.1.5)
|
security (0.1.5)
|
||||||
|
@ -209,12 +238,13 @@ GEM
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
arm64-darwin-23
|
arm64-darwin-23
|
||||||
x86_64-darwin-21
|
ruby
|
||||||
x86_64-linux
|
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
dotenv
|
dotenv
|
||||||
fastlane
|
fastlane (>= 2.2.0)!
|
||||||
|
fastlane-plugin-translate_gpt
|
||||||
|
fastlane-plugin-versioning
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.5.17
|
2.5.14
|
||||||
|
|
|
@ -1,12 +1,21 @@
|
||||||
{
|
{
|
||||||
"pins" : [
|
"pins" : [
|
||||||
{
|
{
|
||||||
"identity" : "generic-json-swift",
|
"identity" : "dtfoundation",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/zoul/generic-json-swift",
|
"location" : "https://github.com/Cocoanetics/DTFoundation.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "0a06575f4038b504e78ac330913d920f1630f510",
|
"revision" : "76062513434421cb6c8a1ae1d4f8368a7ebc2da3",
|
||||||
"version" : "2.0.2"
|
"version" : "1.7.18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "kvitto",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/Cocoanetics/Kvitto",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "88888674d772ddcf19671159ed0022cb0bc37be2",
|
||||||
|
"version" : "1.0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -14,25 +23,44 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/passepartoutvpn/openssl-apple",
|
"location" : "https://github.com/passepartoutvpn/openssl-apple",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "026702febcaebcbf9ea68f2fa66b017eba998cdf",
|
"revision" : "0edc07c7a0e4ec2ca0f448dd68314241ccc925b3",
|
||||||
"version" : "3.2.105"
|
"version" : "3.2.107"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"identity" : "swiftybeaver",
|
"identity" : "passepartoutkit",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/SwiftyBeaver/SwiftyBeaver",
|
"location" : "git@github.com:passepartoutvpn/passepartoutkit",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "12b5acf96d98f91d50de447369bd18df74600f1a",
|
"revision" : "2c32459d6a669e8feed0e6ea2d1250ef72364aa3",
|
||||||
"version" : "1.9.6"
|
"version" : "0.7.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"identity" : "tunnelkit",
|
"identity" : "passepartoutkit-openvpn-openssl",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/passepartoutvpn/tunnelkit",
|
"location" : "git@github.com:passepartoutvpn/passepartoutkit-openvpn-openssl",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "6ab1759e048867fbca9bd5d33f2dc7eb1fa79ca6"
|
"revision" : "a3092a6ee0a63f666aa47ef3f0f50c324a64598d",
|
||||||
|
"version" : "0.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "passepartoutkit-wireguard-go",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "git@github.com:passepartoutvpn/passepartoutkit-wireguard-go",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "2cbd6023300d2dcc3f6f68de4812cf390421ec35",
|
||||||
|
"version" : "0.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "wg-go-apple",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/passepartoutvpn/wg-go-apple",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "860e82efaf261da37483a5f51555be83e5a79ad3",
|
||||||
|
"version" : "0.0.20240714"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -40,7 +68,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/passepartoutvpn/wireguard-apple",
|
"location" : "https://github.com/passepartoutvpn/wireguard-apple",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "b79f0f150356d8200a64922ecf041dd020140aa0"
|
"revision" : "a896f784bc5ed94f29d97e376be5cfa08d4a5d44",
|
||||||
|
"version" : "1.1.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1510"
|
LastUpgradeVersion = "1540"
|
||||||
version = "1.7">
|
version = "1.7">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
@ -14,54 +14,12 @@
|
||||||
buildForAnalyzing = "YES">
|
buildForAnalyzing = "YES">
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "0E57F63720C83FC5008323CF"
|
BlueprintIdentifier = "0E06D18E2B87629100176E1D"
|
||||||
BuildableName = "Passepartout.app"
|
BuildableName = "Passepartout.app"
|
||||||
BlueprintName = "Passepartout"
|
BlueprintName = "Passepartout"
|
||||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildActionEntry>
|
</BuildActionEntry>
|
||||||
<BuildActionEntry
|
|
||||||
buildForTesting = "YES"
|
|
||||||
buildForRunning = "YES"
|
|
||||||
buildForProfiling = "YES"
|
|
||||||
buildForArchiving = "YES"
|
|
||||||
buildForAnalyzing = "YES">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "0EDE8DBE20C86910004C739C"
|
|
||||||
BuildableName = "PassepartoutOpenVPNTunnel.appex"
|
|
||||||
BlueprintName = "OpenVPNTunnel"
|
|
||||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildActionEntry>
|
|
||||||
<BuildActionEntry
|
|
||||||
buildForTesting = "YES"
|
|
||||||
buildForRunning = "YES"
|
|
||||||
buildForProfiling = "YES"
|
|
||||||
buildForArchiving = "YES"
|
|
||||||
buildForAnalyzing = "YES">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "0ECF71F327B6D9CD00CDB528"
|
|
||||||
BuildableName = "WireGuardGo"
|
|
||||||
BlueprintName = "WireGuardGo"
|
|
||||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildActionEntry>
|
|
||||||
<BuildActionEntry
|
|
||||||
buildForTesting = "YES"
|
|
||||||
buildForRunning = "YES"
|
|
||||||
buildForProfiling = "YES"
|
|
||||||
buildForArchiving = "YES"
|
|
||||||
buildForAnalyzing = "YES">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "0ED2B33E27D3C77800FD8EA9"
|
|
||||||
BuildableName = "PassepartoutWireGuardTunnel.appex"
|
|
||||||
BlueprintName = "WireGuardTunnel"
|
|
||||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildActionEntry>
|
|
||||||
</BuildActionEntries>
|
</BuildActionEntries>
|
||||||
</BuildAction>
|
</BuildAction>
|
||||||
<TestAction
|
<TestAction
|
||||||
|
@ -70,21 +28,11 @@
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
shouldAutocreateTestPlan = "YES">
|
shouldAutocreateTestPlan = "YES">
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "0E57F63720C83FC5008323CF"
|
|
||||||
BuildableName = "Passepartout.app"
|
|
||||||
BlueprintName = "Passepartout"
|
|
||||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
language = "it"
|
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
@ -95,7 +43,7 @@
|
||||||
runnableDebuggingMode = "0">
|
runnableDebuggingMode = "0">
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "0E57F63720C83FC5008323CF"
|
BlueprintIdentifier = "0E06D18E2B87629100176E1D"
|
||||||
BuildableName = "Passepartout.app"
|
BuildableName = "Passepartout.app"
|
||||||
BlueprintName = "Passepartout"
|
BlueprintName = "Passepartout"
|
||||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||||
|
@ -103,35 +51,33 @@
|
||||||
</BuildableProductRunnable>
|
</BuildableProductRunnable>
|
||||||
<CommandLineArguments>
|
<CommandLineArguments>
|
||||||
<CommandLineArgument
|
<CommandLineArgument
|
||||||
argument = "-com.apple.CoreData.SQLDebug 0"
|
argument = "-com.apple.CoreData.SQLDebug 1"
|
||||||
isEnabled = "YES">
|
isEnabled = "NO">
|
||||||
</CommandLineArgument>
|
</CommandLineArgument>
|
||||||
<CommandLineArgument
|
<CommandLineArgument
|
||||||
argument = "-com.apple.CoreData.Logging.stderr 0 "
|
argument = " -com.apple.CoreData.ConcurrencyDebug 1"
|
||||||
isEnabled = "YES">
|
|
||||||
</CommandLineArgument>
|
|
||||||
<CommandLineArgument
|
|
||||||
argument = "-com.apple.CoreData.CloudKitDebug 0"
|
|
||||||
isEnabled = "YES">
|
|
||||||
</CommandLineArgument>
|
|
||||||
<CommandLineArgument
|
|
||||||
argument = "-com.apple.CoreData.ConcurrencyDebug 0"
|
|
||||||
isEnabled = "YES">
|
|
||||||
</CommandLineArgument>
|
|
||||||
<CommandLineArgument
|
|
||||||
argument = "-com.apple.CoreData.MigrationDebug 0"
|
|
||||||
isEnabled = "YES">
|
isEnabled = "YES">
|
||||||
</CommandLineArgument>
|
</CommandLineArgument>
|
||||||
</CommandLineArguments>
|
</CommandLineArguments>
|
||||||
<EnvironmentVariables>
|
<EnvironmentVariables>
|
||||||
<EnvironmentVariable
|
<EnvironmentVariable
|
||||||
key = "APP_TYPE"
|
key = "SQLITE_ENABLE_THREAD_ASSERTIONS"
|
||||||
value = "0"
|
value = "1"
|
||||||
isEnabled = "YES">
|
isEnabled = "YES">
|
||||||
</EnvironmentVariable>
|
</EnvironmentVariable>
|
||||||
<EnvironmentVariable
|
<EnvironmentVariable
|
||||||
key = "LOG_LEVEL"
|
key = "SQLITE_ENABLE_FILE_ASSERTIONS"
|
||||||
value = "0"
|
value = "1"
|
||||||
|
isEnabled = "YES">
|
||||||
|
</EnvironmentVariable>
|
||||||
|
<EnvironmentVariable
|
||||||
|
key = "SQLITE_AUTO_TRACE"
|
||||||
|
value = "1"
|
||||||
|
isEnabled = "NO">
|
||||||
|
</EnvironmentVariable>
|
||||||
|
<EnvironmentVariable
|
||||||
|
key = "CUSTOM_USER_LEVEL"
|
||||||
|
value = "2"
|
||||||
isEnabled = "YES">
|
isEnabled = "YES">
|
||||||
</EnvironmentVariable>
|
</EnvironmentVariable>
|
||||||
</EnvironmentVariables>
|
</EnvironmentVariables>
|
||||||
|
@ -146,7 +92,7 @@
|
||||||
runnableDebuggingMode = "0">
|
runnableDebuggingMode = "0">
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "0E57F63720C83FC5008323CF"
|
BlueprintIdentifier = "0E06D18E2B87629100176E1D"
|
||||||
BuildableName = "Passepartout.app"
|
BuildableName = "Passepartout.app"
|
||||||
BlueprintName = "Passepartout"
|
BlueprintName = "Passepartout"
|
||||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1510"
|
LastUpgradeVersion = "1540"
|
||||||
version = "1.3">
|
wasCreatedForAppExtension = "YES"
|
||||||
|
version = "2.0">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
buildImplicitDependencies = "YES">
|
buildImplicitDependencies = "YES">
|
||||||
|
@ -14,9 +15,23 @@
|
||||||
buildForAnalyzing = "YES">
|
buildForAnalyzing = "YES">
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "0E41BD96286711C3006346B4"
|
BlueprintIdentifier = "0EC332C72B8A1808000B9C2F"
|
||||||
BuildableName = "PassepartoutLauncher.app"
|
BuildableName = "PassepartoutTunnel.appex"
|
||||||
BlueprintName = "PassepartoutLauncher"
|
BlueprintName = "PassepartoutTunnel"
|
||||||
|
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "0E06D18E2B87629100176E1D"
|
||||||
|
BuildableName = "Passepartout.app"
|
||||||
|
BlueprintName = "Passepartout"
|
||||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildActionEntry>
|
</BuildActionEntry>
|
||||||
|
@ -26,27 +41,28 @@
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
<Testables>
|
shouldAutocreateTestPlan = "YES">
|
||||||
</Testables>
|
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = ""
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
debugDocumentVersioning = "YES"
|
debugDocumentVersioning = "YES"
|
||||||
debugServiceExtension = "internal"
|
debugServiceExtension = "internal"
|
||||||
allowLocationSimulation = "YES">
|
allowLocationSimulation = "YES"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
<BuildableProductRunnable
|
<BuildableProductRunnable
|
||||||
runnableDebuggingMode = "0">
|
runnableDebuggingMode = "0">
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "0E41BD96286711C3006346B4"
|
BlueprintIdentifier = "0E06D18E2B87629100176E1D"
|
||||||
BuildableName = "PassepartoutLauncher.app"
|
BuildableName = "Passepartout.app"
|
||||||
BlueprintName = "PassepartoutLauncher"
|
BlueprintName = "Passepartout"
|
||||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildableProductRunnable>
|
</BuildableProductRunnable>
|
||||||
|
@ -56,14 +72,16 @@
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
savedToolIdentifier = ""
|
savedToolIdentifier = ""
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
debugDocumentVersioning = "YES">
|
debugDocumentVersioning = "YES"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
<BuildableProductRunnable
|
<BuildableProductRunnable
|
||||||
runnableDebuggingMode = "0">
|
runnableDebuggingMode = "0">
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "0E41BD96286711C3006346B4"
|
BlueprintIdentifier = "0E06D18E2B87629100176E1D"
|
||||||
BuildableName = "PassepartoutLauncher.app"
|
BuildableName = "Passepartout.app"
|
||||||
BlueprintName = "PassepartoutLauncher"
|
BlueprintName = "Passepartout"
|
||||||
ReferencedContainer = "container:Passepartout.xcodeproj">
|
ReferencedContainer = "container:Passepartout.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildableProductRunnable>
|
</BuildableProductRunnable>
|
|
@ -2,40 +2,29 @@
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>aps-environment</key>
|
|
||||||
<string>development</string>
|
|
||||||
<key>com.apple.developer.icloud-container-identifiers</key>
|
|
||||||
<array>
|
|
||||||
<string>iCloud.com.algoritmico.Passepartout</string>
|
|
||||||
<string>iCloud.com.algoritmico.Passepartout.Shared</string>
|
|
||||||
</array>
|
|
||||||
<key>com.apple.developer.icloud-services</key>
|
|
||||||
<array>
|
|
||||||
<string>CloudKit</string>
|
|
||||||
</array>
|
|
||||||
<key>com.apple.developer.networking.networkextension</key>
|
<key>com.apple.developer.networking.networkextension</key>
|
||||||
<array>
|
<array>
|
||||||
<string>packet-tunnel-provider</string>
|
<string>packet-tunnel-provider</string>
|
||||||
</array>
|
</array>
|
||||||
<key>com.apple.developer.networking.wifi-info</key>
|
<key>com.apple.developer.networking.wifi-info</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.developer.siri</key>
|
|
||||||
<true/>
|
|
||||||
<key>com.apple.security.app-sandbox</key>
|
|
||||||
<true/>
|
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>group.$(CFG_GROUP_ID)</string>
|
<string>$(CFG_GROUP_ID)</string>
|
||||||
</array>
|
</array>
|
||||||
<key>com.apple.security.files.user-selected.read-write</key>
|
<key>com.apple.security.app-sandbox</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.network.client</key>
|
<key>com.apple.security.files.user-selected.read-only</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.personal-information.location</key>
|
<key>com.apple.security.personal-information.location</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>com.apple.security.network.client</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.network.server</key>
|
||||||
|
<true/>
|
||||||
<key>keychain-access-groups</key>
|
<key>keychain-access-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>$(AppIdentifierPrefix)group.com.algoritmico.Passepartout</string>
|
<string>$(AppIdentifierPrefix)$(CFG_GROUP_ID)</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -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
|
// AppDelegate.swift
|
||||||
// Passepartout
|
// Passepartout
|
||||||
//
|
//
|
||||||
// Created by Davide De Rosa on 6/25/22.
|
// Created by Davide De Rosa on 9/18/24.
|
||||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||||
//
|
//
|
||||||
// https://github.com/passepartoutvpn
|
// https://github.com/passepartoutvpn
|
||||||
|
@ -23,37 +23,31 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
#if os(iOS)
|
||||||
import PassepartoutLibrary
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
final class AppDelegate: UIResponder, UIApplicationDelegate, ObservableObject {
|
final class AppDelegate: NSObject, UIApplicationDelegate {
|
||||||
private let mac = MacBundle.shared
|
}
|
||||||
|
|
||||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
|
#else
|
||||||
#if targetEnvironment(macCatalyst)
|
|
||||||
mac.configure()
|
import AppKit
|
||||||
mac.menu.install()
|
import CommonLibrary
|
||||||
if mac.utils.isStartedByLauncher {
|
import PassepartoutKit
|
||||||
mac.utils.sendAppToBackground()
|
|
||||||
}
|
final class AppDelegate: NSObject, NSApplicationDelegate {
|
||||||
#endif
|
func applicationDidFinishLaunching(_ notification: Notification) {
|
||||||
return true
|
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 {
|
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
|
||||||
let sceneConfiguration = UISceneConfiguration(name: "SceneDelegate", sessionRole: connectingSceneSession.role)
|
true
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,15 +1,6 @@
|
||||||
{
|
{
|
||||||
"colors" : [
|
"colors" : [
|
||||||
{
|
{
|
||||||
"color" : {
|
|
||||||
"color-space" : "srgb",
|
|
||||||
"components" : {
|
|
||||||
"alpha" : "1.000",
|
|
||||||
"blue" : "0x68",
|
|
||||||
"green" : "0x9C",
|
|
||||||
"red" : "0xD6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"idiom" : "universal"
|
"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"
|
"size" : "256x256"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "AppIcon-mac.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "1x",
|
"scale" : "1x",
|
||||||
"size" : "512x512"
|
"size" : "512x512"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "AppIcon-mac.png",
|
"filename" : "AppIcon-mac@2x.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "2x",
|
"scale" : "2x",
|
||||||
"size" : "512x512"
|
"size" : "512x512"
|
||||||
|
|
|
@ -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 |