diff --git a/dns.xcodeproj/project.pbxproj b/dns.xcodeproj/project.pbxproj index 94d3daf..1e2384a 100644 --- a/dns.xcodeproj/project.pbxproj +++ b/dns.xcodeproj/project.pbxproj @@ -8,6 +8,9 @@ /* Begin PBXFileReference section */ 069DCCFA2F8C0DCE00F1EB16 /* dns.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = dns.app; sourceTree = BUILT_PRODUCTS_DIR; }; + A06A74772F8E95410093A9E4 /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitignore; sourceTree = ""; }; + A06A74782F8E95410093A9E4 /* LICENCE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENCE; sourceTree = ""; }; + A06A74792F8E95410093A9E4 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ @@ -32,6 +35,9 @@ 069DCCF12F8C0DCD00F1EB16 = { isa = PBXGroup; children = ( + A06A74772F8E95410093A9E4 /* .gitignore */, + A06A74782F8E95410093A9E4 /* LICENCE */, + A06A74792F8E95410093A9E4 /* README.md */, 069DCCFC2F8C0DCE00F1EB16 /* dns */, 069DCCFB2F8C0DCE00F1EB16 /* Products */, ); @@ -251,6 +257,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = dns/dns.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; @@ -262,6 +269,7 @@ INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -285,6 +293,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = dns/dns.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; @@ -296,6 +305,7 @@ INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/dns/BlockedCount.swift b/dns/BlockedCount.swift index 69d7686..e18f5b5 100644 --- a/dns/BlockedCount.swift +++ b/dns/BlockedCount.swift @@ -4,7 +4,10 @@ import Foundation struct BlockedCount: View { - @State private var txtRecord: String = "..." + @EnvironmentObject + private var viewModel: ViewModel + + @State private var txtRecord: String = "…" private static let startIndex = 44 @@ -44,33 +47,29 @@ struct BlockedCount: View { } func fetchTXTRecord() { - let dohURL = URL(string: "https://dns.sr2.uk/dns-query?dns=DoQBAAABAAAAAAAABXN0YXRzB2ludmFsaWQAABAAAQ")! + let dohURL = URL(string: "https://\(viewModel.blocklist.server)/dns-query?dns=DoQBAAABAAAAAAAABXN0YXRzB2ludmFsaWQAABAAAQ")! let request = URLRequest(url: dohURL) - URLSession.shared.dataTask(with: request) { data, response, error in - DispatchQueue.main.async { - if error != nil { - txtRecord = "Error" - return - } + Task { + do { + let (data, _) = try await URLSession.shared.data(for: request) - guard let data = data else { - txtRecord = "Error" - return + if let count = parseResponse(data: data) { + txtRecord = count } - - guard let count = parseResponse(data: data) else { + else { txtRecord = "Error" - return } - - txtRecord = count } - }.resume() + catch { + txtRecord = "Error" + } + } } } #Preview { BlockedCount() + .environmentObject(ViewModel()) } diff --git a/dns/BlocklistOption.swift b/dns/BlocklistOption.swift new file mode 100644 index 0000000..452b679 --- /dev/null +++ b/dns/BlocklistOption.swift @@ -0,0 +1,69 @@ +// +// BlocklistOption.swift +// dns +// +// Created by Benjamin Erhart on 14.04.26. +// + +import Foundation + +enum BlocklistOption: String, CaseIterable, Identifiable { + case secure = "Secure" + case securePlusAdblock = "Secure + Adblock" + + var id: String { rawValue } + + var enabled: Bool { + switch self { + case .secure: + return true + case .securePlusAdblock: + return true //false + } + } + + var description: String { + switch self { + case .secure: + return "Malware and phishing protection" + case .securePlusAdblock: + return "Security plus ad and tracker blocking" + } + } + + var icon: String { + switch self { + case .secure: + return "shield" + case .securePlusAdblock: + return "shield.righthalf.filled" + } + } + + var server: String { + switch self { + case .secure: + return "dns.sr2.uk" + case .securePlusAdblock: + return "dnsplus.sr2.uk" + } + } + + var ipv4: String { + switch self { + case .secure: + return "144.76.160.194" + case .securePlusAdblock: + return "192.0.2.1" + } + } + + var ipv6: String { + switch self { + case .secure: + return "2a01:4f8:2210:23ea::4" + case .securePlusAdblock: + return "2001:db8::1" + } + } +} diff --git a/dns/DnsApp.swift b/dns/DnsApp.swift new file mode 100644 index 0000000..acd5119 --- /dev/null +++ b/dns/DnsApp.swift @@ -0,0 +1,16 @@ + +import SwiftUI + +@main +struct DnsApp: App { + + @StateObject + var viewModel = ViewModel() + + var body: some Scene { + WindowGroup { + HomeView() + .environmentObject(viewModel) + } + } +} diff --git a/dns/HomeView.swift b/dns/HomeView.swift index 0bdd24a..d95d302 100644 --- a/dns/HomeView.swift +++ b/dns/HomeView.swift @@ -1,67 +1,6 @@ import SwiftUI -enum BlocklistOption: String, CaseIterable, Identifiable { - case secure = "Secure" - case securePlusAdblock = "Secure + Adblock" - - var id: String { rawValue } - - var enabled: Bool { - switch self { - case .secure: - return true - case .securePlusAdblock: - return false - } - } - - var description: String { - switch self { - case .secure: - return "Malware and phishing protection" - case .securePlusAdblock: - return "Security plus ad and tracker blocking" - } - } - - var icon: String { - switch self { - case .secure: - return "shield" - case .securePlusAdblock: - return "shield.righthalf.filled" - } - } - - var server: String { - switch self { - case .secure: - return "dns.sr2.uk" - case .securePlusAdblock: - return "dnsplus.sr2.uk" - } - } - - var ipv4: String { - switch self { - case .secure: - return "144.76.160.194" - case .securePlusAdblock: - return "192.0.2.1" - } - } - - var ipv6: String { - switch self { - case .secure: - return "2a01:4f8:2210:23ea::4" - case .securePlusAdblock: - return "2001:db8::1" - } - } -} - enum ServiceStatus { case pending case operational @@ -96,8 +35,11 @@ enum ServiceStatus { } struct HomeView: View { + + @EnvironmentObject + private var viewModel: ViewModel + @State private var isEnabled = false - @State private var selectedBlocklist: BlocklistOption = .secure @State private var serviceStatus: ServiceStatus = .operational private let falsePositiveURL = URL(string: "https://www.sr2.uk/contact")! @@ -135,13 +77,13 @@ struct HomeView: View { ForEach(BlocklistOption.allCases) { option in BlocklistRow( option: option, - isSelected: selectedBlocklist == option + isSelected: viewModel.blocklist == option ) .contentShape(Rectangle()) .onTapGesture { guard option.enabled else { return } withAnimation(.spring(duration: 0.3)) { - selectedBlocklist = option + viewModel.blocklist = option } } .opacity(option.enabled ? 1 : 0.6) @@ -166,7 +108,7 @@ struct HomeView: View { HStack { Label("Server", systemImage: "server.rack") Spacer() - Text(selectedBlocklist.server) + Text(viewModel.blocklist.server) .foregroundStyle(.secondary) .font(.system(.body, design: .monospaced)) } @@ -174,7 +116,7 @@ struct HomeView: View { HStack { Label("IPv4", systemImage: "globe") Spacer() - Text(selectedBlocklist.ipv4) + Text(viewModel.blocklist.ipv4) .foregroundStyle(.secondary) .font(.system(.body, design: .monospaced)) } @@ -182,7 +124,7 @@ struct HomeView: View { HStack { Label("IPv6", systemImage: "globe") Spacer() - Text(selectedBlocklist.ipv6) + Text(viewModel.blocklist.ipv6) .foregroundStyle(.secondary) .font(.system(.body, design: .monospaced)) } @@ -278,4 +220,5 @@ struct HomeView: View { #Preview { HomeView() + .environmentObject(ViewModel()) } diff --git a/dns/ViewModel.swift b/dns/ViewModel.swift new file mode 100644 index 0000000..4c82680 --- /dev/null +++ b/dns/ViewModel.swift @@ -0,0 +1,16 @@ +// +// ViewModel.swift +// dns +// +// Created by Benjamin Erhart on 14.04.26. +// + +import Foundation +import Combine + +class ViewModel: NSObject, ObservableObject { + + @Published + var blocklist: BlocklistOption = .secure + +} diff --git a/dns/dns.entitlements b/dns/dns.entitlements new file mode 100644 index 0000000..8a3b751 --- /dev/null +++ b/dns/dns.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.developer.networking.networkextension + + dns-settings + + + diff --git a/dns/dnsApp.swift b/dns/dnsApp.swift deleted file mode 100644 index 165bec1..0000000 --- a/dns/dnsApp.swift +++ /dev/null @@ -1,11 +0,0 @@ - -import SwiftUI - -@main -struct dnsApp: App { - var body: some Scene { - WindowGroup { - HomeView() - } - } -}