mirror of
https://github.com/kkebo/DNSecure.git
synced 2026-03-11 08:54:36 +00:00
Make the server settings customizable
This commit is contained in:
parent
e640e3da14
commit
539ad6a3bb
8 changed files with 515 additions and 53 deletions
|
|
@ -7,6 +7,8 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
890B80D5251DC3A20046BAA0 /* DetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890B80D4251DC3A20046BAA0 /* DetailView.swift */; };
|
||||
890B80DF251DC6B50046BAA0 /* Presets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890B80DE251DC6B50046BAA0 /* Presets.swift */; };
|
||||
8940023C24ACBD2700EBE74B /* CustomDNSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8940023B24ACBD2700EBE74B /* CustomDNSApp.swift */; };
|
||||
8940023E24ACBD2700EBE74B /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8940023D24ACBD2700EBE74B /* ContentView.swift */; };
|
||||
8940024024ACBD2800EBE74B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8940023F24ACBD2800EBE74B /* Assets.xcassets */; };
|
||||
|
|
@ -14,6 +16,8 @@
|
|||
8940024E24ACBD2800EBE74B /* CustomDNSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8940024D24ACBD2800EBE74B /* CustomDNSTests.swift */; };
|
||||
8940025924ACBD2800EBE74B /* CustomDNSUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8940025824ACBD2800EBE74B /* CustomDNSUITests.swift */; };
|
||||
8940026924ACBE4900EBE74B /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8940026824ACBE4900EBE74B /* NetworkExtension.framework */; };
|
||||
8963FDFB251DF1BC00E3DFE7 /* BundleExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8963FDFA251DF1BC00E3DFE7 /* BundleExtensions.swift */; };
|
||||
8986CDCF251D9B3400D947CD /* Resolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8986CDCE251D9B3400D947CD /* Resolver.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
|
@ -34,6 +38,8 @@
|
|||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
890B80D4251DC3A20046BAA0 /* DetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailView.swift; sourceTree = "<group>"; };
|
||||
890B80DE251DC6B50046BAA0 /* Presets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Presets.swift; sourceTree = "<group>"; };
|
||||
8924EDF324C9CDF1004AF871 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||
8940023824ACBD2700EBE74B /* CustomDNS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CustomDNS.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8940023B24ACBD2700EBE74B /* CustomDNSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomDNSApp.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -49,6 +55,8 @@
|
|||
8940025A24ACBD2800EBE74B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
8940026624ACBE4900EBE74B /* CustomDNS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CustomDNS.entitlements; sourceTree = "<group>"; };
|
||||
8940026824ACBE4900EBE74B /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; };
|
||||
8963FDFA251DF1BC00E3DFE7 /* BundleExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleExtensions.swift; sourceTree = "<group>"; };
|
||||
8986CDCE251D9B3400D947CD /* Resolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Resolver.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
|
@ -105,9 +113,13 @@
|
|||
8940026624ACBE4900EBE74B /* CustomDNS.entitlements */,
|
||||
8940023B24ACBD2700EBE74B /* CustomDNSApp.swift */,
|
||||
8940023D24ACBD2700EBE74B /* ContentView.swift */,
|
||||
8963FDFA251DF1BC00E3DFE7 /* BundleExtensions.swift */,
|
||||
890B80DE251DC6B50046BAA0 /* Presets.swift */,
|
||||
890B80D4251DC3A20046BAA0 /* DetailView.swift */,
|
||||
8940023F24ACBD2800EBE74B /* Assets.xcassets */,
|
||||
8940024424ACBD2800EBE74B /* Info.plist */,
|
||||
8940024124ACBD2800EBE74B /* Preview Content */,
|
||||
8986CDCE251D9B3400D947CD /* Resolver.swift */,
|
||||
);
|
||||
path = CustomDNS;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -275,8 +287,12 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8986CDCF251D9B3400D947CD /* Resolver.swift in Sources */,
|
||||
890B80D5251DC3A20046BAA0 /* DetailView.swift in Sources */,
|
||||
8940023E24ACBD2700EBE74B /* ContentView.swift in Sources */,
|
||||
890B80DF251DC6B50046BAA0 /* Presets.swift in Sources */,
|
||||
8940023C24ACBD2700EBE74B /* CustomDNSApp.swift in Sources */,
|
||||
8963FDFB251DF1BC00E3DFE7 /* BundleExtensions.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
@ -446,9 +462,9 @@
|
|||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = xyz.kebo.CustomDNS;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
|
@ -470,9 +486,9 @@
|
|||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = xyz.kebo.CustomDNS;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
|
|
|||
15
CustomDNS/BundleExtensions.swift
Normal file
15
CustomDNS/BundleExtensions.swift
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// BundleExtensions.swift
|
||||
// CustomDNS
|
||||
//
|
||||
// Created by Kenta Kubo on 9/25/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Bundle {
|
||||
var displayName: String? {
|
||||
self.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String
|
||||
?? self.object(forInfoDictionaryKey: "CFBundleName") as? String
|
||||
}
|
||||
}
|
||||
|
|
@ -5,38 +5,139 @@
|
|||
// Created by Kenta Kubo on 7/1/20.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import NetworkExtension
|
||||
import SwiftUI
|
||||
|
||||
struct ContentView {
|
||||
@AppStorage("servers") var servers = Presets.servers
|
||||
@AppStorage("usedID") var usedID: String?
|
||||
@State var isEnabled = false
|
||||
var cancellable: Cancellable?
|
||||
|
||||
init() {
|
||||
self.cancellable = Future<Bool, Error> { resolve in
|
||||
let manager = NEDNSSettingsManager.shared()
|
||||
manager.loadFromPreferences {
|
||||
if let err = $0 {
|
||||
resolve(.failure(err))
|
||||
} else {
|
||||
resolve(.success(manager.isEnabled))
|
||||
}
|
||||
func addNewDoTServer() {
|
||||
self.servers.append(
|
||||
.init(
|
||||
name: "New",
|
||||
configuration: .dnsOverTLS(DoTConfiguration())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
func addNewDoHServer() {
|
||||
self.servers.append(
|
||||
.init(
|
||||
name: "New",
|
||||
configuration: .dnsOverHTTPS(DoHConfiguration())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
func updateStatus() {
|
||||
let manager = NEDNSSettingsManager.shared()
|
||||
manager.loadFromPreferences {
|
||||
if let err = $0 {
|
||||
print("\(err.localizedDescription)")
|
||||
} else {
|
||||
self.isEnabled = manager.isEnabled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func syncSettings() {
|
||||
let manager = NEDNSSettingsManager.shared()
|
||||
manager.loadFromPreferences { loadError in
|
||||
if let loadError = loadError {
|
||||
print("\(loadError.localizedDescription)")
|
||||
return
|
||||
}
|
||||
manager.dnsSettings = self.usedID
|
||||
.flatMap(UUID.init)
|
||||
.flatMap(self.servers.find)
|
||||
.map(\.configuration)
|
||||
.map { $0.toDNSSettings() }
|
||||
manager.saveToPreferences { saveError in
|
||||
if let saveError = saveError {
|
||||
print("\(saveError.localizedDescription)")
|
||||
return
|
||||
}
|
||||
print("saved")
|
||||
}
|
||||
}
|
||||
.mapError { fatalError("\($0.localizedDescription)") }
|
||||
.assign(to: \.isEnabled, on: self)
|
||||
}
|
||||
}
|
||||
|
||||
extension ContentView: View {
|
||||
@ViewBuilder var body: some View {
|
||||
if self.isEnabled {
|
||||
Text("Enabled")
|
||||
.foregroundColor(.green)
|
||||
} else {
|
||||
Text("Disabled")
|
||||
.foregroundColor(.secondary)
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
List {
|
||||
Section(header: Text("Servers")) {
|
||||
ForEach(0..<self.servers.count, id: \.self) { i in
|
||||
NavigationLink(
|
||||
destination: DetailView(
|
||||
server: .init(
|
||||
get: { self.servers[i] },
|
||||
set: { self.servers[i] = $0 }
|
||||
),
|
||||
isOn: .init(
|
||||
get: {
|
||||
self.usedID == self.servers[i].id.uuidString
|
||||
},
|
||||
set: {
|
||||
if $0 {
|
||||
self.usedID = self.servers[i].id.uuidString
|
||||
} else {
|
||||
self.usedID = nil
|
||||
}
|
||||
self.syncSettings()
|
||||
}
|
||||
)
|
||||
)
|
||||
) {
|
||||
VStack(alignment: .leading) {
|
||||
Text(self.servers[i].name)
|
||||
Text(self.servers[i].configuration.description)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
if self.usedID == self.servers[i].id.uuidString {
|
||||
Spacer()
|
||||
Image(systemName: "checkmark")
|
||||
}
|
||||
}
|
||||
}
|
||||
.onDelete { indexSet in
|
||||
self.servers.remove(atOffsets: indexSet)
|
||||
}
|
||||
.onMove { src, dst in
|
||||
self.servers.move(fromOffsets: src, toOffset: dst)
|
||||
}
|
||||
}
|
||||
}
|
||||
.listStyle(SidebarListStyle())
|
||||
.navigationTitle(Bundle.main.displayName!)
|
||||
.toolbar {
|
||||
ToolbarItemGroup(placement: .navigationBarTrailing) {
|
||||
Menu {
|
||||
Button("DNS-over-TLS", action: self.addNewDoTServer)
|
||||
Button("DNS-over-HTTPS", action: self.addNewDoHServer)
|
||||
} label: {
|
||||
Image(systemName: "plus")
|
||||
}
|
||||
EditButton()
|
||||
}
|
||||
ToolbarItem(placement: .status) {
|
||||
VStack {
|
||||
HStack {
|
||||
Circle()
|
||||
.frame(width: 10, height: 10)
|
||||
.foregroundColor(self.isEnabled ? .green : .secondary)
|
||||
Text(self.isEnabled ? "Active" : "Inactive")
|
||||
}
|
||||
.onAppear(perform: self.updateStatus)
|
||||
if !self.isEnabled {
|
||||
Link("Activate", destination: URL(string: "App-prefs:root=General&path=Network/VPN")!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,37 +5,10 @@
|
|||
// Created by Kenta Kubo on 7/1/20.
|
||||
//
|
||||
|
||||
import NetworkExtension
|
||||
import SwiftUI
|
||||
|
||||
@main
|
||||
struct CustomDNSApp {
|
||||
init() {
|
||||
// Create a DNS configuration
|
||||
let manager = NEDNSSettingsManager.shared()
|
||||
manager.loadFromPreferences { loadError in
|
||||
if let loadError = loadError {
|
||||
print(loadError)
|
||||
return
|
||||
}
|
||||
let dotSettings = NEDNSOverTLSSettings(servers: [
|
||||
"1.1.1.1",
|
||||
"1.0.0.1",
|
||||
"2606:4700:4700::64",
|
||||
"2606:4700:4700::6400",
|
||||
])
|
||||
dotSettings.serverName = "cloudflare-dns.com"
|
||||
manager.dnsSettings = dotSettings
|
||||
manager.saveToPreferences { saveError in
|
||||
if let saveError = saveError {
|
||||
print(saveError)
|
||||
return
|
||||
}
|
||||
print("saved")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
struct CustomDNSApp {}
|
||||
|
||||
extension CustomDNSApp: App {
|
||||
var body: some Scene {
|
||||
|
|
|
|||
155
CustomDNS/DetailView.swift
Normal file
155
CustomDNS/DetailView.swift
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
//
|
||||
// DetailView.swift
|
||||
// CustomDNS
|
||||
//
|
||||
// Created by Kenta Kubo on 9/25/20.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct DetailView {
|
||||
@Binding var server: Resolver
|
||||
@Binding var isOn: Bool
|
||||
}
|
||||
|
||||
extension DetailView: View {
|
||||
var body: some View {
|
||||
Form {
|
||||
Section {
|
||||
Toggle("Use This Server", isOn: self.$isOn)
|
||||
}
|
||||
Section {
|
||||
HStack {
|
||||
Text("Name")
|
||||
TextField("Name", text: self.$server.name)
|
||||
.multilineTextAlignment(.trailing)
|
||||
}
|
||||
}
|
||||
switch self.server.configuration {
|
||||
case var .dnsOverTLS(configuration):
|
||||
Section(
|
||||
header: Text("Servers"),
|
||||
footer: Text("The DNS server IP addresses.")
|
||||
) {
|
||||
ForEach(0..<configuration.servers.count, id: \.self) { i in
|
||||
TextField(
|
||||
"IP address",
|
||||
text: .init(
|
||||
get: { configuration.servers[i] },
|
||||
set: { configuration.servers[i] = $0 }
|
||||
),
|
||||
onCommit: {
|
||||
self.server.configuration = .dnsOverTLS(configuration)
|
||||
}
|
||||
)
|
||||
.textContentType(.URL)
|
||||
.keyboardType(.asciiCapableNumberPad)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
}
|
||||
Button("Add New Server") {
|
||||
configuration.servers.append("")
|
||||
self.server.configuration = .dnsOverTLS(configuration)
|
||||
}
|
||||
}
|
||||
Section(
|
||||
header: Text("DNS-over-TLS Settings"),
|
||||
footer: Text("The TLS name of a DNS-over-TLS server.")
|
||||
) {
|
||||
HStack {
|
||||
Text("Server Name")
|
||||
Spacer()
|
||||
TextField(
|
||||
"Server Name",
|
||||
text: .init(
|
||||
get: {
|
||||
configuration.serverName ?? ""
|
||||
},
|
||||
set: {
|
||||
configuration.serverName = $0
|
||||
}
|
||||
),
|
||||
onCommit: {
|
||||
self.server.configuration = .dnsOverTLS(configuration)
|
||||
}
|
||||
)
|
||||
.multilineTextAlignment(.trailing)
|
||||
.textContentType(.URL)
|
||||
.keyboardType(.URL)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
}
|
||||
}
|
||||
case var .dnsOverHTTPS(configuration):
|
||||
Section(
|
||||
header: Text("Servers"),
|
||||
footer: Text("The DNS server IP addresses.")
|
||||
) {
|
||||
ForEach(0..<configuration.servers.count, id: \.self) { i in
|
||||
TextField(
|
||||
"IP address",
|
||||
text: .init(
|
||||
get: { configuration.servers[i] },
|
||||
set: { configuration.servers[i] = $0 }
|
||||
),
|
||||
onCommit: {
|
||||
self.server.configuration = .dnsOverHTTPS(configuration)
|
||||
}
|
||||
)
|
||||
.textContentType(.URL)
|
||||
.keyboardType(.asciiCapableNumberPad)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
}
|
||||
Button("Add New Server") {
|
||||
configuration.servers.append("")
|
||||
self.server.configuration = .dnsOverHTTPS(configuration)
|
||||
}
|
||||
}
|
||||
Section(
|
||||
header: Text("DNS over HTTPS Settings"),
|
||||
footer: Text("The URL of a DNS-over-HTTPS server.")
|
||||
) {
|
||||
HStack {
|
||||
Text("Server URL")
|
||||
Spacer()
|
||||
TextField(
|
||||
"Server URL",
|
||||
text: .init(
|
||||
get: {
|
||||
configuration.serverURL?.absoluteString ?? ""
|
||||
},
|
||||
set: {
|
||||
configuration.serverURL = URL(string: $0)
|
||||
}
|
||||
),
|
||||
onCommit: {
|
||||
self.server.configuration = .dnsOverHTTPS(configuration)
|
||||
}
|
||||
)
|
||||
.multilineTextAlignment(.trailing)
|
||||
.textContentType(.URL)
|
||||
.keyboardType(.URL)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle(self.server.name)
|
||||
}
|
||||
}
|
||||
|
||||
struct DetailView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
DetailView(
|
||||
server: .constant(
|
||||
.init(
|
||||
name: "My Server",
|
||||
configuration: .dnsOverTLS(DoTConfiguration())
|
||||
)
|
||||
),
|
||||
isOn: .constant(true)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
<true/>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
|
|
|
|||
69
CustomDNS/Presets.swift
Normal file
69
CustomDNS/Presets.swift
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
//
|
||||
// Presets.swift
|
||||
// CustomDNS
|
||||
//
|
||||
// Created by Kenta Kubo on 9/25/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum Presets {
|
||||
static let servers: Resolvers = [
|
||||
.init(
|
||||
name: "Google Public DNS",
|
||||
configuration: .dnsOverTLS(
|
||||
DoTConfiguration(
|
||||
servers: [
|
||||
"8.8.8.8",
|
||||
"8.8.4.4",
|
||||
"2001:4860:4860::8888",
|
||||
"2001:4860:4860::8844",
|
||||
],
|
||||
serverName: "dns.google"
|
||||
)
|
||||
)
|
||||
),
|
||||
.init(
|
||||
name: "Google Public DNS",
|
||||
configuration: .dnsOverHTTPS(
|
||||
DoHConfiguration(
|
||||
servers: [
|
||||
"8.8.8.8",
|
||||
"8.8.4.4",
|
||||
"2001:4860:4860::8888",
|
||||
"2001:4860:4860::8844",
|
||||
],
|
||||
serverURL: URL(string: "https://dns.google/dns-query")
|
||||
)
|
||||
)
|
||||
),
|
||||
.init(
|
||||
name: "1.1.1.1",
|
||||
configuration: .dnsOverTLS(
|
||||
DoTConfiguration(
|
||||
servers: [
|
||||
"1.1.1.1",
|
||||
"1.0.0.1",
|
||||
"2606:4700:4700::64",
|
||||
"2606:4700:4700::6400",
|
||||
],
|
||||
serverName: "cloudflare-dns.com"
|
||||
)
|
||||
)
|
||||
),
|
||||
.init(
|
||||
name: "1.1.1.1",
|
||||
configuration: .dnsOverHTTPS(
|
||||
DoHConfiguration(
|
||||
servers: [
|
||||
"1.1.1.1",
|
||||
"1.0.0.1",
|
||||
"2606:4700:4700::64",
|
||||
"2606:4700:4700::6400",
|
||||
],
|
||||
serverURL: URL(string: "https://cloudflare-dns.com/dns-query")
|
||||
)
|
||||
)
|
||||
),
|
||||
]
|
||||
}
|
||||
133
CustomDNS/Resolver.swift
Normal file
133
CustomDNS/Resolver.swift
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
//
|
||||
// Resolver.swift
|
||||
// CustomDNS
|
||||
//
|
||||
// Created by Kenta Kubo on 9/25/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import NetworkExtension
|
||||
|
||||
struct DoTConfiguration {
|
||||
var servers: [String] = []
|
||||
var serverName: String? = nil
|
||||
|
||||
func toDNSSettings() -> NEDNSOverTLSSettings {
|
||||
let settings = NEDNSOverTLSSettings(servers: self.servers)
|
||||
settings.serverName = self.serverName
|
||||
return settings
|
||||
}
|
||||
}
|
||||
|
||||
extension DoTConfiguration: Codable {}
|
||||
|
||||
struct DoHConfiguration {
|
||||
var servers: [String] = []
|
||||
var serverURL: URL? = nil
|
||||
|
||||
func toDNSSettings() -> NEDNSOverHTTPSSettings {
|
||||
let settings = NEDNSOverHTTPSSettings(servers: self.servers)
|
||||
settings.serverURL = self.serverURL
|
||||
return settings
|
||||
}
|
||||
}
|
||||
|
||||
extension DoHConfiguration: Codable {}
|
||||
|
||||
enum Configuration {
|
||||
case dnsOverTLS(DoTConfiguration)
|
||||
case dnsOverHTTPS(DoHConfiguration)
|
||||
|
||||
func toDNSSettings() -> NEDNSSettings {
|
||||
switch self {
|
||||
case let .dnsOverTLS(configuration):
|
||||
return configuration.toDNSSettings()
|
||||
case let .dnsOverHTTPS(configuration):
|
||||
return configuration.toDNSSettings()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Configuration: Codable {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case base, dotConfiguration, dohConfiguration
|
||||
}
|
||||
|
||||
enum Base: String, Codable {
|
||||
case dnsOverTLS, dnsOverHTTPS
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: Self.CodingKeys.self)
|
||||
let base = try container.decode(Self.Base.self, forKey: .base)
|
||||
|
||||
switch base {
|
||||
case .dnsOverTLS:
|
||||
let configuration = try container.decode(DoTConfiguration.self, forKey: .dotConfiguration)
|
||||
self = .dnsOverTLS(configuration)
|
||||
case .dnsOverHTTPS:
|
||||
let configuration = try container.decode(DoHConfiguration.self, forKey: .dohConfiguration)
|
||||
self = .dnsOverHTTPS(configuration)
|
||||
}
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: Self.CodingKeys.self)
|
||||
|
||||
switch self {
|
||||
case let .dnsOverTLS(configuration):
|
||||
try container.encode(Self.Base.dnsOverTLS, forKey: .base)
|
||||
try container.encode(configuration, forKey: .dotConfiguration)
|
||||
case let .dnsOverHTTPS(configuration):
|
||||
try container.encode(Self.Base.dnsOverHTTPS, forKey: .base)
|
||||
try container.encode(configuration, forKey: .dohConfiguration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Configuration: CustomStringConvertible {
|
||||
var description: String {
|
||||
switch self {
|
||||
case .dnsOverTLS: return "DNS-over-TLS"
|
||||
case .dnsOverHTTPS: return "DNS-over-HTTPS"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Resolver {
|
||||
var id = UUID()
|
||||
var name: String
|
||||
var configuration: Configuration
|
||||
}
|
||||
|
||||
extension Resolver: Identifiable {}
|
||||
|
||||
extension Resolver: Codable {}
|
||||
|
||||
typealias Resolvers = [Resolver]
|
||||
|
||||
extension Resolvers {
|
||||
func find(by id: UUID) -> Self.Element? {
|
||||
self.first { $0.id == id }
|
||||
}
|
||||
}
|
||||
|
||||
extension Resolvers: RawRepresentable {
|
||||
public init?(rawValue: String) {
|
||||
guard let data = rawValue.data(using: .utf8),
|
||||
let result = try? JSONDecoder().decode(Self.self, from: data)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
self = result
|
||||
}
|
||||
|
||||
public var rawValue: String {
|
||||
guard let data = try? JSONEncoder().encode(self),
|
||||
let result = String(data: data, encoding: .utf8)
|
||||
else {
|
||||
return "[]"
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue