mirror of
https://github.com/DefinedNet/mobile_nebula.git
synced 2025-02-15 16:25:26 +00:00
Silence some lints
This commit is contained in:
parent
6564a18d3d
commit
985508fd79
6 changed files with 69 additions and 55 deletions
|
@ -24,7 +24,8 @@ extension AppMessageError: LocalizedError {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PacketTunnelProvider: NEPacketTunnelProvider {
|
// FIXME: marked as unchecked Sendable to allow sending `self.pathUpdate`, but we should refactor and re-enable linting.
|
||||||
|
class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
|
||||||
private var networkMonitor: NWPathMonitor?
|
private var networkMonitor: NWPathMonitor?
|
||||||
|
|
||||||
private var site: Site?
|
private var site: Site?
|
||||||
|
@ -177,7 +178,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func pathUpdate(path: Network.NWPath) {
|
private func pathUpdate(path: Network.NWPath) {
|
||||||
let routeDescription = collectAddresses(endpoints: path.gateways)
|
let routeDescription = PacketTunnelProvider.collectAddresses(endpoints: path.gateways)
|
||||||
if routeDescription != cachedRouteDescription {
|
if routeDescription != cachedRouteDescription {
|
||||||
// Don't bother to rebind if we don't have any gateways
|
// Don't bother to rebind if we don't have any gateways
|
||||||
if routeDescription != "" {
|
if routeDescription != "" {
|
||||||
|
@ -187,7 +188,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func collectAddresses(endpoints: [Network.NWEndpoint]) -> String {
|
static private func collectAddresses(endpoints: [Network.NWEndpoint]) -> String {
|
||||||
var str: [String] = []
|
var str: [String] = []
|
||||||
endpoints.forEach{ endpoint in
|
endpoints.forEach{ endpoint in
|
||||||
switch endpoint {
|
switch endpoint {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import NetworkExtension
|
|
||||||
import MobileNebula
|
import MobileNebula
|
||||||
|
import NetworkExtension
|
||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
import os.log
|
import os.log
|
||||||
|
|
||||||
let log = Logger(subsystem: "net.defined.mobileNebula", category: "Site")
|
let log = Logger(subsystem: "net.defined.mobileNebula", category: "Site")
|
||||||
|
|
||||||
enum SiteError: Error {
|
enum SiteError: Error {
|
||||||
case nonConforming(site: [String : Any]?)
|
case nonConforming(site: [String: any Sendable]?)
|
||||||
case noCertificate
|
case noCertificate
|
||||||
case keyLoad
|
case keyLoad
|
||||||
case keySave
|
case keySave
|
||||||
|
@ -131,7 +131,7 @@ struct CertificateValidity: Codable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let statusMap: Dictionary<NEVPNStatus, Bool> = [
|
let statusMap: [NEVPNStatus: Bool] = [
|
||||||
NEVPNStatus.invalid: false,
|
NEVPNStatus.invalid: false,
|
||||||
NEVPNStatus.disconnected: false,
|
NEVPNStatus.disconnected: false,
|
||||||
NEVPNStatus.connecting: false,
|
NEVPNStatus.connecting: false,
|
||||||
|
@ -140,7 +140,7 @@ let statusMap: Dictionary<NEVPNStatus, Bool> = [
|
||||||
NEVPNStatus.disconnecting: true,
|
NEVPNStatus.disconnecting: true,
|
||||||
]
|
]
|
||||||
|
|
||||||
let statusString: Dictionary<NEVPNStatus, String> = [
|
let statusString: [NEVPNStatus: String] = [
|
||||||
NEVPNStatus.invalid: "Invalid configuration",
|
NEVPNStatus.invalid: "Invalid configuration",
|
||||||
NEVPNStatus.disconnected: "Disconnected",
|
NEVPNStatus.disconnected: "Disconnected",
|
||||||
NEVPNStatus.connecting: "Connecting...",
|
NEVPNStatus.connecting: "Connecting...",
|
||||||
|
@ -150,13 +150,14 @@ let statusString: Dictionary<NEVPNStatus, String> = [
|
||||||
]
|
]
|
||||||
|
|
||||||
// Represents a site that was pulled out of the system configuration
|
// Represents a site that was pulled out of the system configuration
|
||||||
class Site: Codable {
|
// FIXME: Make Site properly Sendable, or reconfigure things to not require sending it.
|
||||||
|
class Site: Codable, @unchecked Sendable {
|
||||||
// Stored in manager
|
// Stored in manager
|
||||||
var name: String
|
var name: String
|
||||||
var id: String
|
var id: String
|
||||||
|
|
||||||
// Stored in proto
|
// Stored in proto
|
||||||
var staticHostmap: Dictionary<String, StaticHosts>
|
var staticHostmap: [String: StaticHosts]
|
||||||
var unsafeRoutes: [UnsafeRoute]
|
var unsafeRoutes: [UnsafeRoute]
|
||||||
var cert: CertificateInfo?
|
var cert: CertificateInfo?
|
||||||
var ca: [CertificateInfo]
|
var ca: [CertificateInfo]
|
||||||
|
@ -244,18 +245,19 @@ class Site: Codable {
|
||||||
do {
|
do {
|
||||||
let rawCert = incoming.cert
|
let rawCert = incoming.cert
|
||||||
let rawDetails = MobileNebulaParseCerts(rawCert, &err)
|
let rawDetails = MobileNebulaParseCerts(rawCert, &err)
|
||||||
if (err != nil) {
|
if err != nil {
|
||||||
throw err!
|
throw err!
|
||||||
}
|
}
|
||||||
|
|
||||||
var certs: [CertificateInfo]
|
var certs: [CertificateInfo]
|
||||||
|
|
||||||
certs = try JSONDecoder().decode([CertificateInfo].self, from: rawDetails.data(using: .utf8)!)
|
certs = try JSONDecoder().decode(
|
||||||
if (certs.count == 0) {
|
[CertificateInfo].self, from: rawDetails.data(using: .utf8)!)
|
||||||
|
if certs.count == 0 {
|
||||||
throw SiteError.noCertificate
|
throw SiteError.noCertificate
|
||||||
}
|
}
|
||||||
cert = certs[0]
|
cert = certs[0]
|
||||||
if (!cert!.validity.valid) {
|
if !cert!.validity.valid {
|
||||||
errors.append("Certificate is invalid: \(cert!.validity.reason)")
|
errors.append("Certificate is invalid: \(cert!.validity.reason)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,25 +268,27 @@ class Site: Codable {
|
||||||
do {
|
do {
|
||||||
let rawCa = incoming.ca
|
let rawCa = incoming.ca
|
||||||
let rawCaDetails = MobileNebulaParseCerts(rawCa, &err)
|
let rawCaDetails = MobileNebulaParseCerts(rawCa, &err)
|
||||||
if (err != nil) {
|
if err != nil {
|
||||||
throw err!
|
throw err!
|
||||||
}
|
}
|
||||||
ca = try JSONDecoder().decode([CertificateInfo].self, from: rawCaDetails.data(using: .utf8)!)
|
ca = try JSONDecoder().decode(
|
||||||
|
[CertificateInfo].self, from: rawCaDetails.data(using: .utf8)!)
|
||||||
|
|
||||||
var hasErrors = false
|
var hasErrors = false
|
||||||
ca.forEach { cert in
|
ca.forEach { cert in
|
||||||
if (!cert.validity.valid) {
|
if !cert.validity.valid {
|
||||||
hasErrors = true
|
hasErrors = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasErrors && !managed) {
|
if hasErrors && !managed {
|
||||||
errors.append("There are issues with 1 or more ca certificates")
|
errors.append("There are issues with 1 or more ca certificates")
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
ca = []
|
ca = []
|
||||||
errors.append("Error while loading certificate authorities: \(error.localizedDescription)")
|
errors.append(
|
||||||
|
"Error while loading certificate authorities: \(error.localizedDescription)")
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -294,11 +298,11 @@ class Site: Codable {
|
||||||
errors.append("Unable to create the site directory: \(error.localizedDescription)")
|
errors.append("Unable to create the site directory: \(error.localizedDescription)")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (managed && (try? getDNCredentials())?.invalid != false) {
|
if managed && (try? getDNCredentials())?.invalid != false {
|
||||||
errors.append("Unable to fetch managed updates - please re-enroll the device")
|
errors.append("Unable to fetch managed updates - please re-enroll the device")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errors.isEmpty) {
|
if errors.isEmpty {
|
||||||
do {
|
do {
|
||||||
let encoder = JSONEncoder()
|
let encoder = JSONEncoder()
|
||||||
let rawConfig = try encoder.encode(incoming)
|
let rawConfig = try encoder.encode(incoming)
|
||||||
|
@ -307,7 +311,7 @@ class Site: Codable {
|
||||||
var err: NSError?
|
var err: NSError?
|
||||||
|
|
||||||
MobileNebulaTestConfig(strConfig, key, &err)
|
MobileNebulaTestConfig(strConfig, key, &err)
|
||||||
if (err != nil) {
|
if err != nil {
|
||||||
throw err!
|
throw err!
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -327,7 +331,7 @@ class Site: Codable {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDNCredentials() throws -> DNCredentials {
|
func getDNCredentials() throws -> DNCredentials {
|
||||||
if (!managed) {
|
if !managed {
|
||||||
throw SiteError.unmanagedGetCredentials
|
throw SiteError.unmanagedGetCredentials
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,7 +348,7 @@ class Site: Codable {
|
||||||
let creds = try getDNCredentials()
|
let creds = try getDNCredentials()
|
||||||
creds.invalid = true
|
creds.invalid = true
|
||||||
|
|
||||||
if (!(try creds.save(siteID: self.id))) {
|
if !(try creds.save(siteID: self.id)) {
|
||||||
throw SiteError.dnCredentialLoad
|
throw SiteError.dnCredentialLoad
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -353,7 +357,7 @@ class Site: Codable {
|
||||||
let creds = try getDNCredentials()
|
let creds = try getDNCredentials()
|
||||||
creds.invalid = false
|
creds.invalid = false
|
||||||
|
|
||||||
if (!(try creds.save(siteID: self.id))) {
|
if !(try creds.save(siteID: self.id)) {
|
||||||
throw SiteError.dnCredentialSave
|
throw SiteError.dnCredentialSave
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -426,10 +430,11 @@ class DNCredentials: Codable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This class represents a site coming in from flutter, meant only to be saved and re-loaded as a proper Site
|
// This class represents a site coming in from flutter, meant only to be saved and re-loaded as a proper Site
|
||||||
struct IncomingSite: Codable {
|
// FIXME: Make Site properly Sendable, or reconfigure things to not require sending it.
|
||||||
|
struct IncomingSite: Codable, @unchecked Sendable {
|
||||||
var name: String
|
var name: String
|
||||||
var id: String
|
var id: String
|
||||||
var staticHostmap: Dictionary<String, StaticHosts>
|
var staticHostmap: [String: StaticHosts]
|
||||||
var unsafeRoutes: [UnsafeRoute]?
|
var unsafeRoutes: [UnsafeRoute]?
|
||||||
var cert: String?
|
var cert: String?
|
||||||
var ca: String?
|
var ca: String?
|
||||||
|
@ -456,7 +461,10 @@ struct IncomingSite: Codable {
|
||||||
return try encoder.encode(config)
|
return try encoder.encode(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
func save(manager: NETunnelProviderManager?, saveToManager: Bool = true, callback: @escaping ((any Error)?) -> ()) {
|
func save(
|
||||||
|
manager: NETunnelProviderManager?, saveToManager: Bool = true,
|
||||||
|
callback: @escaping ((any Error)?) -> Void
|
||||||
|
) {
|
||||||
let configPath: URL
|
let configPath: URL
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -469,15 +477,17 @@ struct IncomingSite: Codable {
|
||||||
|
|
||||||
log.notice("Saving to \(configPath, privacy: .public)")
|
log.notice("Saving to \(configPath, privacy: .public)")
|
||||||
do {
|
do {
|
||||||
if (self.key != nil) {
|
if self.key != nil {
|
||||||
let data = self.key!.data(using: .utf8)
|
let data = self.key!.data(using: .utf8)
|
||||||
if (!KeyChain.save(key: "\(self.id).key", data: data!, managed: self.managed ?? false)) {
|
if !KeyChain.save(
|
||||||
|
key: "\(self.id).key", data: data!, managed: self.managed ?? false)
|
||||||
|
{
|
||||||
return callback(SiteError.keySave)
|
return callback(SiteError.keySave)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if ((try self.dnCredentials?.save(siteID: self.id)) == false) {
|
if (try self.dnCredentials?.save(siteID: self.id)) == false {
|
||||||
return callback(SiteError.dnCredentialSave)
|
return callback(SiteError.dnCredentialSave)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -490,24 +500,25 @@ struct IncomingSite: Codable {
|
||||||
return callback(error)
|
return callback(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if targetEnvironment(simulator)
|
||||||
#if targetEnvironment(simulator)
|
|
||||||
// We are on a simulator and there is no NEVPNManager for us to interact with
|
// We are on a simulator and there is no NEVPNManager for us to interact with
|
||||||
callback(nil)
|
callback(nil)
|
||||||
#else
|
#else
|
||||||
if saveToManager {
|
if saveToManager {
|
||||||
self.saveToManager(manager: manager, callback: callback)
|
self.saveToManager(manager: manager, callback: callback)
|
||||||
} else {
|
} else {
|
||||||
callback(nil)
|
callback(nil)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private func saveToManager(manager: NETunnelProviderManager?, callback: @escaping ((any Error)?) -> ()) {
|
private func saveToManager(
|
||||||
if (manager != nil) {
|
manager: NETunnelProviderManager?, callback: @escaping ((any Error)?) -> Void
|
||||||
|
) {
|
||||||
|
if manager != nil {
|
||||||
// We need to refresh our settings to properly update config
|
// We need to refresh our settings to properly update config
|
||||||
manager?.loadFromPreferences { error in
|
manager?.loadFromPreferences { error in
|
||||||
if (error != nil) {
|
if error != nil {
|
||||||
return callback(error)
|
return callback(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,10 +530,13 @@ struct IncomingSite: Codable {
|
||||||
return finishSaveToManager(manager: NETunnelProviderManager(), callback: callback)
|
return finishSaveToManager(manager: NETunnelProviderManager(), callback: callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func finishSaveToManager(manager: NETunnelProviderManager, callback: @escaping ((any Error)?) -> ()) {
|
private func finishSaveToManager(
|
||||||
|
manager: NETunnelProviderManager, callback: @escaping ((any Error)?) -> Void
|
||||||
|
) {
|
||||||
// Stuff our details in the protocol
|
// Stuff our details in the protocol
|
||||||
let proto = manager.protocolConfiguration as? NETunnelProviderProtocol ?? NETunnelProviderProtocol()
|
let proto =
|
||||||
proto.providerBundleIdentifier = "net.defined.mobileNebula.NebulaNetworkExtension";
|
manager.protocolConfiguration as? NETunnelProviderProtocol ?? NETunnelProviderProtocol()
|
||||||
|
proto.providerBundleIdentifier = "net.defined.mobileNebula.NebulaNetworkExtension"
|
||||||
// WARN: If we stop setting providerConfiguration["id"] here, we'll need to use something else to match
|
// WARN: If we stop setting providerConfiguration["id"] here, we'll need to use something else to match
|
||||||
// managers in PacketTunnelProvider.findManager
|
// managers in PacketTunnelProvider.findManager
|
||||||
proto.providerConfiguration = ["id": self.id]
|
proto.providerConfiguration = ["id": self.id]
|
||||||
|
@ -536,7 +550,7 @@ struct IncomingSite: Codable {
|
||||||
manager.localizedDescription = self.name
|
manager.localizedDescription = self.name
|
||||||
manager.isEnabled = true
|
manager.isEnabled = true
|
||||||
|
|
||||||
manager.saveToPreferences{ error in
|
manager.saveToPreferences { error in
|
||||||
return callback(error)
|
return callback(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,12 +47,10 @@ class SiteList {
|
||||||
static func loadAll(completion: @escaping ([String: Site]?, (any Error)?) -> Void) {
|
static func loadAll(completion: @escaping ([String: Site]?, (any Error)?) -> Void) {
|
||||||
#if targetEnvironment(simulator)
|
#if targetEnvironment(simulator)
|
||||||
SiteList.loadAllFromFS { sites, err in
|
SiteList.loadAllFromFS { sites, err in
|
||||||
|
|
||||||
completion(sites, err)
|
completion(sites, err)
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
SiteList.loadAllFromNETPM { sites, err in
|
SiteList.loadAllFromNETPM { sites, err in
|
||||||
|
|
||||||
completion(sites, err)
|
completion(sites, err)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import MobileNebula
|
@preconcurrency import MobileNebula
|
||||||
|
|
||||||
enum APIClientError: Error {
|
enum APIClientError: Error {
|
||||||
case invalidCredentials
|
case invalidCredentials
|
||||||
}
|
}
|
||||||
|
|
||||||
class APIClient {
|
final class APIClient: Sendable {
|
||||||
let apiClient: MobileNebulaAPIClient
|
let apiClient: MobileNebulaAPIClient
|
||||||
let json = JSONDecoder()
|
let json = JSONDecoder()
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ actor DNUpdater {
|
||||||
private let timer = RepeatingTimer(timeInterval: 15 * 60) // 15 * 60 is 15 minutes
|
private let timer = RepeatingTimer(timeInterval: 15 * 60) // 15 * 60 is 15 minutes
|
||||||
private let log = Logger(subsystem: "net.defined.mobileNebula", category: "DNUpdater")
|
private let log = Logger(subsystem: "net.defined.mobileNebula", category: "DNUpdater")
|
||||||
|
|
||||||
private func updateAll(onUpdate: @escaping (Site) -> Void) {
|
private func updateAll(onUpdate: @Sendable @escaping (Site) -> Void) {
|
||||||
SiteList.loadAll(completion: { (sites, _) -> Void in
|
SiteList.loadAll(completion: { (sites, _) -> Void in
|
||||||
if let unwrappedSites = sites?.values {
|
if let unwrappedSites = sites?.values {
|
||||||
// NEVPN seems to force us onto the main thread and we are about to make network calls that
|
// NEVPN seems to force us onto the main thread and we are about to make network calls that
|
||||||
|
@ -28,7 +28,7 @@ actor DNUpdater {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateAllLoop(onUpdate: @escaping (Site) -> Void) {
|
func updateAllLoop(onUpdate: @Sendable @escaping (Site) -> Void) {
|
||||||
timer.eventHandler = {
|
timer.eventHandler = {
|
||||||
self.updateAll(onUpdate: onUpdate)
|
self.updateAll(onUpdate: onUpdate)
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,8 @@ class Sites {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SiteUpdater: NSObject, FlutterStreamHandler {
|
// FIXME: Make this class demonstrably Sendable
|
||||||
|
class SiteUpdater: NSObject, FlutterStreamHandler, @unchecked Sendable {
|
||||||
private var eventSink: FlutterEventSink?
|
private var eventSink: FlutterEventSink?
|
||||||
private var eventChannel: FlutterEventChannel
|
private var eventChannel: FlutterEventChannel
|
||||||
private var site: Site
|
private var site: Site
|
||||||
|
|
Loading…
Reference in a new issue