Add FDA request dialog

This commit is contained in:
世界
2024-10-05 10:03:59 +08:00
parent 41ed30a5fa
commit 88ee9d5097
7 changed files with 92 additions and 9 deletions
@@ -86,6 +86,7 @@ public struct DashboardView: View {
@EnvironmentObject private var environments: ExtensionEnvironments
@EnvironmentObject private var profile: ExtensionProfile
@State private var alert: Alert?
@State private var notStarted = false
var body: some View {
VStack {
@@ -93,10 +94,23 @@ public struct DashboardView: View {
}
.alertBinding($alert)
.onChangeCompat(of: profile.status) { newValue in
if newValue == .connected {
notStarted = false
}
if newValue == .disconnecting || newValue == .connected {
Task {
await checkServiceError()
}
} else if newValue == .connecting {
notStarted = true
} else if newValue == .disconnected {
if #available(iOS 16.0, macOS 13.0, tvOS 17.0, *) {
if notStarted {
Task {
await checkLastDisconnectError()
}
}
}
}
}
}
@@ -111,5 +125,48 @@ public struct DashboardView: View {
alert = Alert(title: Text("Service Error"), message: Text(message))
}
}
@available(iOS 16.0, macOS 13.0, tvOS 17.0, *)
private nonisolated func checkLastDisconnectError() async {
var myError: NSError
do {
try await profile.fetchLastDisconnectError()
return
} catch {
myError = error as NSError
}
#if os(macOS)
if myError.domain == "Library.FullDiskAccessPermissionRequired" {
await MainActor.run {
alert = Alert(
title: Text("Full Disk Access permission is required"),
message: Text("Please grant the permission for SFMExtension, then we can continue."),
primaryButton: .default(Text("Authorize"), action: openFDASettings),
secondaryButton: .cancel()
)
}
return
}
#endif
let message = myError.localizedDescription
await MainActor.run {
alert = Alert(title: Text("Service Error"), message: Text(message))
}
}
#if os(macOS)
private func openFDASettings() {
if NSWorkspace.shared.open(URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles")!) {
return
}
if #available(macOS 13, *) {
NSWorkspace.shared.open(URL(fileURLWithPath: "/System/Applications/System Settings.app"))
} else {
NSWorkspace.shared.open(URL(fileURLWithPath: "/System/Applications/System Preferences.app"))
}
}
#endif
}
}
@@ -23,7 +23,8 @@ public struct ProfileOverrideView: View {
}
FormToggle("No Default Route", """
By default, segment routing is used in `auto_route` instead of global routing. If `*_<route_address/route_exclude_address>` exists in the configuration, this item will not take effect on the corresponding network (commonly used to resolve HomeKit compatibility issues).
By default, segment routing is used in `auto_route` instead of global routing.
If `*_<route_address/route_exclude_address>` exists in the configuration, this item will not take effect on the corresponding network (commonly used to resolve HomeKit compatibility issues).
""", $autoRouteUseSubRangesByDefault) { newValue in
await SharedPreferences.autoRouteUseSubRangesByDefault.set(newValue)
}
+5
View File
@@ -0,0 +1,5 @@
import Foundation
public enum FullDiskAccessPermissionRequired: Error {
case error
}
+5
View File
@@ -49,6 +49,11 @@ public class ExtensionProfile: ObservableObject {
try await manager.saveToPreferences()
}
@available(iOS 16.0, macOS 13.0, tvOS 17.0, *)
public func fetchLastDisconnectError() async throws {
try await connection.fetchLastDisconnectError()
}
public func start() async throws {
await fetchProfile()
manager.isEnabled = true
+1
View File
@@ -32,6 +32,7 @@ open class ExtensionProvider: NEPacketTunnelProvider {
LibboxRedirectStderr(FilePath.cacheDirectory.appendingPathComponent("stderr.log").relativePath, &error)
if let error {
writeFatalError("(packet-tunnel) redirect stderr error: \(error.localizedDescription)")
return
}
await LibboxSetMemoryLimit(!SharedPreferences.ignoreMemoryLimit.get())
@@ -1,5 +1,7 @@
import Libbox
import Library
import NetworkExtension
import System
class PacketTunnelProvider: ExtensionProvider {
override func startTunnel(options: [String: NSObject]?) async throws {
@@ -10,6 +12,19 @@ class PacketTunnelProvider: ExtensionProvider {
let username = usernameObject as! NSString
FilePath.sharedDirectory = URL(filePath: "/Users/\(username)/Library/Group Containers/\(FilePath.groupName)")
FilePath.iCloudDirectory = URL(filePath: "/Users/\(username)/Library/Mobile Documents/iCloud~\(FilePath.packageName.replacingOccurrences(of: ".", with: "~"))").appendingPathComponent("Documents", isDirectory: true)
let databasePath = FilePath.sharedDirectory.appendingPathComponent("settings.db").relativePath
if !FileManager.default.isReadableFile(atPath: databasePath) {
do {
let fd = try FileDescriptor.open(databasePath, .readOnly)
try! fd.close()
NSLog("Can access \(databasePath)")
} catch {
NSLog("Can't access \(databasePath): \(error.localizedDescription)")
}
try await Task.sleep(nanoseconds: NSEC_PER_MSEC * 100)
throw FullDiskAccessPermissionRequired.error
}
self.username = String(username)
try await super.startTunnel(options: options)
}
+7 -8
View File
@@ -117,6 +117,7 @@
3AE4D0BD2A6E2DDC009FEA9E /* Library.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AEC211D2A459B4700A63465 /* Library.framework */; };
3AE4D0BE2A6E2DDC009FEA9E /* Library.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3AEC211D2A459B4700A63465 /* Library.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
3AE4D0C12A6E4852009FEA9E /* InstallSystemExtensionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE4D0C02A6E4852009FEA9E /* InstallSystemExtensionButton.swift */; };
3AE5A6C32C9FD96A002AA4FE /* ExtensionErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE5A6C22C9FD967002AA4FE /* ExtensionErrors.swift */; };
3AEAEE992A4F16430059612D /* Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 3A096F862A4ED3DE00D4A2ED /* Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
3AEC20F62A459AB400A63465 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AEC20F52A459AB400A63465 /* Application.swift */; };
3AEC20FA2A459AB500A63465 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3AEC20F92A459AB500A63465 /* Assets.xcassets */; };
@@ -456,6 +457,7 @@
3A27D9012A89C6870031EBCC /* ExtensionEnvironments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionEnvironments.swift; sourceTree = "<group>"; };
3A2EAEEC2A6F4CBB00D00DE3 /* IndependentApplicationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndependentApplicationDelegate.swift; sourceTree = "<group>"; };
3A2F29EA2C998A5D007E024C /* Export.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Export.plist; sourceTree = "<group>"; };
3A334ECF2C0F621E00E9C577 /* ConnectionDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionDetailsView.swift; sourceTree = "<group>"; };
3A3AB2A62B70C146001815AE /* CoreView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreView.swift; sourceTree = "<group>"; };
3A3AB2A82B70C5F1001815AE /* RequestReviewButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestReviewButton.swift; sourceTree = "<group>"; };
3A3DEBE12A4FFA1A00373BF4 /* ExtensionFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ExtensionFoundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.0.sdk/System/Library/Frameworks/ExtensionFoundation.framework; sourceTree = DEVELOPER_DIR; };
@@ -529,6 +531,7 @@
3AE1719F2A8128DD00393060 /* TVExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TVExtension.entitlements; sourceTree = "<group>"; };
3AE4D0B62A6E2C01009FEA9E /* PacketTunnelProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelProvider.swift; sourceTree = "<group>"; };
3AE4D0C02A6E4852009FEA9E /* InstallSystemExtensionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallSystemExtensionButton.swift; sourceTree = "<group>"; };
3AE5A6C22C9FD967002AA4FE /* ExtensionErrors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionErrors.swift; sourceTree = "<group>"; };
3AEAEE9C2A4F1A9D0059612D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
3AEC20DB2A4599D000A63465 /* Libbox.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Libbox.xcframework; sourceTree = "<group>"; };
3AEC20F32A459AB400A63465 /* sing-box.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "sing-box.app"; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -914,6 +917,7 @@
3AEC21432A45A92B00A63465 /* Network */ = {
isa = PBXGroup;
children = (
3AE5A6C22C9FD967002AA4FE /* ExtensionErrors.swift */,
3A096F892A4ED3DE00D4A2ED /* ExtensionProvider.swift */,
3AF342AA2A4AA173002B34AC /* Extension+Iterator.swift */,
3AF342A82A4AA155002B34AC /* Extension+RunBlocking.swift */,
@@ -1583,6 +1587,7 @@
3AEC21452A45A93800A63465 /* HTTPClient.swift in Sources */,
3AEC213C2A459FDF00A63465 /* Databse.swift in Sources */,
3A60CC292B70A7C400D2D682 /* Color+Extension.swift in Sources */,
3AE5A6C32C9FD96A002AA4FE /* ExtensionErrors.swift in Sources */,
3A4EAD3C2A4FECCE005435B3 /* NEVPNStatus+isConnected.swift in Sources */,
3ADBB4252A7389640041D44F /* ProfileServer.swift in Sources */,
3AEC21422A45A8FF00A63465 /* Profile+Update.swift in Sources */,
@@ -1837,7 +1842,6 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_MODULE_VERIFIER = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -1880,7 +1884,6 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_MODULE_VERIFIER = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -2439,7 +2442,6 @@
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
EMBED_ASSET_PACKS_IN_PRODUCT_BUNDLE = NO;
ENABLE_MODULE_VERIFIER = YES;
ENABLE_ON_DEMAND_RESOURCES = NO;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
@@ -2487,7 +2489,6 @@
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
EMBED_ASSET_PACKS_IN_PRODUCT_BUNDLE = NO;
ENABLE_MODULE_VERIFIER = YES;
ENABLE_ON_DEMAND_RESOURCES = NO;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
@@ -2532,7 +2533,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = SystemExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = SystemExtension;
INFOPLIST_KEY_CFBundleDisplayName = SFMExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_KEY_NSSystemExtensionUsageDescription = "";
LD_RUNPATH_SEARCH_PATHS = (
@@ -2568,7 +2569,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = SystemExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = SystemExtension;
INFOPLIST_KEY_CFBundleDisplayName = SFMExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_KEY_NSSystemExtensionUsageDescription = "";
LD_RUNPATH_SEARCH_PATHS = (
@@ -2685,7 +2686,6 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_MODULE_VERIFIER = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
@@ -2725,7 +2725,6 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_MODULE_VERIFIER = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";