Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KM-5043: Implement force update #170

Merged
merged 3 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions PIA VPN.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,10 @@
E53627372BE802200064DEDF /* SignupUseCaseMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = E53627362BE802200064DEDF /* SignupUseCaseMock.swift */; };
E548E1FF2C1238BD001E9874 /* SnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = E548E1FE2C1238BD001E9874 /* SnapshotTesting */; };
E548E2002C1238CD001E9874 /* WelcomeViewSnapshotTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E548E1EC2C123782001E9874 /* WelcomeViewSnapshotTest.swift */; };
E55188932CB66BCA00E4C241 /* ForceUpdateViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E55188912CB66BCA00E4C241 /* ForceUpdateViewController.swift */; };
E55188942CB66BCA00E4C241 /* ForceUpdateViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = E55188922CB66BCA00E4C241 /* ForceUpdateViewController.xib */; };
E55188952CB66BCA00E4C241 /* ForceUpdateViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E55188912CB66BCA00E4C241 /* ForceUpdateViewController.swift */; };
E55188962CB66BCA00E4C241 /* ForceUpdateViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = E55188922CB66BCA00E4C241 /* ForceUpdateViewController.xib */; };
E55216342BEF63EA001A287F /* SignupIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E55216332BEF63EA001A287F /* SignupIntegrationTests.swift */; };
E55216362BF1393C001A287F /* SignupEmailIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E55216352BF1393C001A287F /* SignupEmailIntegrationTests.swift */; };
E55216382BF14A5B001A287F /* SignupDomainErrorMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E55216372BF14A5B001A287F /* SignupDomainErrorMapper.swift */; };
Expand Down Expand Up @@ -1685,6 +1689,8 @@
E548E1EC2C123782001E9874 /* WelcomeViewSnapshotTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeViewSnapshotTest.swift; sourceTree = "<group>"; };
E548E1F52C1238B5001E9874 /* PIA VPN-tvOS snapshot.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "PIA VPN-tvOS snapshot.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
E548E2012C124AA0001E9874 /* PIA VPN-tvOS snapshot.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "PIA VPN-tvOS snapshot.xctestplan"; sourceTree = "<group>"; };
E55188912CB66BCA00E4C241 /* ForceUpdateViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForceUpdateViewController.swift; sourceTree = "<group>"; };
E55188922CB66BCA00E4C241 /* ForceUpdateViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ForceUpdateViewController.xib; sourceTree = "<group>"; };
E55216332BEF63EA001A287F /* SignupIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignupIntegrationTests.swift; sourceTree = "<group>"; };
E55216352BF1393C001A287F /* SignupEmailIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignupEmailIntegrationTests.swift; sourceTree = "<group>"; };
E55216372BF14A5B001A287F /* SignupDomainErrorMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignupDomainErrorMapper.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2373,6 +2379,7 @@
296BBFEE1840066A00944151 /* UI */ = {
isa = PBXGroup;
children = (
E55188902CB66B7900E4C241 /* Force update */,
E5217F5C2AEAE01400123442 /* NotificationCategory.swift */,
E5217F532AEAD54600123442 /* WalkthroughPageView.swift */,
E5217F4A2AEAD29F00123442 /* PurchasePlanCell.swift */,
Expand Down Expand Up @@ -3567,6 +3574,15 @@
path = "PIA VPNTests snapshot";
sourceTree = "<group>";
};
E55188902CB66B7900E4C241 /* Force update */ = {
isa = PBXGroup;
children = (
E55188912CB66BCA00E4C241 /* ForceUpdateViewController.swift */,
E55188922CB66BCA00E4C241 /* ForceUpdateViewController.xib */,
);
name = "Force update";
sourceTree = "<group>";
};
E55216322BEF63AD001A287F /* Integration */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -5007,6 +5023,7 @@
0ED66BD020A9918000333B35 /* staging.endpoint in Resources */,
DD76292021ECCD510092DF50 /* UsageTileCollectionViewCell.xib in Resources */,
E501CBB72AE97EC800515006 /* Welcome.storyboard in Resources */,
E55188962CB66BCA00E4C241 /* ForceUpdateViewController.xib in Resources */,
DD6DC5C321B6C27F00F9D538 /* pia-spinner.json in Resources */,
0E0715E7201CBB7100D6F666 /* Flags-dev.plist in Resources */,
DD1C138A21E60C63004004B3 /* IPTile.xib in Resources */,
Expand Down Expand Up @@ -5103,6 +5120,7 @@
291C6398183EBC210039EC03 /* Images.xcassets in Resources */,
82183D9625014FDC0033023F /* NetworkCollectionViewCell.xib in Resources */,
82183D9825014FDC0033023F /* CustomNetworkCollectionViewCell.xib in Resources */,
E55188942CB66BCA00E4C241 /* ForceUpdateViewController.xib in Resources */,
E501CBF72AE9806800515006 /* Signup.strings in Resources */,
0E0786DE1EFA7EAE00F77466 /* Components.plist in Resources */,
E501CBB32AE97EBA00515006 /* Signup.storyboard in Resources */,
Expand Down Expand Up @@ -5422,6 +5440,7 @@
E5C507702B0DEC2400200A6A /* AutolayoutViewController.swift in Sources */,
82CAB8F3255C0CD100BB08EF /* MessagesTileCollectionViewCell.swift in Sources */,
E5217F462AEACE0200123442 /* NavigationLogoView.swift in Sources */,
E55188952CB66BCA00E4C241 /* ForceUpdateViewController.swift in Sources */,
E58A45622BA8E373002A0704 /* LoginProvider.swift in Sources */,
E59E8FB02AEA7A81009278F5 /* MagicLinkLoginViewController.swift in Sources */,
0E3A352D1FD9CDC5000B0F99 /* Theme+App.swift in Sources */,
Expand Down Expand Up @@ -5516,6 +5535,7 @@
8272C6332657EE4E00D846A8 /* AutomationSettingsViewController.swift in Sources */,
E59E8FBB2AEA7A81009278F5 /* GDPRViewController.swift in Sources */,
DDF7F755240D35BA00A671C7 /* CustomServerSettingsViewController.swift in Sources */,
E55188932CB66BCA00E4C241 /* ForceUpdateViewController.swift in Sources */,
0ECF5C082017EBAD0047596C /* ThemeCode.swift in Sources */,
3545E98026AAD60C00B812CC /* ServerSelectionDelegate.swift in Sources */,
E5217F402AEAC7A900123442 /* Theme+LightPalette.swift in Sources */,
Expand Down
7 changes: 6 additions & 1 deletion PIA VPN/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,12 @@ class AppDelegate: NSObject, UIApplicationDelegate {
let accountInformationVerifier = AccountInformationAvailabilityFactory.makeAccountInformationAvailabilityVerifier()

accountInformationVerifier.verifyAccountInformationAvailabity(after: AccountInformationAvailabilityVerifier.defaultDeadlineInSeconds, completion: nil)


Client.providers.accountProvider.featureFlags({ _ in
if Client.configuration.featureFlags.contains("force_update") {
NotificationCenter.default.post(name: Notification.Name.__AppDidFetchForceUpdateFeatureFlag, object: nil)
}
})
}

private func refreshShortcutItems(in application: UIApplication) {
Expand Down
15 changes: 14 additions & 1 deletion PIA VPN/Bootstrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ import TunnelKitOpenVPN
import PIAWireguard
#endif
import SwiftyBeaver
import UIKit

extension NSNotification.Name {
public static let __AppDidFetchForceUpdateFeatureFlag = Notification.Name("__AppDidFetchForceUpdateFeatureFlag")
}

class Bootstrapper {

Expand Down Expand Up @@ -162,12 +166,13 @@ class Bootstrapper {
AppPreferences.shared.checksDipExpirationRequest = Client.configuration.featureFlags.contains(Client.FeatureFlags.checkDipExpirationRequest)
AppPreferences.shared.disablesMultiDipTokens = Client.configuration.featureFlags.contains(Client.FeatureFlags.disableMultiDipTokens)
AppPreferences.shared.showNewInitialScreen = Client.configuration.featureFlags.contains(Client.FeatureFlags.showNewInitialScreen)


/// Updates the feature flags values to the ones set on the server only on Release builds.
/// (like Leak protection feature)
self.updateFeatureFlagsForReleaseIfNeeded()

self.checkForceUpdateIfNeeded()
})

//FORCE THE MIGRATION TO GEN4
Expand Down Expand Up @@ -327,3 +332,11 @@ class Bootstrapper {
#endif
}
}

extension Bootstrapper {
func checkForceUpdateIfNeeded() {
if Client.configuration.featureFlags.contains("force_update") {
NotificationCenter.default.post(name: Notification.Name.__AppDidFetchForceUpdateFeatureFlag, object: nil)
}
}
}
9 changes: 9 additions & 0 deletions PIA VPN/DashboardViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ class DashboardViewController: AutolayoutViewController {
nc.addObserver(self, selector: #selector(connectionVPNStatusDidChange(_:)), name: NSNotification.Name.NEVPNStatusDidChange, object: nil)
nc.addObserver(self, selector: #selector(handleDidConnectToRFC1918CompliantWifi(_:)), name: NSNotification.Name.DeviceDidConnectToRFC1918CompliantWifi, object: nil)
nc.addObserver(self, selector: #selector(checkConnectToRFC1918VulnerableWifi(_:)), name: NSNotification.Name.DeviceDidConnectToRFC1918VulnerableWifi, object: nil)
nc.addObserver(self, selector: #selector(presentForceUpdate), name: NSNotification.Name.__AppDidFetchForceUpdateFeatureFlag, object: nil)

self.viewContentHeight = self.viewContentHeightConstraint.constant
}
Expand Down Expand Up @@ -701,6 +702,14 @@ class DashboardViewController: AutolayoutViewController {
}
}

@objc func presentForceUpdate() {
let forceUpdate = ForceUpdateViewController()
forceUpdate.modalPresentationStyle = .fullScreen
DispatchQueue.main.async { [weak self] in
self?.present(forceUpdate, animated: false)
}
}

//MARK: Non compliant Wifi alert

private struct WifiAlertAction {
Expand Down
40 changes: 40 additions & 0 deletions PIA VPN/ForceUpdateViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// ForceUpdateViewController.swift
// PIA VPN
//
// Created by Said Rehouni on 9/10/24.
// Copyright © 2024 Private Internet Access Inc. All rights reserved.
//

import UIKit
import PIALibrary

class ForceUpdateViewController: UIViewController {
@IBOutlet weak var updateButton: PIAButton!
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var descriptionLabel: UILabel!


override func viewDidLoad() {
super.viewDidLoad()

// Do any additional setup after loading the view.

styleUpdateButton()

updateButton.addTarget(self, action: #selector(updateButtonTapped), for: .touchUpInside)
updateButton.setTitle("Update Now", for: .normal)
}

@objc func updateButtonTapped() {
Client.providers.vpnProvider.uninstallAll()
UIApplication.shared.open(URL(string: "https://itunes.apple.com/app/private-internet-access-anonymous/id955626407")!)
}

private func styleUpdateButton() {
updateButton.setRounded()
updateButton.style(style: TextStyle.Buttons.piaGreenButton)
updateButton.setTitle(L10n.Welcome.Purchase.submit.uppercased(),
for: [])
}
}
90 changes: 90 additions & 0 deletions PIA VPN/ForceUpdateViewController.xib
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ForceUpdateViewController" customModule="PIA_VPN" customModuleProvider="target">
<connections>
<outlet property="descriptionLabel" destination="ecX-Zr-LdC" id="6Bv-B0-uO8"/>
<outlet property="titleLabel" destination="KbD-fS-iw2" id="zVZ-aP-q9i"/>
<outlet property="updateButton" destination="HLl-yh-l1E" id="goe-zj-ZRg"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" tag="2" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="24" translatesAutoresizingMaskIntoConstraints="NO" id="liw-vr-nmU">
<rect key="frame" x="20" y="119" width="353" height="639"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="force_update_shield" translatesAutoresizingMaskIntoConstraints="NO" id="7dx-Zd-LvJ">
<rect key="frame" x="103.66666666666669" y="0.0" width="146" height="138"/>
<constraints>
<constraint firstAttribute="width" constant="146" id="DDI-PN-m5q"/>
<constraint firstAttribute="height" constant="138" id="XbN-Iz-yzO"/>
</constraints>
</imageView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="top" spacing="24" translatesAutoresizingMaskIntoConstraints="NO" id="FQV-ZF-r2m">
<rect key="frame" x="10.333333333333343" y="162" width="332.66666666666663" height="111.33333333333331"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Upgrade Your Experience" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="KbD-fS-iw2">
<rect key="frame" x="0.0" y="0.0" width="248.33333333333334" height="26.333333333333332"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="22"/>
<color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="You’re using an older version of PIA. Update your app now to enjoy an enhanced experience with all the latest features." textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ecX-Zr-LdC">
<rect key="frame" x="0.0" y="50.333333333333314" width="332.66666666666669" height="61"/>
<fontDescription key="fontDescription" type="system" weight="light" pointSize="17"/>
<color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ty5-Yz-511">
<rect key="frame" x="56.666666666666686" y="297.33333333333326" width="240" height="267.66666666666674"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="HLl-yh-l1E" customClass="PIAButton" customModule="PIALibrary">
<rect key="frame" x="0.0" y="589" width="353" height="50"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="Vt7-9x-RzF"/>
</constraints>
<color key="tintColor" red="0.99999600649999998" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<state key="normal" title="Button"/>
<buttonConfiguration key="configuration" style="plain" title="Button"/>
</button>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="HLl-yh-l1E" secondAttribute="trailing" id="d0Y-di-7gB"/>
<constraint firstItem="HLl-yh-l1E" firstAttribute="leading" secondItem="liw-vr-nmU" secondAttribute="leading" id="qQa-K0-vqg"/>
</constraints>
</stackView>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="liw-vr-nmU" secondAttribute="bottom" constant="60" id="DYi-Hx-NzJ"/>
<constraint firstItem="liw-vr-nmU" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="20" id="DsA-7H-Iv1"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="liw-vr-nmU" secondAttribute="trailing" constant="20" id="IJR-hN-7PH"/>
<constraint firstItem="liw-vr-nmU" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="60" id="z6E-K9-CBQ"/>
</constraints>
<point key="canvasLocation" x="139.69465648854961" y="20.422535211267608"/>
</view>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" id="joW-BT-sWM">
<rect key="frame" x="0.0" y="0.0" width="240" height="128"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<point key="canvasLocation" x="727" y="-15"/>
</imageView>
</objects>
<resources>
<image name="force_update_shield" width="146" height="138"/>
</resources>
</document>
15 changes: 15 additions & 0 deletions PIA VPN/Images.xcassets/force_update_shield.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"images" : [
{
"filename" : "shield.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true
}
}
Binary file not shown.
3 changes: 3 additions & 0 deletions PIA VPN/PIAHotspotHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ class PIAHotspotHelper {
}
return NEHotspotHelper.register(options: options,
queue: DispatchQueue.main) { [weak self] (cmd: NEHotspotHelperCommand) in

guard !Client.configuration.featureFlags.contains("force_update") else { return }

if let weakSelf = self {
if cmd.commandType == .filterScanList {
log.info("filtering ssid list")
Expand Down
Loading
Loading