Commit Graph

84 Commits

Author SHA1 Message Date
Davide
a91f71345c
Log profiles decoding time 2025-01-05 16:32:18 +01:00
Davide
2f67bcbbf2
Sync local profiles consistently (#1051)
Rather than redoing ProfileManager.observeLocal() altogether:

- Keep the existing profiles subscription (localSubscription)
- Reload ALL local profiles on NE notifications

The reload is "heavy" because each profile save causes a reload of ALL
profiles, but it's the most reliable approach and in the end, it only
takes 1-2msec. It can be improved later.

Partially reverts #1049, because the app did not sync when a VPN
configuration was deleted from the OS settings.
2025-01-04 23:42:10 +01:00
Davide
236df80950
Fix on-demand SSID not being added on macOS (#1050)
Skip CoreLocation completely, not entitled.
2025-01-04 11:01:25 +01:00
Davide
c232fd18a8
Set up local profiles observer once (#1049)
Beyond being useless, reloading the repository across app
active/inactive may spoil notifications and leave the profiles list out
of sync.
2025-01-04 10:46:10 +01:00
Davide
24ddb270aa
Skip backup repository on simulator (#1048)
ProfileManager is behaving crazy because on simulator local and backup
repository point to the same container.
2025-01-04 10:45:51 +01:00
Davide
edb7c29b26
Bump version 2024-12-31 00:49:23 +01:00
Davide
fabb4c664c
Verify tunnel profile periodically (#1047)
Eligibility may have changed during connection. Repeat verification
every 10 minutes.
2024-12-31 00:48:54 +01:00
Davide
8d7351d5e2
Bump version 2024-12-23 22:48:35 +01:00
Davide
3706268bf9
Drop broken macOS code to get SSID (#1042)
Related to #497
2024-12-23 22:47:33 +01:00
Davide
3e04f03b01
Skip local receipt on Apple TV (#1041)
App/Tunnel behavior is inconsistent.
2024-12-22 12:24:20 +01:00
Davide
6d62953eff
Improve display of keep-alive options in OpenVPN configuration (#1038)
Timeout was not displayed. Move options to a separate section.
2024-12-22 10:55:56 +01:00
Davide
2ae615406a
Update API with fixed keep-alive 2024-12-22 08:09:13 +01:00
Davide
f112ea8061
Save last used profile (#1036)
Especially useful on macOS and tvOS where Network Extension does not
retain this information when the profile is disabled. On these
platforms, there's no native way to tell the last used profile, so save
it to UserDefaults and fall back to it when tunnel.currentProfile is
nil.
2024-12-21 22:39:55 +01:00
Davide
e13a84cba3
Fix uncredited features on tvOS (#1033)
This was not apparent on TestFlight, but features from single iOS and
macOS "Full version" purchases were not being credited on the Apple TV
because of the incomplete `#if` conditionals.
2024-12-20 23:21:22 +01:00
Davide
0d3af046b4
Fall back to production if beta receipt is missing (#1031)
When level is .beta, it was relying on beta receipt exclusively without
falling back to production receipt.

This was preventing the sandbox receipt ("production" in TestFlight)
from being read unless the AppUserLevel was explicitly set to .freemium
(0).
2024-12-20 21:09:02 +01:00
Davide
59e4e2e4ab
Hide profiles until remote repository is ready
Regression from #1029
2024-12-20 10:39:39 +01:00
Davide
42bf392fff
Do not connect TV profile on server selection (#1030)
You may still connect manually, but iOS/macOS apps mainly serve as
remote to switch servers on the TV.
2024-12-20 10:30:57 +01:00
Davide
f8e623e1fe
Fix regressions with CloudKit synchronization (#1029)
The remote container is shared by ProfileManager and
PreferencesManager, but it must be the same for CloudKit sync
to work properly.

Externalize the logic of onEligibleFeatures() so that the
AppContext singleton can update the managers (and their
repositories) with the new remote store.

Now that the remote profile repository is reloaded every time that
eligible features change, the .removeDuplicates() may also be
restored. Just add a .dropFirst() to skip the initially empty
value of eligible features. Even when features are eventually empty,
a value is always emitted after IAPManager.reloadReceipt()

Lastly, enable Core Data lightweight migration.

Regressions from #1017
2024-12-20 10:05:07 +01:00
Davide
c527171957
Simplify products (#1024)
Only offer compensations to former purchasers:

- .appleTV to .full purchasers
- .full to .appleTV purchasers

Always suggest .fullTV to new purchasers.

Finally rename:

- .full to .iOS_macOS
- .fullTV to .allFeatures (lifetime)
2024-12-18 10:15:58 +01:00
Davide
2eca757dc6
Verify sharing/TV features only on profile save (#1023)
Do not verify sharing/TV on connect iOS/macOS.
2024-12-18 09:16:58 +01:00
Davide
75de2029ff
Always refresh app features onForeground() (#1022)
Even if they haven't changed since the app was last sent to the
background.

Regression from #1019 where the initial .reloadReceipt() call was
wrapped in a Task to make it asynchronous.
2024-12-17 20:57:10 +01:00
Davide
a81b615261
Bump version 2024-12-17 18:50:27 +01:00
Davide
6255a273fe
Add recurring products to paywall (#1019)
Suggest whenever .fullTV is suggested. For this reason, subscriptions
are not suggested to existing full version purchasers, because they only
miss the one-time .appleTV purchase. Group purchases by feature products
and full version products, e.g.:

- Features
  - Apple TV
- Full version
  - Yearly
  - Monthly
  - Full
  - Full + TV

Additionally, fix reloadReceipt() slowing down onLaunch() sometimes. The
warning sign would appear on restricted profiles until the receipt is
loaded.
2024-12-17 18:23:27 +01:00
Davide
ef59dcc08e
Reword strings in "Purchased" view
Title: "Purchases"
Products header: "Products"
2024-12-16 21:57:05 +01:00
Davide
789f6ad515
Unify paywall and eligibility (#1018)
- Present paywall only on save/connect because PurchaseRequiredButton
instances were presenting paywalls with partial requirements
- Retain PurchaseRequiredButton just to flag paid features visually, but
do nothing on tap
- Suggest paywall products via IAPManager and required features, rather
than from views
- Handle .sharing/.appleTV requirements in ProfileCoordinator, rather
than in StorageSection
- Discontinue platform purchases, but treat as full if iOS + macOS
2024-12-16 21:45:36 +01:00
Davide
ffb8829f4f
Reorganize Core Data containers (#1017)
Before anything, remove any code related to App Group containers from
tvOS target because they are not available. Include the beta receipt
override, it's broken for that reason.

In short:

- Store all Core Data containers locally. Do not use the App Group for
Core Data for consistency across platforms.
- Store logs in the App Group on iOS/macOS, but locally on tvOS (see
`urlForCaches`).

Then, rather than one container per model, merge models into:

- Local: Providers
- Remote: Profiles + Preferences (now in the same CloudKit container)

Reuse the remote model for backups too.

This change is safe because:

- Local profiles are stored via Network Extension in the keychain, not
Core Data
- Remote profiles are re-imported via CloudKit sync
- Providers are re-downloaded on first use
- Preferences are lost, but they are "cheap" data
- Profile backups are lost, but they were hidden anyway
2024-12-15 20:20:33 +01:00
Davide
8ad71b2980
Bump version 2024-12-15 13:52:05 +01:00
Davide
a04c1072c8
Allow Ethernet on-demand on all platforms (#1012)
Fixes #1010
2024-12-14 21:59:25 +01:00
Davide
b9353a6b02
Temporarily disable auto-deletion of migrated profiles (#1013)
Leave room for downgrade until 3.0.0 is stable.
2024-12-14 21:58:39 +01:00
Davide
1837d0576e
Update README (#1008)
- Simplify badges
- Drop app description, annoying to maintain (refer to the website)
- Drop screenshots (refer to the App Store)
- Update Credits
- Inform about private PassepartoutKit

Fixes #613
2024-12-14 09:44:10 +01:00
Davide
d0f25d6d6e
Add translations for the former 12 languages (#1005)
Closes #588
2024-12-12 23:32:27 +01:00
Davide
88c53bed2e
Regroup views/logic of VPNProviderServerView 2024-12-12 18:44:14 +01:00
Davide
2075f109f2
Fix unselectable presets (#1004)
Revert #996 and do something midway:

- When set, use preset filter as selection (disambiguate compatible
presets)
- Set initial preset filter with current selected server preset

Server selection still picks a random preset if:

- Preset filter is "Any"
- More than one preset is compatible
2024-12-12 18:38:16 +01:00
Davide
ed45e5d2e4
Fix a Core Data crash on Apple TV (#1003)
Could not create the Preferences Core Data container in the App Group
because sub-directories did not exist. Create them upfront when using
App Group URLs.

This was not an issue with other Core Data containers because they are
stored in the app directories, where "Library/Documents" already exists.
2024-12-12 12:48:58 +01:00
Davide
81aa3a2714
Skip onboarding migration if no migratable profiles (#1002)
Annoying!
2024-12-11 22:20:14 +01:00
Davide
ff88b3562d
Clean up dangling module preferences (#999)
Erase on module removal, reference is otherwise lost forever.
2024-12-10 20:33:35 +01:00
Davide
d8447ddb38
Fix a few things about screenshots
- Postpone "Connected" screenshot
- Disable "Only favorites" to avoid iOS failure
- Prefix screenshot filename with device name and "0"
2024-12-10 18:37:53 +01:00
Davide
f441a2eed0
Autogenerate screenshots for all platforms (#998)
Unframed for now.

- Split Main/TV targets
- Extend ProfileManager for screenshot scenarios
- Rename UITesting to UIAccessibility

Active profile looks very big on TV simulator, temporarily commented
`.padding(.top, 50)` in ActiveProfileView.

Closes #974
2024-12-10 18:06:23 +01:00
Davide
a626722224
Fix TV active toggle color when on-demand 2024-12-10 17:31:33 +01:00
Davide
ddd45c1855
Bump version 2024-12-10 15:30:45 +01:00
Davide
2b3c28832b
Migrate provider favorites to Core Data entities (#997)
Rather than a Codable array.
2024-12-10 15:19:07 +01:00
Davide
c7bba033fe
Fix incorrect selection of VPN preset (#996)
Drop "Any" to rather make the preset filter an explicit preset
selection.

Regardless of `filtersWithSelection`, _always_ enforce the preset filter
to:

- The preset of the currently selected entity
- The first among available presets (normally non-empty)

Fixes #995
2024-12-10 14:45:07 +01:00
Davide
6f9c78b257
Track module preferences history in Core Data (#994)
Restore CDModulePreferencesV3 to track the history of module prefrences.

This way, excluded endpoints may be saved globally to Core Data as a
starting point. Then in Profile.userInfo we only save the relevant
exclusions for the current configuration.

The .excludedEndpoints relationship is therefore moved out of
CDProviderPreferencesV3.

Further refactoring:

- ModuleViewParameters now includes a ModulePreferences observable that
module views can observe
- Tunnel doesn't need access to PreferencesManager anymore (exclusions
are in Profile.userInfo)
2024-12-10 14:13:10 +01:00
Davide
aeec943c58
Move ModulePreferences to Profile.userInfo (#993)
Store module preferences in the Profile.userInfo field for atomicity.
Access and modification are dramatically simplified, and synchronization
comes for free.

On the other side, fix provider preferences synchronization by using
viewContext for the CloudKit container.

Fixes #992
2024-12-10 11:18:52 +01:00
Davide
912f62b29e
Revert "Unobserve ProfileEditor"
This reverts commit f1a0ecadfa.
2024-12-09 20:35:42 +01:00
Davide
a642b27d2b
Deduplicate preferences by last update (#991)
Fixes #990
2024-12-09 09:13:16 +01:00
Davide
93a15cd766
Review incorrect behavior in preferences (#989)
- Save/rollback was done outside of MOC
- Use different contexts for module/provider preferences
  - Save providers → also saves modules
  - Discard modules → also discards providers
- Use background context because it's not automatically merged (can
rollback)
- Expose ModulePreferences in OpenVPNView as StateObject
- Rework Blacklist to a more reusable ObservableList
- Reapply #988
2024-12-09 08:44:13 +01:00
Davide
c72a69829b
Fix compile error on TV 2024-12-09 07:59:37 +01:00
Davide
fae0200995
Exclude OpenVPN endpoints (#987)
Exclude endpoints from OpenVPN modules and providers with the generic
Blacklist<T> observable. Eventually, rebuild the Profile in
PacketTunnelProvider (via DefaultTunnelProcessor) with the applied
exclusions from preferences.

Revisit approach to preferences:

- Module preferences
  - Tied to the module and therefore to the parent profile
- Load/save in ProfileEditor on request (rather than on
ProfileEditor.load)
- Provider preferences
  - Shared globally across profiles
  - Load/save in module view if needed

For more consistency with Core Data:

- Revert to observables for both module and provider preferences
- Treat excluded endpoints as relationships rather than a serialized
Array
- Add/remove single relationships over bulk delete + re-add
- Do not map the relationships, Blacklist only needs exists/add/remove:
  - isExcludedEndpoint
  - addExcludedEndpoint
  - removeExcludedEndpoint

Some clean-up:

- Move the importer logic to OpenVPNView.ImportModifier
- Move the preview data to OpenVPN.Configuration.Builder.forPreviews
- Drop objectWillChange.send() on .repository didSet to avoid potential
recursion during SwiftUI updates

Closes #971
2024-12-09 02:00:55 +01:00
Davide
5f20d791c2
Show module UUID in DEBUG 2024-12-09 01:01:01 +01:00