-
Notifications
You must be signed in to change notification settings - Fork 369
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow users to import settings by pasting JSON blobs
- Loading branch information
Jon Petersson
committed
Jan 24, 2024
1 parent
3a5ba4a
commit 0c68536
Showing
14 changed files
with
687 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// | ||
// IPOverride.swift | ||
// MullvadVPN | ||
// | ||
// Created by Jon Petersson on 2024-01-16. | ||
// Copyright © 2024 Mullvad VPN AB. All rights reserved. | ||
// | ||
|
||
import Network | ||
|
||
public struct RelayOverrides: Codable { | ||
public let overrides: [IPOverride] | ||
|
||
private enum CodingKeys: String, CodingKey { | ||
case overrides = "relay_overrides" | ||
} | ||
} | ||
|
||
public struct IPOverride: Codable, Equatable { | ||
public let hostname: String | ||
public var ipv4Address: IPv4Address? | ||
public var ipv6Address: IPv6Address? | ||
|
||
private enum CodingKeys: String, CodingKey { | ||
case hostname | ||
case ipv4Address = "ipv4_addr_in" | ||
case ipv6Address = "ipv6_addr_in" | ||
} | ||
|
||
init(hostname: String, ipv4Address: IPv4Address?, ipv6Address: IPv6Address?) throws { | ||
self.hostname = hostname | ||
self.ipv4Address = ipv4Address | ||
self.ipv6Address = ipv6Address | ||
|
||
if self.ipv4Address.isNil && self.ipv6Address.isNil { | ||
throw NSError(domain: "IPOverrideInitDomain", code: NSFormattingError) | ||
} | ||
} | ||
|
||
public init(from decoder: Decoder) throws { | ||
let container = try decoder.container(keyedBy: CodingKeys.self) | ||
|
||
self.hostname = try container.decode(String.self, forKey: .hostname) | ||
self.ipv4Address = try container.decodeIfPresent(IPv4Address.self, forKey: .ipv4Address) | ||
self.ipv6Address = try container.decodeIfPresent(IPv6Address.self, forKey: .ipv6Address) | ||
|
||
if self.ipv4Address.isNil && self.ipv6Address.isNil { | ||
throw NSError(domain: "IPOverrideInitDomain", code: NSFormattingError) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
// | ||
// IPOverrideRepository.swift | ||
// MullvadVPN | ||
// | ||
// Created by Jon Petersson on 2024-01-16. | ||
// Copyright © 2024 Mullvad VPN AB. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
public protocol IPOverrideRepositoryProtocol { | ||
func add(_ overrides: [IPOverride]) | ||
func fetchAll() -> [IPOverride] | ||
func fetchByHostname(_ hostname: String) -> IPOverride? | ||
func deleteAll() | ||
func parseData(_ data: Data) throws -> [IPOverride] | ||
} | ||
|
||
public class IPOverrideRepository: IPOverrideRepositoryProtocol { | ||
public init() {} | ||
|
||
public func add(_ overrides: [IPOverride]) { | ||
var storedOverrides = fetchAll() | ||
|
||
overrides.forEach { override in | ||
if let existingOverrideIndex = storedOverrides.firstIndex(where: { $0.hostname == override.hostname }) { | ||
var existingOverride = storedOverrides[existingOverrideIndex] | ||
|
||
if let ipv4Address = override.ipv4Address { | ||
existingOverride.ipv4Address = ipv4Address | ||
} | ||
|
||
if let ipv6Address = override.ipv6Address { | ||
existingOverride.ipv6Address = ipv6Address | ||
} | ||
|
||
storedOverrides[existingOverrideIndex] = existingOverride | ||
} else { | ||
storedOverrides.append(override) | ||
} | ||
} | ||
|
||
do { | ||
try writeIpOverrides(storedOverrides) | ||
} catch { | ||
print("Could not add override(s): \(overrides) \nError: \(error)") | ||
} | ||
} | ||
|
||
public func fetchAll() -> [IPOverride] { | ||
return (try? readIpOverrides()) ?? [] | ||
} | ||
|
||
public func fetchByHostname(_ hostname: String) -> IPOverride? { | ||
return fetchAll().first { $0.hostname == hostname } | ||
} | ||
|
||
public func deleteAll() { | ||
do { | ||
try SettingsManager.store.delete(key: .ipOverrides) | ||
} catch { | ||
print("Could not delete all overrides. \nError: \(error)") | ||
} | ||
} | ||
|
||
public func parseData(_ data: Data) throws -> [IPOverride] { | ||
let decoder = JSONDecoder() | ||
let jsonData = try decoder.decode(RelayOverrides.self, from: data) | ||
|
||
return jsonData.overrides | ||
} | ||
|
||
private func readIpOverrides() throws -> [IPOverride] { | ||
let parser = makeParser() | ||
let data = try SettingsManager.store.read(key: .ipOverrides) | ||
|
||
return try parser.parseUnversionedPayload(as: [IPOverride].self, from: data) | ||
} | ||
|
||
private func writeIpOverrides(_ overrides: [IPOverride]) throws { | ||
let parser = makeParser() | ||
let data = try parser.produceUnversionedPayload(overrides) | ||
|
||
try SettingsManager.store.write(data, for: .ipOverrides) | ||
} | ||
|
||
private func makeParser() -> SettingsParser { | ||
SettingsParser(decoder: JSONDecoder(), encoder: JSONEncoder()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.