Silence some lints

This commit is contained in:
Caleb Jasik 2025-02-11 18:07:22 -06:00
parent 6564a18d3d
commit 985508fd79
No known key found for this signature in database
6 changed files with 69 additions and 55 deletions

View file

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

View file

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

View file

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

View file

@ -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()

View file

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

View file

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