Proper VPN simulator with notifications, etc.
This commit is contained in:
@@ -17,6 +17,10 @@
|
|||||||
541075CF24C9D43A00D6F1BF /* UNNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 541075CD24C9D43A00D6F1BF /* UNNotification.swift */; };
|
541075CF24C9D43A00D6F1BF /* UNNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 541075CD24C9D43A00D6F1BF /* UNNotification.swift */; };
|
||||||
541075D124CDBA0000D6F1BF /* ThrottledBatchQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 541075D024CDBA0000D6F1BF /* ThrottledBatchQueue.swift */; };
|
541075D124CDBA0000D6F1BF /* ThrottledBatchQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 541075D024CDBA0000D6F1BF /* ThrottledBatchQueue.swift */; };
|
||||||
541075D224CDBA0000D6F1BF /* ThrottledBatchQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 541075D024CDBA0000D6F1BF /* ThrottledBatchQueue.swift */; };
|
541075D224CDBA0000D6F1BF /* ThrottledBatchQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 541075D024CDBA0000D6F1BF /* ThrottledBatchQueue.swift */; };
|
||||||
|
541075D524CE286200D6F1BF /* CachedConnectionAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 541075D424CE286200D6F1BF /* CachedConnectionAlert.swift */; };
|
||||||
|
541075D624CE286200D6F1BF /* CachedConnectionAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 541075D424CE286200D6F1BF /* CachedConnectionAlert.swift */; };
|
||||||
|
541075D924CE2C7200D6F1BF /* GlassVPNHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 541075D824CE2C7200D6F1BF /* GlassVPNHook.swift */; };
|
||||||
|
541075DA24CE2C7200D6F1BF /* GlassVPNHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 541075D824CE2C7200D6F1BF /* GlassVPNHook.swift */; };
|
||||||
5412F8EE24571B8200A63D7A /* VCDateFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5412F8ED24571B8100A63D7A /* VCDateFilter.swift */; };
|
5412F8EE24571B8200A63D7A /* VCDateFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5412F8ED24571B8100A63D7A /* VCDateFilter.swift */; };
|
||||||
5412FCC224C628FA000DE429 /* TVCReminderAlerts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5412FCBF24C628F9000DE429 /* TVCReminderAlerts.swift */; };
|
5412FCC224C628FA000DE429 /* TVCReminderAlerts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5412FCBF24C628F9000DE429 /* TVCReminderAlerts.swift */; };
|
||||||
5412FCC324C628FA000DE429 /* TVCChooseAlertTone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5412FCC024C628F9000DE429 /* TVCChooseAlertTone.swift */; };
|
5412FCC324C628FA000DE429 /* TVCChooseAlertTone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5412FCC024C628F9000DE429 /* TVCChooseAlertTone.swift */; };
|
||||||
@@ -172,7 +176,7 @@
|
|||||||
54D8B9832471BD8100EB2414 /* DBAppOnly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D8B9822471BD8100EB2414 /* DBAppOnly.swift */; };
|
54D8B9832471BD8100EB2414 /* DBAppOnly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D8B9822471BD8100EB2414 /* DBAppOnly.swift */; };
|
||||||
54D8B98624796E9900EB2414 /* GroupedDomainDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D8B98524796E9800EB2414 /* GroupedDomainDataSource.swift */; };
|
54D8B98624796E9900EB2414 /* GroupedDomainDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D8B98524796E9800EB2414 /* GroupedDomainDataSource.swift */; };
|
||||||
54E540F2247C423200F7C34A /* DomainFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E540F1247C423200F7C34A /* DomainFilter.swift */; };
|
54E540F2247C423200F7C34A /* DomainFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E540F1247C423200F7C34A /* DomainFilter.swift */; };
|
||||||
54E540F4247D3F2600F7C34A /* TestDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E540F3247D3F2600F7C34A /* TestDataSource.swift */; };
|
54E540F4247D3F2600F7C34A /* SimulatorVPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E540F3247D3F2600F7C34A /* SimulatorVPN.swift */; };
|
||||||
54E540F8247DB90F00F7C34A /* RecordingsDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E540F7247DB90F00F7C34A /* RecordingsDB.swift */; };
|
54E540F8247DB90F00F7C34A /* RecordingsDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E540F7247DB90F00F7C34A /* RecordingsDB.swift */; };
|
||||||
54E540FA2482414800F7C34A /* SyncUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E540F92482414800F7C34A /* SyncUpdate.swift */; };
|
54E540FA2482414800F7C34A /* SyncUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E540F92482414800F7C34A /* SyncUpdate.swift */; };
|
||||||
54E67E4624A8B0FE0025D261 /* PrefsShared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E67E4524A8B0FE0025D261 /* PrefsShared.swift */; };
|
54E67E4624A8B0FE0025D261 /* PrefsShared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E67E4524A8B0FE0025D261 /* PrefsShared.swift */; };
|
||||||
@@ -216,6 +220,8 @@
|
|||||||
540E67832433FAFE00871BBE /* TVCPreviousRecords.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVCPreviousRecords.swift; sourceTree = "<group>"; };
|
540E67832433FAFE00871BBE /* TVCPreviousRecords.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVCPreviousRecords.swift; sourceTree = "<group>"; };
|
||||||
541075CD24C9D43A00D6F1BF /* UNNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UNNotification.swift; sourceTree = "<group>"; };
|
541075CD24C9D43A00D6F1BF /* UNNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UNNotification.swift; sourceTree = "<group>"; };
|
||||||
541075D024CDBA0000D6F1BF /* ThrottledBatchQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThrottledBatchQueue.swift; sourceTree = "<group>"; };
|
541075D024CDBA0000D6F1BF /* ThrottledBatchQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThrottledBatchQueue.swift; sourceTree = "<group>"; };
|
||||||
|
541075D424CE286200D6F1BF /* CachedConnectionAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachedConnectionAlert.swift; sourceTree = "<group>"; };
|
||||||
|
541075D824CE2C7200D6F1BF /* GlassVPNHook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlassVPNHook.swift; sourceTree = "<group>"; };
|
||||||
5412F8ED24571B8100A63D7A /* VCDateFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VCDateFilter.swift; sourceTree = "<group>"; };
|
5412F8ED24571B8100A63D7A /* VCDateFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VCDateFilter.swift; sourceTree = "<group>"; };
|
||||||
5412FCBF24C628F9000DE429 /* TVCReminderAlerts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TVCReminderAlerts.swift; sourceTree = "<group>"; };
|
5412FCBF24C628F9000DE429 /* TVCReminderAlerts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TVCReminderAlerts.swift; sourceTree = "<group>"; };
|
||||||
5412FCC024C628F9000DE429 /* TVCChooseAlertTone.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TVCChooseAlertTone.swift; sourceTree = "<group>"; };
|
5412FCC024C628F9000DE429 /* TVCChooseAlertTone.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TVCChooseAlertTone.swift; sourceTree = "<group>"; };
|
||||||
@@ -365,7 +371,7 @@
|
|||||||
54D8B9822471BD8100EB2414 /* DBAppOnly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBAppOnly.swift; sourceTree = "<group>"; };
|
54D8B9822471BD8100EB2414 /* DBAppOnly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBAppOnly.swift; sourceTree = "<group>"; };
|
||||||
54D8B98524796E9800EB2414 /* GroupedDomainDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupedDomainDataSource.swift; sourceTree = "<group>"; };
|
54D8B98524796E9800EB2414 /* GroupedDomainDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupedDomainDataSource.swift; sourceTree = "<group>"; };
|
||||||
54E540F1247C423200F7C34A /* DomainFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainFilter.swift; sourceTree = "<group>"; };
|
54E540F1247C423200F7C34A /* DomainFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainFilter.swift; sourceTree = "<group>"; };
|
||||||
54E540F3247D3F2600F7C34A /* TestDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestDataSource.swift; sourceTree = "<group>"; };
|
54E540F3247D3F2600F7C34A /* SimulatorVPN.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimulatorVPN.swift; sourceTree = "<group>"; };
|
||||||
54E540F7247DB90F00F7C34A /* RecordingsDB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordingsDB.swift; sourceTree = "<group>"; };
|
54E540F7247DB90F00F7C34A /* RecordingsDB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordingsDB.swift; sourceTree = "<group>"; };
|
||||||
54E540F92482414800F7C34A /* SyncUpdate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncUpdate.swift; sourceTree = "<group>"; };
|
54E540F92482414800F7C34A /* SyncUpdate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncUpdate.swift; sourceTree = "<group>"; };
|
||||||
54E67E4524A8B0FE0025D261 /* PrefsShared.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefsShared.swift; sourceTree = "<group>"; };
|
54E67E4524A8B0FE0025D261 /* PrefsShared.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefsShared.swift; sourceTree = "<group>"; };
|
||||||
@@ -430,6 +436,17 @@
|
|||||||
path = Recordings;
|
path = Recordings;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
541075D324CE284700D6F1BF /* Push Notifications */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
541075CD24C9D43A00D6F1BF /* UNNotification.swift */,
|
||||||
|
54CE8BC324B1ED2100CC1756 /* PushNotification.swift */,
|
||||||
|
543078C824B75CD100278F2D /* PushNotificationAppOnly.swift */,
|
||||||
|
541075D424CE286200D6F1BF /* CachedConnectionAlert.swift */,
|
||||||
|
);
|
||||||
|
path = "Push Notifications";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
541AC5CB2399498A00A769D7 = {
|
541AC5CB2399498A00A769D7 = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -456,9 +473,11 @@
|
|||||||
54E540F0247C386500F7C34A /* Data Source */,
|
54E540F0247C386500F7C34A /* Data Source */,
|
||||||
54B345A4241BB975004C53CC /* Extensions */,
|
54B345A4241BB975004C53CC /* Extensions */,
|
||||||
545DDDD224436A03003B6544 /* Common Classes */,
|
545DDDD224436A03003B6544 /* Common Classes */,
|
||||||
|
541075D324CE284700D6F1BF /* Push Notifications */,
|
||||||
548B1F9423D338EC005B047C /* main.entitlements */,
|
548B1F9423D338EC005B047C /* main.entitlements */,
|
||||||
541AC5D72399498A00A769D7 /* AppDelegate.swift */,
|
541AC5D72399498A00A769D7 /* AppDelegate.swift */,
|
||||||
54E67E4A24A8C6370025D261 /* GlassVPN.swift */,
|
54E67E4A24A8C6370025D261 /* GlassVPN.swift */,
|
||||||
|
541075D824CE2C7200D6F1BF /* GlassVPNHook.swift */,
|
||||||
542E2A972404973F001462DC /* TBCMain.swift */,
|
542E2A972404973F001462DC /* TBCMain.swift */,
|
||||||
540C6454240D5BAE00E948F9 /* Requests */,
|
540C6454240D5BAE00E948F9 /* Requests */,
|
||||||
540E677E242D2CD200871BBE /* Recordings */,
|
540E677E242D2CD200871BBE /* Recordings */,
|
||||||
@@ -538,8 +557,6 @@
|
|||||||
541FC47524A12D01009154D8 /* IBViews.swift */,
|
541FC47524A12D01009154D8 /* IBViews.swift */,
|
||||||
5404AEEC24A95F3F003B2F54 /* SlideInAnimation.swift */,
|
5404AEEC24A95F3F003B2F54 /* SlideInAnimation.swift */,
|
||||||
541075D024CDBA0000D6F1BF /* ThrottledBatchQueue.swift */,
|
541075D024CDBA0000D6F1BF /* ThrottledBatchQueue.swift */,
|
||||||
54CE8BC324B1ED2100CC1756 /* PushNotification.swift */,
|
|
||||||
543078C824B75CD100278F2D /* PushNotificationAppOnly.swift */,
|
|
||||||
);
|
);
|
||||||
path = "Common Classes";
|
path = "Common Classes";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -562,7 +579,6 @@
|
|||||||
54B345A8241BBA0B004C53CC /* Logging.swift */,
|
54B345A8241BBA0B004C53CC /* Logging.swift */,
|
||||||
54E67E4E24A8E2910025D261 /* Equatable.swift */,
|
54E67E4E24A8E2910025D261 /* Equatable.swift */,
|
||||||
54B345A5241BB982004C53CC /* Notifications.swift */,
|
54B345A5241BB982004C53CC /* Notifications.swift */,
|
||||||
541075CD24C9D43A00D6F1BF /* UNNotification.swift */,
|
|
||||||
54B345AA241BBA5B004C53CC /* AlertSheet.swift */,
|
54B345AA241BBA5B004C53CC /* AlertSheet.swift */,
|
||||||
54E67E5024A8E8820025D261 /* View.swift */,
|
54E67E5024A8E8820025D261 /* View.swift */,
|
||||||
541DCA6024A6B0F6005F1A4B /* Color.swift */,
|
541DCA6024A6B0F6005F1A4B /* Color.swift */,
|
||||||
@@ -812,7 +828,7 @@
|
|||||||
54E540F0247C386500F7C34A /* Data Source */ = {
|
54E540F0247C386500F7C34A /* Data Source */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
54E540F3247D3F2600F7C34A /* TestDataSource.swift */,
|
54E540F3247D3F2600F7C34A /* SimulatorVPN.swift */,
|
||||||
54E540F92482414800F7C34A /* SyncUpdate.swift */,
|
54E540F92482414800F7C34A /* SyncUpdate.swift */,
|
||||||
54D8B98524796E9800EB2414 /* GroupedDomainDataSource.swift */,
|
54D8B98524796E9800EB2414 /* GroupedDomainDataSource.swift */,
|
||||||
54E540F1247C423200F7C34A /* DomainFilter.swift */,
|
54E540F1247C423200F7C34A /* DomainFilter.swift */,
|
||||||
@@ -964,7 +980,9 @@
|
|||||||
54E67E4924A8B1280025D261 /* Prefs.swift in Sources */,
|
54E67E4924A8B1280025D261 /* Prefs.swift in Sources */,
|
||||||
54E540F8247DB90F00F7C34A /* RecordingsDB.swift in Sources */,
|
54E540F8247DB90F00F7C34A /* RecordingsDB.swift in Sources */,
|
||||||
54E67E4F24A8E2910025D261 /* Equatable.swift in Sources */,
|
54E67E4F24A8E2910025D261 /* Equatable.swift in Sources */,
|
||||||
54E540F4247D3F2600F7C34A /* TestDataSource.swift in Sources */,
|
54E540F4247D3F2600F7C34A /* SimulatorVPN.swift in Sources */,
|
||||||
|
541075D924CE2C7200D6F1BF /* GlassVPNHook.swift in Sources */,
|
||||||
|
541075D524CE286200D6F1BF /* CachedConnectionAlert.swift in Sources */,
|
||||||
5404AEEF24ACC089003B2F54 /* VCAnalysisBar.swift in Sources */,
|
5404AEEF24ACC089003B2F54 /* VCAnalysisBar.swift in Sources */,
|
||||||
545DDDD424466D37003B6544 /* AutoLayout.swift in Sources */,
|
545DDDD424466D37003B6544 /* AutoLayout.swift in Sources */,
|
||||||
54B345AD241BBB00004C53CC /* DBExtensions.swift in Sources */,
|
54B345AD241BBB00004C53CC /* DBExtensions.swift in Sources */,
|
||||||
@@ -1082,6 +1100,7 @@
|
|||||||
54751E522423955100168273 /* URL.swift in Sources */,
|
54751E522423955100168273 /* URL.swift in Sources */,
|
||||||
54CA02A92426B2FD003A5E04 /* RejectAdapter.swift in Sources */,
|
54CA02A92426B2FD003A5E04 /* RejectAdapter.swift in Sources */,
|
||||||
54CA02732426B2FD003A5E04 /* IPPool.swift in Sources */,
|
54CA02732426B2FD003A5E04 /* IPPool.swift in Sources */,
|
||||||
|
541075D624CE286200D6F1BF /* CachedConnectionAlert.swift in Sources */,
|
||||||
54CA027E2426B2FD003A5E04 /* DomainListRule.swift in Sources */,
|
54CA027E2426B2FD003A5E04 /* DomainListRule.swift in Sources */,
|
||||||
54CA02782426B2FD003A5E04 /* BinaryDataScanner.swift in Sources */,
|
54CA02782426B2FD003A5E04 /* BinaryDataScanner.swift in Sources */,
|
||||||
54CA02B12426B2FD003A5E04 /* ServerAdapterFactory.swift in Sources */,
|
54CA02B12426B2FD003A5E04 /* ServerAdapterFactory.swift in Sources */,
|
||||||
@@ -1112,6 +1131,7 @@
|
|||||||
54CA02B32426B2FD003A5E04 /* HTTPAdapterFactory.swift in Sources */,
|
54CA02B32426B2FD003A5E04 /* HTTPAdapterFactory.swift in Sources */,
|
||||||
54CA02702426B2FD003A5E04 /* HTTPStreamScanner.swift in Sources */,
|
54CA02702426B2FD003A5E04 /* HTTPStreamScanner.swift in Sources */,
|
||||||
54CA02812426B2FD003A5E04 /* DNSFailRule.swift in Sources */,
|
54CA02812426B2FD003A5E04 /* DNSFailRule.swift in Sources */,
|
||||||
|
541075DA24CE2C7200D6F1BF /* GlassVPNHook.swift in Sources */,
|
||||||
54CA02AC2426B2FD003A5E04 /* AuthenticationServerAdapterFactory.swift in Sources */,
|
54CA02AC2426B2FD003A5E04 /* AuthenticationServerAdapterFactory.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import NetworkExtension
|
import NetworkExtension
|
||||||
import UserNotifications
|
|
||||||
|
|
||||||
private let queue = DispatchQueue.init(label: "PSIGlassDNSQueue", qos: .userInteractive, target: .main)
|
fileprivate var hook : GlassVPNHook!
|
||||||
|
|
||||||
// MARK: ObserverFactory
|
// MARK: ObserverFactory
|
||||||
|
|
||||||
@@ -16,10 +15,7 @@ class LDObserverFactory: ObserverFactory {
|
|||||||
override func signal(_ event: ProxySocketEvent) {
|
override func signal(_ event: ProxySocketEvent) {
|
||||||
switch event {
|
switch event {
|
||||||
case .receivedRequest(let session, let socket):
|
case .receivedRequest(let session, let socket):
|
||||||
let i = filterIndex(for: session.host)
|
let kill = hook.processDNSRequest(session.host)
|
||||||
let (block, ignore, cA, cB) = (i<0) ? (false, false, false, false) : filterOptions[i]
|
|
||||||
let kill = ignore ? block : procRequest(session.host, blck: block, custA: cA, custB: cB)
|
|
||||||
// TODO: disable ignore & block during recordings
|
|
||||||
if kill { socket.forceDisconnect() }
|
if kill { socket.forceDisconnect() }
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
@@ -37,8 +33,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||||||
private let proxyServerAddress = "127.0.0.1"
|
private let proxyServerAddress = "127.0.0.1"
|
||||||
private var proxyServer: GCDHTTPProxyServer!
|
private var proxyServer: GCDHTTPProxyServer!
|
||||||
|
|
||||||
private var autoDeleteTimer: Timer? = nil
|
|
||||||
|
|
||||||
// MARK: Delegate
|
// MARK: Delegate
|
||||||
|
|
||||||
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
|
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
|
||||||
@@ -82,31 +76,13 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
|
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
|
||||||
let message = String(data: messageData, encoding: .utf8)
|
hook.handleAppMessage(messageData)
|
||||||
if let msg = message, let i = msg.firstIndex(of: ":") {
|
|
||||||
let action = msg.prefix(upTo: i)
|
|
||||||
let value = msg.suffix(from: msg.index(after: i))
|
|
||||||
switch action {
|
|
||||||
case "filter-update":
|
|
||||||
reloadDomainFilter() // TODO: reload only selected domain?
|
|
||||||
return
|
|
||||||
case "auto-delete":
|
|
||||||
setAutoDelete(Int(value) ?? PrefsShared.AutoDeleteLogsDays)
|
|
||||||
return
|
|
||||||
case "notify-prefs-change":
|
|
||||||
reloadNotificationSettings()
|
|
||||||
return
|
|
||||||
default: break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DDLogWarn("This should never happen! Received unknown handleAppMessage: \(message ?? messageData.base64EncodedString())")
|
|
||||||
reloadSettings() // just in case we fallback to do everything
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Helper
|
// MARK: Helper
|
||||||
|
|
||||||
private func willInitProxy() {
|
private func willInitProxy() {
|
||||||
reloadSettings()
|
hook = GlassVPNHook()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func createProxy() -> NEPacketTunnelNetworkSettings {
|
private func createProxy() -> NEPacketTunnelNetworkSettings {
|
||||||
@@ -143,155 +119,11 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||||||
proxyServer.stop()
|
proxyServer.stop()
|
||||||
proxyServer = nil
|
proxyServer = nil
|
||||||
// custom
|
// custom
|
||||||
filterDomains = nil
|
hook.cleanUp()
|
||||||
filterOptions = nil
|
hook = nil
|
||||||
autoDeleteTimer?.fire() // one last time before we quit
|
|
||||||
autoDeleteTimer?.invalidate()
|
|
||||||
notifyTone = nil
|
|
||||||
if PrefsShared.RestartReminder.Enabled {
|
if PrefsShared.RestartReminder.Enabled {
|
||||||
PushNotification.scheduleRestartReminderBadge(on: true)
|
PushNotification.scheduleRestartReminderBadge(on: true)
|
||||||
PushNotification.scheduleRestartReminderBanner()
|
PushNotification.scheduleRestartReminderBanner()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func reloadSettings() {
|
|
||||||
reloadDomainFilter()
|
|
||||||
setAutoDelete(PrefsShared.AutoDeleteLogsDays)
|
|
||||||
reloadNotificationSettings()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ################################################################
|
|
||||||
// #
|
|
||||||
// # MARK: - Domain Filter
|
|
||||||
// #
|
|
||||||
// ################################################################
|
|
||||||
|
|
||||||
fileprivate var filterDomains: [String]!
|
|
||||||
fileprivate var filterOptions: [(block: Bool, ignore: Bool, customA: Bool, customB: Bool)]!
|
|
||||||
|
|
||||||
extension PacketTunnelProvider {
|
|
||||||
fileprivate func reloadDomainFilter() {
|
|
||||||
let tmp = AppDB?.loadFilters()?.map({
|
|
||||||
(String($0.reversed()), $1)
|
|
||||||
}).sorted(by: { $0.0 < $1.0 }) ?? []
|
|
||||||
let t1 = tmp.map { $0.0 }
|
|
||||||
let t2 = tmp.map { ($1.contains(.blocked),
|
|
||||||
$1.contains(.ignored),
|
|
||||||
$1.contains(.customA),
|
|
||||||
$1.contains(.customB)) }
|
|
||||||
filterDomains = t1
|
|
||||||
filterOptions = t2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Backward DNS Binary Tree Lookup
|
|
||||||
fileprivate func filterIndex(for domain: String) -> Int {
|
|
||||||
let reverseDomain = String(domain.reversed())
|
|
||||||
var lo = 0, hi = filterDomains.count - 1
|
|
||||||
while lo <= hi {
|
|
||||||
let mid = (lo + hi)/2
|
|
||||||
if filterDomains[mid] < reverseDomain {
|
|
||||||
lo = mid + 1
|
|
||||||
} else if reverseDomain < filterDomains[mid] {
|
|
||||||
hi = mid - 1
|
|
||||||
} else {
|
|
||||||
return mid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if lo > 0, reverseDomain.hasPrefix(filterDomains[lo - 1] + ".") {
|
|
||||||
return lo - 1
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ################################################################
|
|
||||||
// #
|
|
||||||
// # MARK: - Auto-delete Timer
|
|
||||||
// #
|
|
||||||
// ################################################################
|
|
||||||
|
|
||||||
extension PacketTunnelProvider {
|
|
||||||
|
|
||||||
private func setAutoDelete(_ days: Int) {
|
|
||||||
autoDeleteTimer?.invalidate()
|
|
||||||
guard days > 0 else { return }
|
|
||||||
// Repeat interval uses days as hours. min 1 hr, max 24 hrs.
|
|
||||||
let interval = TimeInterval(min(24, days) * 60 * 60)
|
|
||||||
autoDeleteTimer = Timer.scheduledTimer(timeInterval: interval,
|
|
||||||
target: self, selector: #selector(autoDeleteNow),
|
|
||||||
userInfo: days, repeats: true)
|
|
||||||
autoDeleteTimer!.fire()
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func autoDeleteNow(_ sender: Timer) {
|
|
||||||
DDLogInfo("Auto-delete old logs")
|
|
||||||
queue.async {
|
|
||||||
do {
|
|
||||||
try AppDB?.dnsLogsDeleteOlderThan(days: sender.userInfo as! Int)
|
|
||||||
} catch {
|
|
||||||
DDLogWarn("Couldn't delete logs, will retry in 5 minutes. \(error)")
|
|
||||||
if sender.isValid {
|
|
||||||
sender.fireDate = Date().addingTimeInterval(300) // retry in 5 min
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ################################################################
|
|
||||||
// #
|
|
||||||
// # MARK: - Notifications
|
|
||||||
// #
|
|
||||||
// ################################################################
|
|
||||||
|
|
||||||
fileprivate var notifyEnabled: Bool = false
|
|
||||||
fileprivate var notifyIvertMode: Bool = false
|
|
||||||
fileprivate var notifyListBlocked: Bool = false
|
|
||||||
fileprivate var notifyListCustomA: Bool = false
|
|
||||||
fileprivate var notifyListCustomB: Bool = false
|
|
||||||
fileprivate var notifyListElse: Bool = false
|
|
||||||
fileprivate var notifyTone: AnyObject?
|
|
||||||
|
|
||||||
extension PacketTunnelProvider {
|
|
||||||
func reloadNotificationSettings() {
|
|
||||||
notifyEnabled = PrefsShared.ConnectionAlerts.Enabled
|
|
||||||
guard #available(iOS 10.0, *), notifyEnabled else {
|
|
||||||
notifyTone = nil
|
|
||||||
return
|
|
||||||
}
|
|
||||||
notifyIvertMode = PrefsShared.ConnectionAlerts.ExcludeMode
|
|
||||||
notifyListBlocked = PrefsShared.ConnectionAlerts.Lists.Blocked
|
|
||||||
notifyListCustomA = PrefsShared.ConnectionAlerts.Lists.CustomA
|
|
||||||
notifyListCustomB = PrefsShared.ConnectionAlerts.Lists.CustomB
|
|
||||||
notifyListElse = PrefsShared.ConnectionAlerts.Lists.Else
|
|
||||||
notifyTone = UNNotificationSound.from(string: PrefsShared.ConnectionAlerts.Sound)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ################################################################
|
|
||||||
// #
|
|
||||||
// # MARK: - Process DNS Request
|
|
||||||
// #
|
|
||||||
// ################################################################
|
|
||||||
|
|
||||||
/// Log domain request and post notification if wanted.
|
|
||||||
/// - Returns: `true` if the request shoud be blocked
|
|
||||||
fileprivate func procRequest(_ domain: String, blck: Bool, custA: Bool, custB: Bool) -> Bool {
|
|
||||||
queue.async {
|
|
||||||
do { try AppDB?.logWrite(domain, blocked: blck) }
|
|
||||||
catch { DDLogWarn("Couldn't write: \(error)") }
|
|
||||||
}
|
|
||||||
if #available(iOS 10.0, *), notifyEnabled {
|
|
||||||
let onAnyList = notifyListBlocked && blck || notifyListCustomA && custA || notifyListCustomB && custB || notifyListElse
|
|
||||||
if notifyIvertMode ? !onAnyList : onAnyList {
|
|
||||||
// TODO: wait for response to block or allow connection
|
|
||||||
PushNotification.scheduleConnectionAlert(domain, sound: notifyTone as! UNNotificationSound?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return blck
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||||||
PrefsShared.registerDefaults()
|
PrefsShared.registerDefaults()
|
||||||
|
|
||||||
#if IOS_SIMULATOR
|
#if IOS_SIMULATOR
|
||||||
TestDataSource.load()
|
SimulatorVPN.load()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sync.start()
|
sync.start()
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ import Foundation
|
|||||||
|
|
||||||
#if IOS_SIMULATOR
|
#if IOS_SIMULATOR
|
||||||
|
|
||||||
class TestDataSource {
|
fileprivate var hook : GlassVPNHook!
|
||||||
|
|
||||||
|
class SimulatorVPN {
|
||||||
|
static var timer: Timer?
|
||||||
|
|
||||||
static func load() {
|
static func load() {
|
||||||
QLog.Debug("SQLite path: \(URL.internalDB())")
|
QLog.Debug("SQLite path: \(URL.internalDB())")
|
||||||
@@ -27,13 +30,29 @@ class TestDataSource {
|
|||||||
db.setFilter("bi.test.com", [.blocked, .ignored])
|
db.setFilter("bi.test.com", [.blocked, .ignored])
|
||||||
|
|
||||||
QLog.Debug("Done")
|
QLog.Debug("Done")
|
||||||
|
}
|
||||||
Timer.repeating(2, call: #selector(insertRandom), on: self)
|
|
||||||
|
static func start() {
|
||||||
|
hook = GlassVPNHook()
|
||||||
|
timer = Timer.repeating(2, call: #selector(insertRandom), on: self)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func stop() {
|
||||||
|
timer?.invalidate()
|
||||||
|
timer = nil
|
||||||
|
hook.cleanUp()
|
||||||
|
hook = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc static func insertRandom() {
|
@objc static func insertRandom() {
|
||||||
//QLog.Debug("Inserting 1 periodic log entry")
|
//QLog.Debug("Inserting 1 periodic log entry")
|
||||||
try? AppDB?.logWrite("\(arc4random() % 5).count.test.com", blocked: true)
|
let domain = "\(arc4random() % 5).count.test.com"
|
||||||
|
let kill = hook.processDNSRequest(domain)
|
||||||
|
if kill { QLog.Info("Blocked: \(domain)") }
|
||||||
|
}
|
||||||
|
|
||||||
|
static func sendMsg(_ messageData: Data) {
|
||||||
|
hook.handleAppMessage(messageData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -10,6 +10,10 @@ final class GlassVPNManager {
|
|||||||
private(set) var state: VPNState = .off
|
private(set) var state: VPNState = .off
|
||||||
|
|
||||||
fileprivate init() {
|
fileprivate init() {
|
||||||
|
#if IOS_SIMULATOR
|
||||||
|
postProcessedVPNState(.on)
|
||||||
|
SimulatorVPN.start()
|
||||||
|
#else
|
||||||
NETunnelProviderManager.loadAllFromPreferences { managers, error in
|
NETunnelProviderManager.loadAllFromPreferences { managers, error in
|
||||||
self.managerVPN = managers?.first {
|
self.managerVPN = managers?.first {
|
||||||
($0.protocolConfiguration as? NETunnelProviderProtocol)?
|
($0.protocolConfiguration as? NETunnelProviderProtocol)?
|
||||||
@@ -24,10 +28,15 @@ final class GlassVPNManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
NSNotification.Name.NEVPNStatusDidChange.observe(call: #selector(vpnStatusChanged(_:)), on: self)
|
NSNotification.Name.NEVPNStatusDidChange.observe(call: #selector(vpnStatusChanged(_:)), on: self)
|
||||||
|
#endif
|
||||||
NotifyDNSFilterChanged.observe(call: #selector(didChangeDomainFilter), on: self)
|
NotifyDNSFilterChanged.observe(call: #selector(didChangeDomainFilter), on: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setEnabled(_ newState: Bool) {
|
func setEnabled(_ newState: Bool) {
|
||||||
|
#if IOS_SIMULATOR
|
||||||
|
postProcessedVPNState(newState ? .on : .off)
|
||||||
|
newState ? SimulatorVPN.start() : SimulatorVPN.stop()
|
||||||
|
#else
|
||||||
guard let mgr = self.managerVPN else {
|
guard let mgr = self.managerVPN else {
|
||||||
self.createNewVPN { manager in
|
self.createNewVPN { manager in
|
||||||
self.managerVPN = manager
|
self.managerVPN = manager
|
||||||
@@ -41,11 +50,18 @@ final class GlassVPNManager {
|
|||||||
newState ? try? mgr.connection.startVPNTunnel() : mgr.connection.stopVPNTunnel()
|
newState ? try? mgr.connection.startVPNTunnel() : mgr.connection.stopVPNTunnel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Notify VPN extension about changes
|
/// Notify VPN extension about changes
|
||||||
/// - Returns: `true` on success, `false` if VPN is off or message could not be converted to `.utf8`
|
/// - Returns: `true` on success, `false` if VPN is off or message could not be converted to `.utf8`
|
||||||
@discardableResult func send(_ message: VPNAppMessage) -> Bool {
|
@discardableResult func send(_ message: VPNAppMessage) -> Bool {
|
||||||
|
#if IOS_SIMULATOR
|
||||||
|
if state == .on, let data = message.raw {
|
||||||
|
SimulatorVPN.sendMsg(data)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
#else
|
||||||
if let session = self.managerVPN?.connection as? NETunnelProviderSession,
|
if let session = self.managerVPN?.connection as? NETunnelProviderSession,
|
||||||
session.status == .connected, let data = message.raw {
|
session.status == .connected, let data = message.raw {
|
||||||
do {
|
do {
|
||||||
@@ -53,6 +69,7 @@ final class GlassVPNManager {
|
|||||||
return true
|
return true
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
138
main/GlassVPNHook.swift
Normal file
138
main/GlassVPNHook.swift
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
class GlassVPNHook {
|
||||||
|
|
||||||
|
private let queue = DispatchQueue.init(label: "PSIGlassDNSQueue", qos: .userInteractive, target: .main)
|
||||||
|
|
||||||
|
private var filterDomains: [String]!
|
||||||
|
private var filterOptions: [(block: Bool, ignore: Bool, customA: Bool, customB: Bool)]!
|
||||||
|
private var autoDeleteTimer: Timer? = nil
|
||||||
|
private var cachedNotify: CachedConnectionAlert!
|
||||||
|
|
||||||
|
init() { reset() }
|
||||||
|
|
||||||
|
/// Reload from stored settings and rebuilt binary search tree
|
||||||
|
private func reset() {
|
||||||
|
reloadDomainFilter()
|
||||||
|
setAutoDelete(PrefsShared.AutoDeleteLogsDays)
|
||||||
|
cachedNotify = CachedConnectionAlert()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invalidate auto-delete timer and release stored properties. You should nullify this instance afterwards.
|
||||||
|
func cleanUp() {
|
||||||
|
filterDomains = nil
|
||||||
|
filterOptions = nil
|
||||||
|
autoDeleteTimer?.fire() // one last time before we quit
|
||||||
|
autoDeleteTimer?.invalidate()
|
||||||
|
cachedNotify = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call this method from `PacketTunnelProvider.handleAppMessage(_:completionHandler:)`
|
||||||
|
func handleAppMessage(_ messageData: Data) {
|
||||||
|
let message = String(data: messageData, encoding: .utf8)
|
||||||
|
if let msg = message, let i = msg.firstIndex(of: ":") {
|
||||||
|
let action = msg.prefix(upTo: i)
|
||||||
|
let value = msg.suffix(from: msg.index(after: i))
|
||||||
|
switch action {
|
||||||
|
case "filter-update":
|
||||||
|
reloadDomainFilter() // TODO: reload only selected domain?
|
||||||
|
return
|
||||||
|
case "auto-delete":
|
||||||
|
setAutoDelete(Int(value) ?? PrefsShared.AutoDeleteLogsDays)
|
||||||
|
return
|
||||||
|
case "notify-prefs-change":
|
||||||
|
cachedNotify = CachedConnectionAlert()
|
||||||
|
return
|
||||||
|
default: break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NSLog("[VPN.WARN] This should never happen! Received unknown handleAppMessage: \(message ?? messageData.base64EncodedString())")
|
||||||
|
reset() // just in case we fallback to do everything
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Process DNS Request
|
||||||
|
|
||||||
|
/// Log domain request and post notification (if enabled).
|
||||||
|
/// - Returns: `true` if the request shoud be blocked.
|
||||||
|
func processDNSRequest(_ domain: String) -> Bool {
|
||||||
|
let i = filterIndex(for: domain)
|
||||||
|
// TODO: disable ignore & block during recordings
|
||||||
|
let (block, ignore, cA, cB) = (i<0) ? (false, false, false, false) : filterOptions[i]
|
||||||
|
if ignore {
|
||||||
|
return block
|
||||||
|
}
|
||||||
|
queue.async {
|
||||||
|
do { try AppDB?.logWrite(domain, blocked: block) }
|
||||||
|
catch { NSLog("[VPN.WARN] Couldn't write: \(error)") }
|
||||||
|
}
|
||||||
|
cachedNotify.postOrIgnore(domain, blck: block, custA: cA, custB: cB)
|
||||||
|
// TODO: wait for notify response to block or allow connection
|
||||||
|
return block
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build binary tree for reverse DNS lookup
|
||||||
|
private func reloadDomainFilter() {
|
||||||
|
let tmp = AppDB?.loadFilters()?.map({
|
||||||
|
(String($0.reversed()), $1)
|
||||||
|
}).sorted(by: { $0.0 < $1.0 }) ?? []
|
||||||
|
let t1 = tmp.map { $0.0 }
|
||||||
|
let t2 = tmp.map { ($1.contains(.blocked),
|
||||||
|
$1.contains(.ignored),
|
||||||
|
$1.contains(.customA),
|
||||||
|
$1.contains(.customB)) }
|
||||||
|
filterDomains = t1
|
||||||
|
filterOptions = t2
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lookup for reverse DNS binary tree
|
||||||
|
private func filterIndex(for domain: String) -> Int {
|
||||||
|
let reverseDomain = String(domain.reversed())
|
||||||
|
var lo = 0, hi = filterDomains.count - 1
|
||||||
|
while lo <= hi {
|
||||||
|
let mid = (lo + hi)/2
|
||||||
|
if filterDomains[mid] < reverseDomain {
|
||||||
|
lo = mid + 1
|
||||||
|
} else if reverseDomain < filterDomains[mid] {
|
||||||
|
hi = mid - 1
|
||||||
|
} else {
|
||||||
|
return mid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if lo > 0, reverseDomain.hasPrefix(filterDomains[lo - 1] + ".") {
|
||||||
|
return lo - 1
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Auto-delete Timer
|
||||||
|
|
||||||
|
/// Prepare auto-delete timer with interval between 1 hr - 1 day.
|
||||||
|
/// - Parameter days: Max age to keep when deleting
|
||||||
|
private func setAutoDelete(_ days: Int) {
|
||||||
|
autoDeleteTimer?.invalidate()
|
||||||
|
guard days > 0 else { return }
|
||||||
|
// Repeat interval uses days as hours. min 1 hr, max 24 hrs.
|
||||||
|
let interval = TimeInterval(min(24, days) * 60 * 60)
|
||||||
|
autoDeleteTimer = Timer.scheduledTimer(timeInterval: interval,
|
||||||
|
target: self, selector: #selector(autoDeleteNow),
|
||||||
|
userInfo: days, repeats: true)
|
||||||
|
autoDeleteTimer!.fire()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Callback fired when old data should be deleted.
|
||||||
|
@objc private func autoDeleteNow(_ sender: Timer) {
|
||||||
|
NSLog("[VPN.INFO] Auto-delete old logs")
|
||||||
|
queue.async {
|
||||||
|
do {
|
||||||
|
try AppDB?.dnsLogsDeleteOlderThan(days: sender.userInfo as! Int)
|
||||||
|
} catch {
|
||||||
|
NSLog("[VPN.WARN] Couldn't delete logs, will retry in 5 minutes. \(error)")
|
||||||
|
if sender.isValid {
|
||||||
|
sender.fireDate = Date().addingTimeInterval(300) // retry in 5 min
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
43
main/Push Notifications/CachedConnectionAlert.swift
Normal file
43
main/Push Notifications/CachedConnectionAlert.swift
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import Foundation
|
||||||
|
import UserNotifications
|
||||||
|
|
||||||
|
struct CachedConnectionAlert {
|
||||||
|
let enabled: Bool
|
||||||
|
let invertedMode: Bool
|
||||||
|
let listBlocked, listCustomA, listCustomB, listElse: Bool
|
||||||
|
let tone: AnyObject?
|
||||||
|
|
||||||
|
init() {
|
||||||
|
enabled = PrefsShared.ConnectionAlerts.Enabled
|
||||||
|
guard #available(iOS 10.0, *), enabled else {
|
||||||
|
invertedMode = false
|
||||||
|
listBlocked = false
|
||||||
|
listCustomA = false
|
||||||
|
listCustomB = false
|
||||||
|
listElse = false
|
||||||
|
tone = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
invertedMode = PrefsShared.ConnectionAlerts.ExcludeMode
|
||||||
|
listBlocked = PrefsShared.ConnectionAlerts.Lists.Blocked
|
||||||
|
listCustomA = PrefsShared.ConnectionAlerts.Lists.CustomA
|
||||||
|
listCustomB = PrefsShared.ConnectionAlerts.Lists.CustomB
|
||||||
|
listElse = PrefsShared.ConnectionAlerts.Lists.Else
|
||||||
|
tone = UNNotificationSound.from(string: PrefsShared.ConnectionAlerts.Sound)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If notifications are enabled and allowed, schedule new notification. Otherwise NOOP.
|
||||||
|
/// - Parameters:
|
||||||
|
/// - domain: Domain will be used as unique identifier for noticiation center and in notification message.
|
||||||
|
/// - blck: Indicator whether `domain` is part of `blocked` list
|
||||||
|
/// - custA: Indicator whether `domain` is part of custom list `A`
|
||||||
|
/// - custB: Indicator whether `domain` is part of custom list `B`
|
||||||
|
func postOrIgnore(_ domain: String, blck: Bool, custA: Bool, custB: Bool) {
|
||||||
|
if #available(iOS 10.0, *), enabled {
|
||||||
|
let onAnyList = listBlocked && blck || listCustomA && custA || listCustomB && custB || listElse
|
||||||
|
if invertedMode ? !onAnyList : onAnyList {
|
||||||
|
PushNotification.scheduleConnectionAlert(domain, sound: tone as! UNNotificationSound?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,11 +5,11 @@ enum NotificationRequestState {
|
|||||||
@available(iOS 10.0, *)
|
@available(iOS 10.0, *)
|
||||||
init(_ from: UNAuthorizationStatus) {
|
init(_ from: UNAuthorizationStatus) {
|
||||||
switch from {
|
switch from {
|
||||||
case .notDetermined: self = .NotDetermined
|
|
||||||
case .denied: self = .Denied
|
case .denied: self = .Denied
|
||||||
case .authorized: self = .Authorized
|
case .authorized: self = .Authorized
|
||||||
case .provisional: self = .Provisional
|
case .provisional: self = .Provisional
|
||||||
@unknown default: fatalError()
|
case .notDetermined: fallthrough
|
||||||
|
@unknown default: self = .NotDetermined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user