Compare commits

..

5 commits

8 changed files with 147 additions and 95 deletions

View file

@ -8,6 +8,9 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
069DCCFA2F8C0DCE00F1EB16 /* dns.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = dns.app; sourceTree = BUILT_PRODUCTS_DIR; }; 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 = "<group>"; };
A06A74782F8E95410093A9E4 /* LICENCE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENCE; sourceTree = "<group>"; };
A06A74792F8E95410093A9E4 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFileSystemSynchronizedRootGroup section */
@ -32,6 +35,9 @@
069DCCF12F8C0DCD00F1EB16 = { 069DCCF12F8C0DCD00F1EB16 = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
A06A74772F8E95410093A9E4 /* .gitignore */,
A06A74782F8E95410093A9E4 /* LICENCE */,
A06A74792F8E95410093A9E4 /* README.md */,
069DCCFC2F8C0DCE00F1EB16 /* dns */, 069DCCFC2F8C0DCE00F1EB16 /* dns */,
069DCCFB2F8C0DCE00F1EB16 /* Products */, 069DCCFB2F8C0DCE00F1EB16 /* Products */,
); );
@ -251,6 +257,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = dns/dns.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
@ -262,6 +269,7 @@
INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -285,6 +293,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = dns/dns.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
@ -296,6 +305,7 @@
INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",

View file

@ -4,7 +4,10 @@ import Foundation
struct BlockedCount: View { struct BlockedCount: View {
@State private var txtRecord: String = "..." @EnvironmentObject
private var viewModel: ViewModel
@State private var txtRecord: String = ""
private static let startIndex = 44 private static let startIndex = 44
@ -44,33 +47,29 @@ struct BlockedCount: View {
} }
func fetchTXTRecord() { 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) let request = URLRequest(url: dohURL)
URLSession.shared.dataTask(with: request) { data, response, error in Task {
DispatchQueue.main.async { do {
if error != nil { let (data, _) = try await URLSession.shared.data(for: request)
txtRecord = "Error"
return
}
guard let data = data else {
txtRecord = "Error"
return
}
guard let count = parseResponse(data: data) else {
txtRecord = "Error"
return
}
if let count = parseResponse(data: data) {
txtRecord = count txtRecord = count
} }
}.resume() else {
txtRecord = "Error"
}
}
catch {
txtRecord = "Error"
}
}
} }
} }
#Preview { #Preview {
BlockedCount() BlockedCount()
.environmentObject(ViewModel())
} }

69
dns/BlocklistOption.swift Normal file
View file

@ -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"
}
}
}

16
dns/DnsApp.swift Normal file
View file

@ -0,0 +1,16 @@
import SwiftUI
@main
struct DnsApp: App {
@StateObject
var viewModel = ViewModel()
var body: some Scene {
WindowGroup {
HomeView()
.environmentObject(viewModel)
}
}
}

View file

@ -1,67 +1,6 @@
import SwiftUI 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 { enum ServiceStatus {
case pending case pending
case operational case operational
@ -96,8 +35,11 @@ enum ServiceStatus {
} }
struct HomeView: View { struct HomeView: View {
@EnvironmentObject
private var viewModel: ViewModel
@State private var isEnabled = false @State private var isEnabled = false
@State private var selectedBlocklist: BlocklistOption = .secure
@State private var serviceStatus: ServiceStatus = .operational @State private var serviceStatus: ServiceStatus = .operational
private let falsePositiveURL = URL(string: "https://www.sr2.uk/contact")! private let falsePositiveURL = URL(string: "https://www.sr2.uk/contact")!
@ -135,13 +77,13 @@ struct HomeView: View {
ForEach(BlocklistOption.allCases) { option in ForEach(BlocklistOption.allCases) { option in
BlocklistRow( BlocklistRow(
option: option, option: option,
isSelected: selectedBlocklist == option isSelected: viewModel.blocklist == option
) )
.contentShape(Rectangle()) .contentShape(Rectangle())
.onTapGesture { .onTapGesture {
guard option.enabled else { return } guard option.enabled else { return }
withAnimation(.spring(duration: 0.3)) { withAnimation(.spring(duration: 0.3)) {
selectedBlocklist = option viewModel.blocklist = option
} }
} }
.opacity(option.enabled ? 1 : 0.6) .opacity(option.enabled ? 1 : 0.6)
@ -166,7 +108,7 @@ struct HomeView: View {
HStack { HStack {
Label("Server", systemImage: "server.rack") Label("Server", systemImage: "server.rack")
Spacer() Spacer()
Text(selectedBlocklist.server) Text(viewModel.blocklist.server)
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
.font(.system(.body, design: .monospaced)) .font(.system(.body, design: .monospaced))
} }
@ -174,7 +116,7 @@ struct HomeView: View {
HStack { HStack {
Label("IPv4", systemImage: "globe") Label("IPv4", systemImage: "globe")
Spacer() Spacer()
Text(selectedBlocklist.ipv4) Text(viewModel.blocklist.ipv4)
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
.font(.system(.body, design: .monospaced)) .font(.system(.body, design: .monospaced))
} }
@ -182,7 +124,7 @@ struct HomeView: View {
HStack { HStack {
Label("IPv6", systemImage: "globe") Label("IPv6", systemImage: "globe")
Spacer() Spacer()
Text(selectedBlocklist.ipv6) Text(viewModel.blocklist.ipv6)
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
.font(.system(.body, design: .monospaced)) .font(.system(.body, design: .monospaced))
} }
@ -278,4 +220,5 @@ struct HomeView: View {
#Preview { #Preview {
HomeView() HomeView()
.environmentObject(ViewModel())
} }

16
dns/ViewModel.swift Normal file
View file

@ -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
}

10
dns/dns.entitlements Normal file
View file

@ -0,0 +1,10 @@
<?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>com.apple.developer.networking.networkextension</key>
<array>
<string>dns-settings</string>
</array>
</dict>
</plist>

View file

@ -1,11 +0,0 @@
import SwiftUI
@main
struct dnsApp: App {
var body: some Scene {
WindowGroup {
HomeView()
}
}
}