Compare commits
72 Commits
0.0.201904
...
0.0.201910
Author | SHA1 | Date | |
---|---|---|---|
226166bdaf | |||
80fa72cabc | |||
d976d159d0 | |||
84ca7fcf40 | |||
f120a6aab0 | |||
0d8108d8da | |||
e072ebee58 | |||
c6767d9007 | |||
bb5760cca4 | |||
26b7971ba6 | |||
b286ede3c6 | |||
4ef7afe3ca | |||
377f2f0496 | |||
7ed5893fc6 | |||
e70c397e54 | |||
6a6be9edde | |||
37f8500fe6 | |||
207f82dd9d | |||
de8fedf87a | |||
98d306da5b | |||
c7b7b1247b | |||
a66f13eb01 | |||
f50e7ae686 | |||
4d6692548c | |||
1dccd39818 | |||
4cb775c72f | |||
4cb783c447 | |||
d20daa345a | |||
168ba2da8a | |||
714d6a41bd | |||
9b92a8f933 | |||
5e9780ef8f | |||
9faf814e8b | |||
30da10a0e9 | |||
a18614d6b3 | |||
5100e597aa | |||
0340641c4c | |||
813dea6902 | |||
c30d491edc | |||
88c80d6694 | |||
393718dfaf | |||
f852b6f919 | |||
8926434682 | |||
493c7b102e | |||
717bc8a26f | |||
e582155a10 | |||
70d19691a7 | |||
40b1f0bac8 | |||
52ac9b82c2 | |||
fc1fdbbcdb | |||
300268daa0 | |||
9bf304a9ac | |||
586a592b68 | |||
c0526d2efb | |||
fdbd4f875e | |||
4a037cc706 | |||
5190fc2249 | |||
3f25d54dcc | |||
f9880907a2 | |||
404fa741e8 | |||
6e1f03e41c | |||
6d8965e97d | |||
5e5481b69b | |||
69b33c0fad | |||
167e4f0bf2 | |||
6e3b28852a | |||
5914e868ab | |||
83ea9d6fa7 | |||
b954e9a4fd | |||
76894fba68 | |||
89a564ce62 | |||
178fe86d36 |
@ -1,12 +1,14 @@
|
||||
# [WireGuard](https://www.wireguard.com/) for iOS and macOS
|
||||
|
||||
This project contains an application for iOS and for macOS, as well as many components shared between the two of them. You may toggle between the two platforms by selecting the target from within Xcode.
|
||||
|
||||
## Building
|
||||
|
||||
- Clone this repo recursively:
|
||||
- Clone this repo:
|
||||
|
||||
```
|
||||
$ git clone --recursive https://git.zx2c4.com/wireguard-ios
|
||||
$ cd wireguard-ios
|
||||
$ git clone https://git.zx2c4.com/wireguard-apple
|
||||
$ cd wireguard-apple
|
||||
```
|
||||
|
||||
- Rename and populate developer team ID file:
|
||||
|
@ -112,6 +112,6 @@ class Keychain {
|
||||
static func verifyReference(called ref: Data) -> Bool {
|
||||
return SecItemCopyMatching([kSecClass as String: kSecClassGenericPassword,
|
||||
kSecValuePersistentRef as String: ref] as CFDictionary,
|
||||
nil) == errSecSuccess
|
||||
nil) != errSecItemNotFound
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,9 @@ extension NETunnelProviderProtocol {
|
||||
if passwordReference == nil {
|
||||
return nil
|
||||
}
|
||||
#if os(macOS)
|
||||
providerConfiguration = ["UID": getuid()]
|
||||
#endif
|
||||
|
||||
let endpoints = tunnelConfiguration.peers.compactMap { $0.endpoint }
|
||||
if endpoints.count == 1 {
|
||||
@ -60,11 +63,25 @@ extension NETunnelProviderProtocol {
|
||||
* in the keychain. But it's still useful to keep the migration
|
||||
* around so that .mobileconfig files are easier.
|
||||
*/
|
||||
guard let oldConfig = providerConfiguration?["WgQuickConfig"] as? String else { return false }
|
||||
providerConfiguration = nil
|
||||
guard passwordReference == nil else { return true }
|
||||
wg_log(.debug, message: "Migrating tunnel configuration '\(name)'")
|
||||
passwordReference = Keychain.makeReference(containing: oldConfig, called: name)
|
||||
return true
|
||||
if let oldConfig = providerConfiguration?["WgQuickConfig"] as? String {
|
||||
#if os(macOS)
|
||||
providerConfiguration = ["UID": getuid()]
|
||||
#elseif os(iOS)
|
||||
providerConfiguration = nil
|
||||
#else
|
||||
#error("Unimplemented")
|
||||
#endif
|
||||
guard passwordReference == nil else { return true }
|
||||
wg_log(.debug, message: "Migrating tunnel configuration '\(name)'")
|
||||
passwordReference = Keychain.makeReference(containing: oldConfig, called: name)
|
||||
return true
|
||||
}
|
||||
#if os(macOS)
|
||||
if passwordReference != nil && providerConfiguration?["UID"] == nil && verifyConfigurationReference() {
|
||||
providerConfiguration = ["UID": getuid()]
|
||||
return true
|
||||
}
|
||||
#endif
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ extension TunnelConfiguration {
|
||||
var interfaceConfiguration: InterfaceConfiguration?
|
||||
var peerConfigurations = [PeerConfiguration]()
|
||||
|
||||
let lines = wgQuickConfig.split(separator: "\n")
|
||||
let lines = wgQuickConfig.split { $0.isNewline }
|
||||
|
||||
var parserState = ParserState.notInASection
|
||||
var attributes = [String: String]()
|
||||
|
@ -52,6 +52,10 @@
|
||||
6F0F44CB222D55FD00B0FF04 /* EditableTextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F0F44CA222D55FD00B0FF04 /* EditableTextCell.swift */; };
|
||||
6F1075642258AE9800D78929 /* DeleteTunnelsConfirmationAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F1075632258AE9800D78929 /* DeleteTunnelsConfirmationAlert.swift */; };
|
||||
6F19D30422402B8700A126F2 /* ConfirmationAlertPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F19D30322402B8700A126F2 /* ConfirmationAlertPresenter.swift */; };
|
||||
6F2449E8226587B90047B9E9 /* MacAppStoreUpdateDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2449E7226587B80047B9E9 /* MacAppStoreUpdateDetector.swift */; };
|
||||
6F3E02E9228000F6001FE7E3 /* MainMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F3E02E8228000F6001FE7E3 /* MainMenu.swift */; };
|
||||
6F29A9432278518D00DC6A6B /* RecentTunnelsTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F29A9422278518D00DC6A6B /* RecentTunnelsTracker.swift */; };
|
||||
6F29A94722787B1600DC6A6B /* QuickActionItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F29A94622787B1600DC6A6B /* QuickActionItem.swift */; };
|
||||
6F4DD16B21DA558800690EAE /* TunnelListRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F4DD16A21DA558800690EAE /* TunnelListRow.swift */; };
|
||||
6F4DD16C21DA558F00690EAE /* NSTableView+Reuse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F4DD16721DA552B00690EAE /* NSTableView+Reuse.swift */; };
|
||||
6F4DD16E21DBEA0700690EAE /* ManageTunnelsRootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F4DD16D21DBEA0700690EAE /* ManageTunnelsRootViewController.swift */; };
|
||||
@ -66,6 +70,7 @@
|
||||
6F628C3D217F09E9003482A3 /* TunnelViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F628C3C217F09E9003482A3 /* TunnelViewModel.swift */; };
|
||||
6F628C3F217F3413003482A3 /* DNSServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F628C3E217F3413003482A3 /* DNSServer.swift */; };
|
||||
6F628C41217F47DB003482A3 /* TunnelDetailTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F628C40217F47DB003482A3 /* TunnelDetailTableViewController.swift */; };
|
||||
6F6483E7229293300075BA15 /* LaunchedAtLoginDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F6483E6229293300075BA15 /* LaunchedAtLoginDetector.swift */; };
|
||||
6F6899A62180447E0012E523 /* x25519.c in Sources */ = {isa = PBXBuildFile; fileRef = 6F6899A52180447E0012E523 /* x25519.c */; };
|
||||
6F6899A8218044FC0012E523 /* Curve25519.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F6899A7218044FC0012E523 /* Curve25519.swift */; };
|
||||
6F693A562179E556008551C1 /* Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F693A552179E556008551C1 /* Endpoint.swift */; };
|
||||
@ -298,6 +303,10 @@
|
||||
6F0F44CA222D55FD00B0FF04 /* EditableTextCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditableTextCell.swift; sourceTree = "<group>"; };
|
||||
6F1075632258AE9800D78929 /* DeleteTunnelsConfirmationAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteTunnelsConfirmationAlert.swift; sourceTree = "<group>"; };
|
||||
6F19D30322402B8700A126F2 /* ConfirmationAlertPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationAlertPresenter.swift; sourceTree = "<group>"; };
|
||||
6F2449E7226587B80047B9E9 /* MacAppStoreUpdateDetector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacAppStoreUpdateDetector.swift; sourceTree = "<group>"; };
|
||||
6F3E02E8228000F6001FE7E3 /* MainMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainMenu.swift; sourceTree = "<group>"; };
|
||||
6F29A9422278518D00DC6A6B /* RecentTunnelsTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentTunnelsTracker.swift; sourceTree = "<group>"; };
|
||||
6F29A94622787B1600DC6A6B /* QuickActionItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QuickActionItem.swift; sourceTree = "<group>"; };
|
||||
6F4DD16721DA552B00690EAE /* NSTableView+Reuse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSTableView+Reuse.swift"; sourceTree = "<group>"; };
|
||||
6F4DD16A21DA558800690EAE /* TunnelListRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelListRow.swift; sourceTree = "<group>"; };
|
||||
6F4DD16D21DBEA0700690EAE /* ManageTunnelsRootViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageTunnelsRootViewController.swift; sourceTree = "<group>"; };
|
||||
@ -316,6 +325,7 @@
|
||||
6F628C3C217F09E9003482A3 /* TunnelViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelViewModel.swift; sourceTree = "<group>"; };
|
||||
6F628C3E217F3413003482A3 /* DNSServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DNSServer.swift; sourceTree = "<group>"; };
|
||||
6F628C40217F47DB003482A3 /* TunnelDetailTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TunnelDetailTableViewController.swift; sourceTree = "<group>"; };
|
||||
6F6483E6229293300075BA15 /* LaunchedAtLoginDetector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchedAtLoginDetector.swift; sourceTree = "<group>"; };
|
||||
6F689999218043390012E523 /* WireGuard-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WireGuard-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
6F6899A42180447E0012E523 /* x25519.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x25519.h; sourceTree = "<group>"; };
|
||||
6F6899A52180447E0012E523 /* x25519.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x25519.c; sourceTree = "<group>"; };
|
||||
@ -562,6 +572,8 @@
|
||||
6F919EC2218A2AE90023B400 /* ErrorPresenter.swift */,
|
||||
6F19D30322402B8700A126F2 /* ConfirmationAlertPresenter.swift */,
|
||||
5F45417C21C1B23600994C13 /* UITableViewCell+Reuse.swift */,
|
||||
6F29A9422278518D00DC6A6B /* RecentTunnelsTracker.swift */,
|
||||
6F29A94622787B1600DC6A6B /* QuickActionItem.swift */,
|
||||
6FF4AC23211EC472002C96EB /* Info.plist */,
|
||||
6FF4AC482120B9E0002C96EB /* WireGuard.entitlements */,
|
||||
);
|
||||
@ -629,9 +641,12 @@
|
||||
6FB1BD5F21D2607A00A991BF /* AppDelegate.swift */,
|
||||
6F89E17921EDEB0E00C97BB9 /* StatusItemController.swift */,
|
||||
6FBA101621D655340051C35F /* StatusMenu.swift */,
|
||||
6F3E02E8228000F6001FE7E3 /* MainMenu.swift */,
|
||||
6F89E17B21F090CC00C97BB9 /* TunnelsTracker.swift */,
|
||||
6FBA104121D6BC210051C35F /* ErrorPresenter.swift */,
|
||||
6FCD99AE21E0EA1700BA4C82 /* ImportPanelPresenter.swift */,
|
||||
6F2449E7226587B80047B9E9 /* MacAppStoreUpdateDetector.swift */,
|
||||
6F6483E6229293300075BA15 /* LaunchedAtLoginDetector.swift */,
|
||||
6FB1BD6121D2607E00A991BF /* Assets.xcassets */,
|
||||
6FB1BD6621D2607E00A991BF /* Info.plist */,
|
||||
6FB1BD6721D2607E00A991BF /* WireGuard.entitlements */,
|
||||
@ -1286,8 +1301,10 @@
|
||||
6F4DD16B21DA558800690EAE /* TunnelListRow.swift in Sources */,
|
||||
6FDB6D15224CB2CE00EE4BC3 /* LogViewCell.swift in Sources */,
|
||||
6FE3661D21F64F6B00F78C7D /* ConfTextColorTheme.swift in Sources */,
|
||||
6F3E02E9228000F6001FE7E3 /* MainMenu.swift in Sources */,
|
||||
5F52D0BF21E3788900283CEA /* NSColor+Hex.swift in Sources */,
|
||||
6FB1BDBE21D50F0200A991BF /* Logger.swift in Sources */,
|
||||
6F6483E7229293300075BA15 /* LaunchedAtLoginDetector.swift in Sources */,
|
||||
6FB1BDBF21D50F0200A991BF /* TunnelConfiguration+WgQuickConfig.swift in Sources */,
|
||||
6FADE96C2254B8C300B838A4 /* UnusableTunnelDetailViewController.swift in Sources */,
|
||||
6FFACD2021E4D8D500E9A2A5 /* ParseError+WireGuardAppError.swift in Sources */,
|
||||
@ -1304,6 +1321,7 @@
|
||||
6FBA104321D6BC250051C35F /* ErrorPresenter.swift in Sources */,
|
||||
6FB1BDC521D50F0300A991BF /* Endpoint.swift in Sources */,
|
||||
6FB1BDC621D50F0300A991BF /* DNSServer.swift in Sources */,
|
||||
6F2449E8226587B90047B9E9 /* MacAppStoreUpdateDetector.swift in Sources */,
|
||||
6FB1BDC721D50F0300A991BF /* InterfaceConfiguration.swift in Sources */,
|
||||
6F907C9D224663A2003CED21 /* LogViewHelper.swift in Sources */,
|
||||
6FB1BDC821D50F0300A991BF /* PeerConfiguration.swift in Sources */,
|
||||
@ -1343,6 +1361,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6FE1765A21C90E87002690EA /* LocalizationHelper.swift in Sources */,
|
||||
6F29A94722787B1600DC6A6B /* QuickActionItem.swift in Sources */,
|
||||
6FF3527221C2616C0008484E /* ringlogger.c in Sources */,
|
||||
6F0F44CB222D55FD00B0FF04 /* EditableTextCell.swift in Sources */,
|
||||
6FF3527321C2616C0008484E /* Logger.swift in Sources */,
|
||||
@ -1383,6 +1402,7 @@
|
||||
6F7774EA217229DB006A79B3 /* IPAddressRange.swift in Sources */,
|
||||
6F7774E82172020C006A79B3 /* TunnelConfiguration.swift in Sources */,
|
||||
6FDEF7FB21863B6100D8FBF6 /* unzip.c in Sources */,
|
||||
6F29A9432278518D00DC6A6B /* RecentTunnelsTracker.swift in Sources */,
|
||||
6F6899A8218044FC0012E523 /* Curve25519.swift in Sources */,
|
||||
6F0F44C9222D55BB00B0FF04 /* TextCell.swift in Sources */,
|
||||
5F4541A021C2D6B700994C13 /* TunnelListCell.swift in Sources */,
|
||||
@ -1513,7 +1533,7 @@
|
||||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = WireGuard/UI/macOS/LoginItemHelper/LoginItemHelper.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
INFOPLIST_FILE = WireGuard/UI/macOS/Info.plist;
|
||||
INFOPLIST_FILE = WireGuard/UI/macOS/LoginItemHelper/Info.plist;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "$(APP_ID_MACOS).login-item-helper";
|
||||
PRODUCT_NAME = WireGuardLoginItemHelper;
|
||||
SDKROOT = macosx;
|
||||
@ -1526,7 +1546,7 @@
|
||||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = WireGuard/UI/macOS/LoginItemHelper/LoginItemHelper.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
INFOPLIST_FILE = WireGuard/UI/macOS/Info.plist;
|
||||
INFOPLIST_FILE = WireGuard/UI/macOS/LoginItemHelper/Info.plist;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "$(APP_ID_MACOS).login-item-helper";
|
||||
PRODUCT_NAME = WireGuardLoginItemHelper;
|
||||
SDKROOT = macosx;
|
||||
@ -1687,6 +1707,7 @@
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
@ -1752,6 +1773,7 @@
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
|
@ -291,19 +291,41 @@
|
||||
"alertSystemErrorMessageTunnelConfigurationReadWriteFailed" = "Reading or writing the configuration failed.";
|
||||
"alertSystemErrorMessageTunnelConfigurationUnknown" = "Unknown system error.";
|
||||
|
||||
// Mac status bar menu / pulldown menu
|
||||
// Mac status bar menu / pulldown menu / main menu
|
||||
|
||||
"macMenuNetworks (%@)" = "Networks: %@";
|
||||
"macMenuNetworksNone" = "Networks: None";
|
||||
|
||||
"macMenuTitle" = "WireGuard";
|
||||
"macMenuManageTunnels" = "Manage tunnels";
|
||||
"macMenuImportTunnels" = "Import tunnel(s) from file…";
|
||||
"macMenuAddEmptyTunnel" = "Add empty tunnel…";
|
||||
"macMenuViewLog" = "View log";
|
||||
"macMenuExportTunnels" = "Export tunnels to zip…";
|
||||
"macMenuManageTunnels" = "Manage Tunnels";
|
||||
"macMenuImportTunnels" = "Import Tunnel(s) from File…";
|
||||
"macMenuAddEmptyTunnel" = "Add Empty Tunnel…";
|
||||
"macMenuViewLog" = "View Log";
|
||||
"macMenuExportTunnels" = "Export Tunnels to Zip…";
|
||||
"macMenuAbout" = "About WireGuard";
|
||||
"macMenuQuit" = "Quit";
|
||||
"macMenuQuit" = "Quit WireGuard";
|
||||
|
||||
"macMenuHideApp" = "Hide WireGuard";
|
||||
"macMenuHideOtherApps" = "Hide Others";
|
||||
"macMenuShowAllApps" = "Show All";
|
||||
|
||||
"macMenuFile" = "File";
|
||||
"macMenuCloseWindow" = "Close Window";
|
||||
|
||||
"macMenuEdit" = "Edit";
|
||||
"macMenuCut" = "Cut";
|
||||
"macMenuCopy" = "Copy";
|
||||
"macMenuPaste" = "Paste";
|
||||
"macMenuSelectAll" = "Select All";
|
||||
|
||||
"macMenuTunnel" = "Tunnel";
|
||||
"macMenuToggleStatus" = "Toggle Status";
|
||||
"macMenuEditTunnel" = "Edit…";
|
||||
"macMenuDeleteSelected" = "Delete Selected";
|
||||
|
||||
"macMenuWindow" = "Window";
|
||||
"macMenuMinimize" = "Minimize";
|
||||
"macMenuZoom" = "Zoom";
|
||||
|
||||
// Mac manage tunnels window
|
||||
|
||||
@ -383,10 +405,14 @@
|
||||
|
||||
// Mac alert
|
||||
|
||||
"macConfirmAndQuitAlertMessage" = "Do you want to close the tunnels manager or quit WireGuard entirely?";
|
||||
"macConfirmAndQuitAlertInfo" = "If you close the tunnels manager, WireGuard will continue to be available from the menu bar icon.";
|
||||
"macConfirmAndQuitInfoWithActiveTunnel (%@)" = "If you close the tunnels manager, WireGuard will continue to be available from the menu bar icon.\n\nNote that if you quit WireGuard entirely the currently active tunnel ('%@') will still remain active until you deactivate it from this application or through the Network panel in System Preferences.";
|
||||
"macConfirmAndQuitAlertQuitWireGuard" = "Quit WireGuard";
|
||||
"macConfirmAndQuitAlertCloseWindow" = "Close Tunnels Manager";
|
||||
|
||||
"macAppExitingWithActiveTunnelMessage" = "WireGuard is exiting with an active tunnel";
|
||||
"macAppExitingWithActiveTunnelInfo" = "The tunnel will remain active after exiting. You may disable it by reopening this application or through the Network panel in System Preferences.";
|
||||
"macPrivacyNoticeMessage" = "Privacy notice: be sure you trust this configuration file";
|
||||
"macPrivacyNoticeInfo" = "You will be prompted by the system to allow or disallow adding a VPN configuration. While this application does not send any information to the WireGuard project, information is by design sent to the servers specified inside of the configuration file you have just added, which configures your computer to use those servers as a VPN. Be certain that you trust this configuration before clicking “Allow” in the following dialog.";
|
||||
|
||||
// Mac tooltip
|
||||
|
||||
@ -405,3 +431,13 @@
|
||||
"macUnusableTunnelMessage" = "The configuration for this tunnel cannot be found in the keychain.";
|
||||
"macUnusableTunnelInfo" = "In case this tunnel was created by another user, only that user can view, edit, or activate this tunnel.";
|
||||
"macUnusableTunnelButtonTitleDeleteTunnel" = "Delete tunnel";
|
||||
|
||||
// Mac App Store updating alert
|
||||
|
||||
"macAppStoreUpdatingAlertMessage" = "App Store would like to update WireGuard";
|
||||
"macAppStoreUpdatingAlertInfoWithOnDemand (%@)" = "Please disable on-demand for tunnel ‘%@’, deactivate it, and then continue updating in App Store.";
|
||||
"macAppStoreUpdatingAlertInfoWithoutOnDemand (%@)" = "Please deactivate tunnel ‘%@’ and then continue updating in App Store.";
|
||||
|
||||
// Donation
|
||||
|
||||
"donateLink" = "♥ Donate to the WireGuard Project";
|
||||
|
@ -1,2 +1,2 @@
|
||||
VERSION_NAME = 0.0.20190409
|
||||
VERSION_ID = 7
|
||||
VERSION_NAME = 0.0.20191012
|
||||
VERSION_ID = 14
|
||||
|
@ -46,46 +46,59 @@ extension ActivateOnDemandOption {
|
||||
}
|
||||
|
||||
init(from tunnelProviderManager: NETunnelProviderManager) {
|
||||
let rules = tunnelProviderManager.onDemandRules ?? []
|
||||
let activateOnDemandOption: ActivateOnDemandOption
|
||||
if tunnelProviderManager.isOnDemandEnabled, let onDemandRules = tunnelProviderManager.onDemandRules {
|
||||
self = ActivateOnDemandOption.create(from: onDemandRules)
|
||||
} else {
|
||||
self = .off
|
||||
}
|
||||
}
|
||||
|
||||
private static func create(from rules: [NEOnDemandRule]) -> ActivateOnDemandOption {
|
||||
switch rules.count {
|
||||
case 0:
|
||||
activateOnDemandOption = .off
|
||||
return .off
|
||||
case 1:
|
||||
let rule = rules[0]
|
||||
precondition(rule.action == .connect)
|
||||
activateOnDemandOption = .anyInterface(.anySSID)
|
||||
guard rule.action == .connect else { return .off }
|
||||
return .anyInterface(.anySSID)
|
||||
case 2:
|
||||
let connectRule = rules.first(where: { $0.action == .connect })!
|
||||
let disconnectRule = rules.first(where: { $0.action == .disconnect })!
|
||||
guard let connectRule = rules.first(where: { $0.action == .connect }) else {
|
||||
wg_log(.error, message: "Unexpected onDemandRules set on tunnel provider manager: \(rules.count) rules found but no connect rule.")
|
||||
return .off
|
||||
}
|
||||
guard let disconnectRule = rules.first(where: { $0.action == .disconnect }) else {
|
||||
wg_log(.error, message: "Unexpected onDemandRules set on tunnel provider manager: \(rules.count) rules found but no disconnect rule.")
|
||||
return .off
|
||||
}
|
||||
if connectRule.interfaceTypeMatch == .wiFi && disconnectRule.interfaceTypeMatch == nonWiFiInterfaceType {
|
||||
activateOnDemandOption = .wiFiInterfaceOnly(.anySSID)
|
||||
return .wiFiInterfaceOnly(.anySSID)
|
||||
} else if connectRule.interfaceTypeMatch == nonWiFiInterfaceType && disconnectRule.interfaceTypeMatch == .wiFi {
|
||||
activateOnDemandOption = .nonWiFiInterfaceOnly
|
||||
return .nonWiFiInterfaceOnly
|
||||
} else {
|
||||
fatalError("Unexpected onDemandRules set on tunnel provider manager")
|
||||
wg_log(.error, message: "Unexpected onDemandRules set on tunnel provider manager: \(rules.count) rules found but interface types are inconsistent.")
|
||||
return .off
|
||||
}
|
||||
case 3:
|
||||
let ssidRule = rules.first(where: { $0.interfaceTypeMatch == .wiFi && $0.ssidMatch != nil })!
|
||||
let nonWiFiRule = rules.first(where: { $0.interfaceTypeMatch == nonWiFiInterfaceType })!
|
||||
guard let ssidRule = rules.first(where: { $0.interfaceTypeMatch == .wiFi && $0.ssidMatch != nil }) else { return .off }
|
||||
guard let nonWiFiRule = rules.first(where: { $0.interfaceTypeMatch == nonWiFiInterfaceType }) else { return .off }
|
||||
let ssids = ssidRule.ssidMatch!
|
||||
switch (ssidRule.action, nonWiFiRule.action) {
|
||||
case (.connect, .connect):
|
||||
activateOnDemandOption = .anyInterface(.onlySpecificSSIDs(ssids))
|
||||
return .anyInterface(.onlySpecificSSIDs(ssids))
|
||||
case (.connect, .disconnect):
|
||||
activateOnDemandOption = .wiFiInterfaceOnly(.onlySpecificSSIDs(ssids))
|
||||
return .wiFiInterfaceOnly(.onlySpecificSSIDs(ssids))
|
||||
case (.disconnect, .connect):
|
||||
activateOnDemandOption = .anyInterface(.exceptSpecificSSIDs(ssids))
|
||||
return .anyInterface(.exceptSpecificSSIDs(ssids))
|
||||
case (.disconnect, .disconnect):
|
||||
activateOnDemandOption = .wiFiInterfaceOnly(.exceptSpecificSSIDs(ssids))
|
||||
return .wiFiInterfaceOnly(.exceptSpecificSSIDs(ssids))
|
||||
default:
|
||||
fatalError("Unexpected SSID onDemandRules set on tunnel provider manager")
|
||||
wg_log(.error, message: "Unexpected onDemandRules set on tunnel provider manager: \(rules.count) rules found")
|
||||
return .off
|
||||
}
|
||||
default:
|
||||
fatalError("Unexpected number of onDemandRules set on tunnel provider manager")
|
||||
wg_log(.error, message: "Unexpected number of onDemandRules set on tunnel provider manager: \(rules.count) rules found")
|
||||
return .off
|
||||
}
|
||||
|
||||
self = activateOnDemandOption
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ class TunnelsManager {
|
||||
startObservingTunnelConfigurations()
|
||||
}
|
||||
|
||||
static func create(completionHandler: @escaping (WireGuardResult<TunnelsManager>) -> Void) {
|
||||
static func create(completionHandler: @escaping (Result<TunnelsManager, TunnelsManagerError>) -> Void) {
|
||||
#if targetEnvironment(simulator)
|
||||
completionHandler(.success(TunnelsManager(tunnelProviders: MockTunnels.createMockTunnels())))
|
||||
#else
|
||||
@ -46,7 +46,11 @@ class TunnelsManager {
|
||||
|
||||
var tunnelManagers = managers ?? []
|
||||
var refs: Set<Data> = []
|
||||
var tunnelNames: Set<String> = []
|
||||
for (index, tunnelManager) in tunnelManagers.enumerated().reversed() {
|
||||
if let tunnelName = tunnelManager.localizedDescription {
|
||||
tunnelNames.insert(tunnelName)
|
||||
}
|
||||
guard let proto = tunnelManager.protocolConfiguration as? NETunnelProviderProtocol else { continue }
|
||||
if proto.migrateConfigurationIfNeeded(called: tunnelManager.localizedDescription ?? "unknown") {
|
||||
tunnelManager.saveToPreferences { _ in }
|
||||
@ -54,18 +58,27 @@ class TunnelsManager {
|
||||
#if os(iOS)
|
||||
let passwordRef = proto.verifyConfigurationReference() ? proto.passwordReference : nil
|
||||
#elseif os(macOS)
|
||||
let passwordRef = proto.passwordReference // To handle multiple users in macOS, we skip verifying
|
||||
let passwordRef: Data?
|
||||
if proto.providerConfiguration?["UID"] as? uid_t == getuid() {
|
||||
passwordRef = proto.verifyConfigurationReference() ? proto.passwordReference : nil
|
||||
} else {
|
||||
passwordRef = proto.passwordReference // To handle multiple users in macOS, we skip verifying
|
||||
}
|
||||
#else
|
||||
#error("Unimplemented")
|
||||
#endif
|
||||
if let ref = passwordRef {
|
||||
refs.insert(ref)
|
||||
} else {
|
||||
wg_log(.info, message: "Removing orphaned tunnel with non-verifying keychain entry: \(tunnelManager.localizedDescription ?? "<unknown>")")
|
||||
tunnelManager.removeFromPreferences { _ in }
|
||||
tunnelManagers.remove(at: index)
|
||||
}
|
||||
}
|
||||
Keychain.deleteReferences(except: refs)
|
||||
#if os(iOS)
|
||||
RecentTunnelsTracker.cleanupTunnels(except: tunnelNames)
|
||||
#endif
|
||||
completionHandler(.success(TunnelsManager(tunnelProviders: tunnelManagers)))
|
||||
}
|
||||
#endif
|
||||
@ -104,7 +117,7 @@ class TunnelsManager {
|
||||
}
|
||||
}
|
||||
|
||||
func add(tunnelConfiguration: TunnelConfiguration, onDemandOption: ActivateOnDemandOption = .off, completionHandler: @escaping (WireGuardResult<TunnelContainer>) -> Void) {
|
||||
func add(tunnelConfiguration: TunnelConfiguration, onDemandOption: ActivateOnDemandOption = .off, completionHandler: @escaping (Result<TunnelContainer, TunnelsManagerError>) -> Void) {
|
||||
let tunnelName = tunnelConfiguration.name ?? ""
|
||||
if tunnelName.isEmpty {
|
||||
completionHandler(.failure(TunnelsManagerError.tunnelNameEmpty))
|
||||
@ -167,9 +180,15 @@ class TunnelsManager {
|
||||
let tail = tunnelConfigurations.dropFirst()
|
||||
add(tunnelConfiguration: head) { [weak self, tail] result in
|
||||
DispatchQueue.main.async {
|
||||
let numberSuccessful = numberSuccessful + (result.isSuccess ? 1 : 0)
|
||||
let lastError = lastError ?? (result.error as? TunnelsManagerError)
|
||||
self?.addMultiple(tunnelConfigurations: tail, numberSuccessful: numberSuccessful, lastError: lastError, completionHandler: completionHandler)
|
||||
var numberSuccessfulCount = numberSuccessful
|
||||
var lastError: TunnelsManagerError?
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
lastError = error
|
||||
case .success:
|
||||
numberSuccessfulCount = numberSuccessful + 1
|
||||
}
|
||||
self?.addMultiple(tunnelConfigurations: tail, numberSuccessful: numberSuccessfulCount, lastError: lastError, completionHandler: completionHandler)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -182,7 +201,8 @@ class TunnelsManager {
|
||||
}
|
||||
|
||||
let tunnelProviderManager = tunnel.tunnelProvider
|
||||
let isNameChanged = tunnelName != tunnelProviderManager.localizedDescription
|
||||
let oldName = tunnelProviderManager.localizedDescription ?? ""
|
||||
let isNameChanged = tunnelName != oldName
|
||||
if isNameChanged {
|
||||
guard !tunnels.contains(where: { $0.name == tunnelName }) else {
|
||||
completionHandler(TunnelsManagerError.tunnelAlreadyExistsWithThatName)
|
||||
@ -214,6 +234,9 @@ class TunnelsManager {
|
||||
self.tunnels.sort { TunnelsManager.tunnelNameIsLessThan($0.name, $1.name) }
|
||||
let newIndex = self.tunnels.firstIndex(of: tunnel)!
|
||||
self.tunnelsListDelegate?.tunnelMoved(from: oldIndex, to: newIndex)
|
||||
#if os(iOS)
|
||||
RecentTunnelsTracker.handleTunnelRenamed(oldName: oldName, newName: tunnelName)
|
||||
#endif
|
||||
}
|
||||
self.tunnelsListDelegate?.tunnelModified(at: self.tunnels.firstIndex(of: tunnel)!)
|
||||
|
||||
@ -245,10 +268,15 @@ class TunnelsManager {
|
||||
|
||||
func remove(tunnel: TunnelContainer, completionHandler: @escaping (TunnelsManagerError?) -> Void) {
|
||||
let tunnelProviderManager = tunnel.tunnelProvider
|
||||
if tunnel.isTunnelConfigurationAvailableInKeychain {
|
||||
#if os(macOS)
|
||||
if tunnel.isTunnelAvailableToUser {
|
||||
(tunnelProviderManager.protocolConfiguration as? NETunnelProviderProtocol)?.destroyConfigurationReference()
|
||||
}
|
||||
|
||||
#elseif os(iOS)
|
||||
(tunnelProviderManager.protocolConfiguration as? NETunnelProviderProtocol)?.destroyConfigurationReference()
|
||||
#else
|
||||
#error("Unimplemented")
|
||||
#endif
|
||||
tunnelProviderManager.removeFromPreferences { [weak self] error in
|
||||
guard error == nil else {
|
||||
wg_log(.error, message: "Remove: Saving configuration failed: \(error!)")
|
||||
@ -260,6 +288,10 @@ class TunnelsManager {
|
||||
self.tunnelsListDelegate?.tunnelRemoved(at: index, tunnel: tunnel)
|
||||
}
|
||||
completionHandler(nil)
|
||||
|
||||
#if os(iOS)
|
||||
RecentTunnelsTracker.handleTunnelRemoved(tunnelName: tunnel.name)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -292,6 +324,10 @@ class TunnelsManager {
|
||||
return tunnels[index]
|
||||
}
|
||||
|
||||
func mapTunnels<T>(transform: (TunnelContainer) throws -> T) rethrows -> [T] {
|
||||
return try tunnels.map(transform)
|
||||
}
|
||||
|
||||
func index(of tunnel: TunnelContainer) -> Int? {
|
||||
return tunnels.firstIndex(of: tunnel)
|
||||
}
|
||||
@ -337,6 +373,10 @@ class TunnelsManager {
|
||||
#else
|
||||
tunnel.startActivation(activationDelegate: activationDelegate)
|
||||
#endif
|
||||
|
||||
#if os(iOS)
|
||||
RecentTunnelsTracker.handleTunnelActivated(tunnelName: tunnel.name)
|
||||
#endif
|
||||
}
|
||||
|
||||
func startDeactivation(of tunnel: TunnelContainer) {
|
||||
@ -464,14 +504,16 @@ class TunnelContainer: NSObject {
|
||||
return tunnelProvider.tunnelConfiguration
|
||||
}
|
||||
|
||||
var isTunnelConfigurationAvailableInKeychain: Bool {
|
||||
return tunnelProvider.isTunnelConfigurationAvailableInKeychain
|
||||
}
|
||||
|
||||
var onDemandOption: ActivateOnDemandOption {
|
||||
return ActivateOnDemandOption(from: tunnelProvider)
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
var isTunnelAvailableToUser: Bool {
|
||||
return (tunnelProvider.protocolConfiguration as? NETunnelProviderProtocol)?.providerConfiguration?["UID"] as? uid_t == getuid()
|
||||
}
|
||||
#endif
|
||||
|
||||
init(tunnel: NETunnelProviderManager) {
|
||||
name = tunnel.localizedDescription ?? "Unnamed"
|
||||
let status = TunnelStatus(from: tunnel.connection.status)
|
||||
@ -580,18 +622,8 @@ class TunnelContainer: NSObject {
|
||||
}
|
||||
|
||||
extension NETunnelProviderManager {
|
||||
private static var cachedIsConfigAvailableInKeychainKey: UInt8 = 0
|
||||
private static var cachedConfigKey: UInt8 = 0
|
||||
|
||||
var isTunnelConfigurationAvailableInKeychain: Bool {
|
||||
if let cachedNumber = objc_getAssociatedObject(self, &NETunnelProviderManager.cachedIsConfigAvailableInKeychainKey) as? NSNumber {
|
||||
return cachedNumber.boolValue
|
||||
}
|
||||
let isAvailable = (protocolConfiguration as? NETunnelProviderProtocol)?.verifyConfigurationReference() ?? false
|
||||
objc_setAssociatedObject(self, &NETunnelProviderManager.cachedIsConfigAvailableInKeychainKey, NSNumber(value: isAvailable), objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
return isAvailable
|
||||
}
|
||||
|
||||
var tunnelConfiguration: TunnelConfiguration? {
|
||||
if let cached = objc_getAssociatedObject(self, &NETunnelProviderManager.cachedConfigKey) as? TunnelConfiguration {
|
||||
return cached
|
||||
@ -607,17 +639,9 @@ extension NETunnelProviderManager {
|
||||
protocolConfiguration = NETunnelProviderProtocol(tunnelConfiguration: tunnelConfiguration, previouslyFrom: protocolConfiguration)
|
||||
localizedDescription = tunnelConfiguration.name
|
||||
objc_setAssociatedObject(self, &NETunnelProviderManager.cachedConfigKey, tunnelConfiguration, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
objc_setAssociatedObject(self, &NETunnelProviderManager.cachedIsConfigAvailableInKeychainKey, NSNumber(value: true), objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
|
||||
func isEquivalentTo(_ tunnel: TunnelContainer) -> Bool {
|
||||
switch (isTunnelConfigurationAvailableInKeychain, tunnel.isTunnelConfigurationAvailableInKeychain) {
|
||||
case (true, true):
|
||||
return tunnelConfiguration == tunnel.tunnelConfiguration
|
||||
case (false, false):
|
||||
return localizedDescription == tunnel.name
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return localizedDescription == tunnel.name && tunnelConfiguration == tunnel.tunnelConfiguration
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,10 @@ class TunnelImporter {
|
||||
if url.pathExtension.lowercased() == "zip" {
|
||||
dispatchGroup.enter()
|
||||
ZipImporter.importConfigFiles(from: url) { result in
|
||||
if let error = result.error {
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
lastFileImportErrorText = error.alertText
|
||||
}
|
||||
if let configsInZip = result.value {
|
||||
case .success(let configsInZip):
|
||||
configs.append(contentsOf: configsInZip)
|
||||
}
|
||||
dispatchGroup.leave()
|
||||
@ -44,10 +44,20 @@ class TunnelImporter {
|
||||
}
|
||||
return
|
||||
}
|
||||
let tunnelConfiguration = try? TunnelConfiguration(fromWgQuickConfig: fileContents, called: fileBaseName)
|
||||
var parseError: Error?
|
||||
var tunnelConfiguration: TunnelConfiguration?
|
||||
do {
|
||||
tunnelConfiguration = try TunnelConfiguration(fromWgQuickConfig: fileContents, called: fileBaseName)
|
||||
} catch let error {
|
||||
parseError = error
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
if tunnelConfiguration == nil {
|
||||
lastFileImportErrorText = (title: tr("alertBadConfigImportTitle"), message: tr(format: "alertBadConfigImportMessage (%@)", fileName))
|
||||
if parseError != nil {
|
||||
if let parseError = parseError as? WireGuardAppError {
|
||||
lastFileImportErrorText = parseError.alertText
|
||||
} else {
|
||||
lastFileImportErrorText = (title: tr("alertBadConfigImportTitle"), message: tr(format: "alertBadConfigImportMessage (%@)", fileName))
|
||||
}
|
||||
}
|
||||
configs.append(tunnelConfiguration)
|
||||
dispatchGroup.leave()
|
||||
|
@ -9,10 +9,17 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
var mainVC: MainViewController?
|
||||
var isLaunchedForSpecificAction = false
|
||||
|
||||
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
Logger.configureGlobal(tagged: "APP", withFilePath: FileManager.logFileURL?.path)
|
||||
|
||||
if let launchOptions = launchOptions {
|
||||
if launchOptions[.url] != nil || launchOptions[.shortcutItem] != nil {
|
||||
isLaunchedForSpecificAction = true
|
||||
}
|
||||
}
|
||||
|
||||
let window = UIWindow(frame: UIScreen.main.bounds)
|
||||
window.backgroundColor = .white
|
||||
self.window = window
|
||||
@ -27,16 +34,28 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
}
|
||||
|
||||
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
|
||||
guard let tunnelsManager = mainVC?.tunnelsManager else { return true }
|
||||
TunnelImporter.importFromFile(urls: [url], into: tunnelsManager, sourceVC: mainVC, errorPresenterType: ErrorPresenter.self) {
|
||||
_ = FileManager.deleteFile(at: url)
|
||||
}
|
||||
mainVC?.importFromDisposableFile(url: url)
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
mainVC?.refreshTunnelConnectionStatuses()
|
||||
}
|
||||
|
||||
func applicationWillResignActive(_ application: UIApplication) {
|
||||
guard let allTunnelNames = mainVC?.allTunnelNames() else { return }
|
||||
application.shortcutItems = QuickActionItem.createItems(allTunnelNames: allTunnelNames)
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
|
||||
guard shortcutItem.type == QuickActionItem.type else {
|
||||
completionHandler(false)
|
||||
return
|
||||
}
|
||||
let tunnelName = shortcutItem.localizedTitle
|
||||
mainVC?.showTunnelDetailForTunnel(named: tunnelName, animated: false, shouldToggleStatus: true)
|
||||
completionHandler(true)
|
||||
}
|
||||
}
|
||||
|
||||
extension AppDelegate {
|
||||
@ -45,7 +64,7 @@ extension AppDelegate {
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, shouldRestoreApplicationState coder: NSCoder) -> Bool {
|
||||
return true
|
||||
return !self.isLaunchedForSpecificAction
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, viewControllerWithRestorationIdentifierPath identifierComponents: [String], coder: NSCoder) -> UIViewController? {
|
||||
@ -58,7 +77,7 @@ extension AppDelegate {
|
||||
}
|
||||
} else {
|
||||
// Show it when tunnelsManager is available
|
||||
mainVC?.showTunnelDetailForTunnel(named: tunnelName, animated: false)
|
||||
mainVC?.showTunnelDetailForTunnel(named: tunnelName, animated: false, shouldToggleStatus: false)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -64,6 +64,8 @@
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
|
25
WireGuard/WireGuard/UI/iOS/QuickActionItem.swift
Normal file
@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
||||
|
||||
import UIKit
|
||||
|
||||
class QuickActionItem: UIApplicationShortcutItem {
|
||||
static let type = "WireGuardTunnelActivateAndShow"
|
||||
|
||||
init(tunnelName: String) {
|
||||
super.init(type: QuickActionItem.type, localizedTitle: tunnelName, localizedSubtitle: nil, icon: nil, userInfo: nil)
|
||||
}
|
||||
|
||||
static func createItems(allTunnelNames: [String]) -> [QuickActionItem] {
|
||||
let numberOfItems = 10
|
||||
// Currently, only 4 items shown by iOS, but that can increase in the future.
|
||||
// iOS will discard additional items we give it.
|
||||
var tunnelNames = RecentTunnelsTracker.recentlyActivatedTunnelNames(limit: numberOfItems)
|
||||
let numberOfSlotsRemaining = numberOfItems - tunnelNames.count
|
||||
if numberOfSlotsRemaining > 0 {
|
||||
let moreTunnels = allTunnelNames.filter { !tunnelNames.contains($0) }.prefix(numberOfSlotsRemaining)
|
||||
tunnelNames.append(contentsOf: moreTunnels)
|
||||
}
|
||||
return tunnelNames.map { QuickActionItem(tunnelName: $0) }
|
||||
}
|
||||
}
|
72
WireGuard/WireGuard/UI/iOS/RecentTunnelsTracker.swift
Normal file
@ -0,0 +1,72 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
||||
|
||||
import Foundation
|
||||
|
||||
class RecentTunnelsTracker {
|
||||
|
||||
private static let keyRecentlyActivatedTunnelNames = "recentlyActivatedTunnelNames"
|
||||
private static let maxNumberOfTunnels = 10
|
||||
|
||||
private static var userDefaults: UserDefaults? {
|
||||
guard let appGroupId = FileManager.appGroupId else {
|
||||
wg_log(.error, staticMessage: "Cannot obtain app group ID from bundle for tracking recently used tunnels")
|
||||
return nil
|
||||
}
|
||||
guard let userDefaults = UserDefaults(suiteName: appGroupId) else {
|
||||
wg_log(.error, staticMessage: "Cannot obtain shared user defaults for tracking recently used tunnels")
|
||||
return nil
|
||||
}
|
||||
return userDefaults
|
||||
}
|
||||
|
||||
static func handleTunnelActivated(tunnelName: String) {
|
||||
guard let userDefaults = RecentTunnelsTracker.userDefaults else { return }
|
||||
var recentTunnels = userDefaults.stringArray(forKey: keyRecentlyActivatedTunnelNames) ?? []
|
||||
if let existingIndex = recentTunnels.firstIndex(of: tunnelName) {
|
||||
recentTunnels.remove(at: existingIndex)
|
||||
}
|
||||
recentTunnels.insert(tunnelName, at: 0)
|
||||
if recentTunnels.count > maxNumberOfTunnels {
|
||||
recentTunnels.removeLast(recentTunnels.count - maxNumberOfTunnels)
|
||||
}
|
||||
userDefaults.set(recentTunnels, forKey: keyRecentlyActivatedTunnelNames)
|
||||
}
|
||||
|
||||
static func handleTunnelRemoved(tunnelName: String) {
|
||||
guard let userDefaults = RecentTunnelsTracker.userDefaults else { return }
|
||||
var recentTunnels = userDefaults.stringArray(forKey: keyRecentlyActivatedTunnelNames) ?? []
|
||||
if let existingIndex = recentTunnels.firstIndex(of: tunnelName) {
|
||||
recentTunnels.remove(at: existingIndex)
|
||||
userDefaults.set(recentTunnels, forKey: keyRecentlyActivatedTunnelNames)
|
||||
}
|
||||
}
|
||||
|
||||
static func handleTunnelRenamed(oldName: String, newName: String) {
|
||||
guard let userDefaults = RecentTunnelsTracker.userDefaults else { return }
|
||||
var recentTunnels = userDefaults.stringArray(forKey: keyRecentlyActivatedTunnelNames) ?? []
|
||||
if let existingIndex = recentTunnels.firstIndex(of: oldName) {
|
||||
recentTunnels[existingIndex] = newName
|
||||
userDefaults.set(recentTunnels, forKey: keyRecentlyActivatedTunnelNames)
|
||||
}
|
||||
}
|
||||
|
||||
static func cleanupTunnels(except tunnelNamesToKeep: Set<String>) {
|
||||
guard let userDefaults = RecentTunnelsTracker.userDefaults else { return }
|
||||
var recentTunnels = userDefaults.stringArray(forKey: keyRecentlyActivatedTunnelNames) ?? []
|
||||
let oldCount = recentTunnels.count
|
||||
recentTunnels.removeAll { !tunnelNamesToKeep.contains($0) }
|
||||
if oldCount != recentTunnels.count {
|
||||
userDefaults.set(recentTunnels, forKey: keyRecentlyActivatedTunnelNames)
|
||||
}
|
||||
}
|
||||
|
||||
static func recentlyActivatedTunnelNames(limit: Int) -> [String] {
|
||||
guard let userDefaults = RecentTunnelsTracker.userDefaults else { return [] }
|
||||
var recentTunnels = userDefaults.stringArray(forKey: keyRecentlyActivatedTunnelNames) ?? []
|
||||
if limit < recentTunnels.count {
|
||||
recentTunnels.removeLast(recentTunnels.count - limit)
|
||||
}
|
||||
return recentTunnels
|
||||
}
|
||||
}
|
@ -20,6 +20,15 @@ class LogViewController: UIViewController {
|
||||
return busyIndicator
|
||||
}()
|
||||
|
||||
let paragraphStyle: NSParagraphStyle = {
|
||||
let paragraphStyle = NSMutableParagraphStyle()
|
||||
paragraphStyle.setParagraphStyle(NSParagraphStyle.default)
|
||||
paragraphStyle.lineHeightMultiple = 1.2
|
||||
return paragraphStyle
|
||||
}()
|
||||
|
||||
var isNextLineHighlighted = false
|
||||
|
||||
var logViewHelper: LogViewHelper?
|
||||
var isFetchingLogEntries = false
|
||||
private var updateLogEntriesTimer: Timer?
|
||||
@ -68,9 +77,20 @@ class LogViewController: UIViewController {
|
||||
}
|
||||
guard !fetchedLogEntries.isEmpty else { return }
|
||||
let isScrolledToEnd = self.textView.contentSize.height - self.textView.bounds.height - self.textView.contentOffset.y < 1
|
||||
let text = fetchedLogEntries.reduce("") { $0 + $1.text() + "\n" }
|
||||
let font = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.body)
|
||||
let richText = NSAttributedString(string: text, attributes: [.font: font])
|
||||
|
||||
let richText = NSMutableAttributedString()
|
||||
let bodyFont = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.body)
|
||||
let captionFont = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.caption1)
|
||||
let lightGrayColor = UIColor(white: 0.88, alpha: 1.0)
|
||||
|
||||
for logEntry in fetchedLogEntries {
|
||||
let bgColor = self.isNextLineHighlighted ? lightGrayColor : UIColor.white
|
||||
let timestampText = NSAttributedString(string: logEntry.timestamp + "\n", attributes: [.font: captionFont, .backgroundColor: bgColor, .paragraphStyle: self.paragraphStyle])
|
||||
let messageText = NSAttributedString(string: logEntry.message + "\n", attributes: [.font: bodyFont, .backgroundColor: bgColor, .paragraphStyle: self.paragraphStyle])
|
||||
richText.append(timestampText)
|
||||
richText.append(messageText)
|
||||
self.isNextLineHighlighted.toggle()
|
||||
}
|
||||
self.textView.textStorage.append(richText)
|
||||
if isScrolledToEnd {
|
||||
let endOfCurrentText = NSRange(location: (self.textView.text as NSString).length, length: 0)
|
||||
|
@ -42,22 +42,25 @@ class MainViewController: UISplitViewController {
|
||||
TunnelsManager.create { [weak self] result in
|
||||
guard let self = self else { return }
|
||||
|
||||
if let error = result.error {
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
ErrorPresenter.showErrorAlert(error: error, from: self)
|
||||
return
|
||||
case .success(let tunnelsManager):
|
||||
self.tunnelsManager = tunnelsManager
|
||||
self.tunnelsListVC?.setTunnelsManager(tunnelsManager: tunnelsManager)
|
||||
|
||||
tunnelsManager.activationDelegate = self
|
||||
|
||||
self.onTunnelsManagerReady?(tunnelsManager)
|
||||
self.onTunnelsManagerReady = nil
|
||||
}
|
||||
let tunnelsManager: TunnelsManager = result.value!
|
||||
|
||||
self.tunnelsManager = tunnelsManager
|
||||
self.tunnelsListVC?.setTunnelsManager(tunnelsManager: tunnelsManager)
|
||||
|
||||
tunnelsManager.activationDelegate = self
|
||||
|
||||
self.onTunnelsManagerReady?(tunnelsManager)
|
||||
self.onTunnelsManagerReady = nil
|
||||
}
|
||||
}
|
||||
|
||||
func allTunnelNames() -> [String]? {
|
||||
guard let tunnelsManager = self.tunnelsManager else { return nil }
|
||||
return tunnelsManager.mapTunnels { $0.name }
|
||||
}
|
||||
}
|
||||
|
||||
extension MainViewController: TunnelsManagerActivationDelegate {
|
||||
@ -85,19 +88,17 @@ extension MainViewController {
|
||||
}
|
||||
}
|
||||
|
||||
func showTunnelDetailForTunnel(named tunnelName: String, animated: Bool) {
|
||||
func showTunnelDetailForTunnel(named tunnelName: String, animated: Bool, shouldToggleStatus: Bool) {
|
||||
let showTunnelDetailBlock: (TunnelsManager) -> Void = { [weak self] tunnelsManager in
|
||||
guard let self = self else { return }
|
||||
guard let tunnelsListVC = self.tunnelsListVC else { return }
|
||||
if let tunnel = tunnelsManager.tunnel(named: tunnelName) {
|
||||
let tunnelDetailVC = TunnelDetailTableViewController(tunnelsManager: tunnelsManager, tunnel: tunnel)
|
||||
let tunnelDetailNC = UINavigationController(rootViewController: tunnelDetailVC)
|
||||
tunnelDetailNC.restorationIdentifier = "DetailNC"
|
||||
if let self = self {
|
||||
if animated {
|
||||
self.showDetailViewController(tunnelDetailNC, sender: self)
|
||||
} else {
|
||||
UIView.performWithoutAnimation {
|
||||
self.showDetailViewController(tunnelDetailNC, sender: self)
|
||||
}
|
||||
tunnelsListVC.showTunnelDetail(for: tunnel, animated: false)
|
||||
if shouldToggleStatus {
|
||||
if tunnel.status == .inactive {
|
||||
tunnelsManager.startActivation(of: tunnel)
|
||||
} else if tunnel.status == .active {
|
||||
tunnelsManager.startDeactivation(of: tunnel)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -108,6 +109,19 @@ extension MainViewController {
|
||||
onTunnelsManagerReady = showTunnelDetailBlock
|
||||
}
|
||||
}
|
||||
|
||||
func importFromDisposableFile(url: URL) {
|
||||
let importFromFileBlock: (TunnelsManager) -> Void = { [weak self] tunnelsManager in
|
||||
TunnelImporter.importFromFile(urls: [url], into: tunnelsManager, sourceVC: self, errorPresenterType: ErrorPresenter.self) {
|
||||
_ = FileManager.deleteFile(at: url)
|
||||
}
|
||||
}
|
||||
if let tunnelsManager = tunnelsManager {
|
||||
importFromFileBlock(tunnelsManager)
|
||||
} else {
|
||||
onTunnelsManagerReady = importFromFileBlock
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension MainViewController: UISplitViewControllerDelegate {
|
||||
|
@ -266,6 +266,10 @@ extension SSIDOptionEditTableViewController {
|
||||
case .ssidOption:
|
||||
let previousOption = selectedOption
|
||||
selectedOption = ssidOptionFields[indexPath.row]
|
||||
guard previousOption != selectedOption else {
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
return
|
||||
}
|
||||
loadSections()
|
||||
if previousOption == .anySSID {
|
||||
let indexSet = IndexSet(1 ... 2)
|
||||
|
@ -11,6 +11,7 @@ class SettingsTableViewController: UITableViewController {
|
||||
case goBackendVersion
|
||||
case exportZipArchive
|
||||
case viewLog
|
||||
case donateLink
|
||||
|
||||
var localizedUIString: String {
|
||||
switch self {
|
||||
@ -18,12 +19,13 @@ class SettingsTableViewController: UITableViewController {
|
||||
case .goBackendVersion: return tr("settingsVersionKeyWireGuardGoBackend")
|
||||
case .exportZipArchive: return tr("settingsExportZipButtonTitle")
|
||||
case .viewLog: return tr("settingsViewLogButtonTitle")
|
||||
case .donateLink: return tr("donateLink")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let settingsFieldsBySection: [[SettingsFields]] = [
|
||||
[.iosAppVersion, .goBackendVersion],
|
||||
[.iosAppVersion, .goBackendVersion, .donateLink],
|
||||
[.exportZipArchive],
|
||||
[.viewLog]
|
||||
]
|
||||
@ -160,14 +162,23 @@ extension SettingsTableViewController {
|
||||
self?.exportConfigurationsAsZipFile(sourceView: cell.button)
|
||||
}
|
||||
return cell
|
||||
} else {
|
||||
assert(field == .viewLog)
|
||||
} else if field == .viewLog {
|
||||
let cell: ButtonCell = tableView.dequeueReusableCell(for: indexPath)
|
||||
cell.buttonText = field.localizedUIString
|
||||
cell.onTapped = { [weak self] in
|
||||
self?.presentLogView()
|
||||
}
|
||||
return cell
|
||||
} else if field == .donateLink {
|
||||
let cell: ButtonCell = tableView.dequeueReusableCell(for: indexPath)
|
||||
cell.buttonText = field.localizedUIString
|
||||
cell.onTapped = {
|
||||
if let url = URL(string: "https://www.wireguard.com/donations/"), UIApplication.shared.canOpenURL(url) {
|
||||
UIApplication.shared.open(url, options: [:])
|
||||
}
|
||||
}
|
||||
return cell
|
||||
}
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
@ -127,10 +127,10 @@ class TunnelEditTableViewController: UITableViewController {
|
||||
} else {
|
||||
// We're adding a new tunnel
|
||||
tunnelsManager.add(tunnelConfiguration: tunnelConfiguration, onDemandOption: onDemandOption) { [weak self] result in
|
||||
if let error = result.error {
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
ErrorPresenter.showErrorAlert(error: error, from: self)
|
||||
} else {
|
||||
let tunnel: TunnelContainer = result.value!
|
||||
case .success(let tunnel):
|
||||
self?.dismiss(animated: true, completion: nil)
|
||||
self?.delegate?.tunnelSaved(tunnel: tunnel)
|
||||
}
|
||||
|
@ -251,6 +251,24 @@ class TunnelsListTableViewController: UIViewController {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func showTunnelDetail(for tunnel: TunnelContainer, animated: Bool) {
|
||||
guard let tunnelsManager = tunnelsManager else { return }
|
||||
guard let splitViewController = splitViewController else { return }
|
||||
guard let navController = navigationController else { return }
|
||||
|
||||
let tunnelDetailVC = TunnelDetailTableViewController(tunnelsManager: tunnelsManager,
|
||||
tunnel: tunnel)
|
||||
let tunnelDetailNC = UINavigationController(rootViewController: tunnelDetailVC)
|
||||
tunnelDetailNC.restorationIdentifier = "DetailNC"
|
||||
if splitViewController.isCollapsed && navController.viewControllers.count > 1 {
|
||||
navController.setViewControllers([self, tunnelDetailNC], animated: animated)
|
||||
} else {
|
||||
splitViewController.showDetailViewController(tunnelDetailNC, sender: self, animated: animated)
|
||||
}
|
||||
detailDisplayedTunnel = tunnel
|
||||
self.presentedViewController?.dismiss(animated: false, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
extension TunnelsListTableViewController: UIDocumentPickerDelegate {
|
||||
@ -264,9 +282,10 @@ extension TunnelsListTableViewController: QRScanViewControllerDelegate {
|
||||
func addScannedQRCode(tunnelConfiguration: TunnelConfiguration, qrScanViewController: QRScanViewController,
|
||||
completionHandler: (() -> Void)?) {
|
||||
tunnelsManager?.add(tunnelConfiguration: tunnelConfiguration) { result in
|
||||
if let error = result.error {
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
ErrorPresenter.showErrorAlert(error: error, from: qrScanViewController, onDismissal: completionHandler)
|
||||
} else {
|
||||
case .success:
|
||||
completionHandler?()
|
||||
}
|
||||
}
|
||||
@ -308,12 +327,7 @@ extension TunnelsListTableViewController: UITableViewDelegate {
|
||||
}
|
||||
guard let tunnelsManager = tunnelsManager else { return }
|
||||
let tunnel = tunnelsManager.tunnel(at: indexPath.row)
|
||||
let tunnelDetailVC = TunnelDetailTableViewController(tunnelsManager: tunnelsManager,
|
||||
tunnel: tunnel)
|
||||
let tunnelDetailNC = UINavigationController(rootViewController: tunnelDetailVC)
|
||||
tunnelDetailNC.restorationIdentifier = "DetailNC"
|
||||
showDetailViewController(tunnelDetailNC, sender: self) // Shall get propagated up to the split-vc
|
||||
detailDisplayedTunnel = tunnel
|
||||
showTunnelDetail(for: tunnel, animated: true)
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
|
||||
@ -386,3 +400,15 @@ extension TunnelsListTableViewController: TunnelsManagerListDelegate {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UISplitViewController {
|
||||
func showDetailViewController(_ vc: UIViewController, sender: Any?, animated: Bool) {
|
||||
if animated {
|
||||
showDetailViewController(vc, sender: sender)
|
||||
} else {
|
||||
UIView.performWithoutAnimation {
|
||||
showDetailViewController(vc, sender: sender)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,33 +13,95 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
|
||||
var manageTunnelsRootVC: ManageTunnelsRootViewController?
|
||||
var manageTunnelsWindowObject: NSWindow?
|
||||
var onAppDeactivation: (() -> Void)?
|
||||
|
||||
func applicationWillFinishLaunching(_ notification: Notification) {
|
||||
// To workaround a possible AppKit bug that causes the main menu to become unresponsive sometimes
|
||||
// (especially when launched through Xcode) if we call setActivationPolicy(.regular) in
|
||||
// in applicationDidFinishLaunching, we set it to .prohibited here.
|
||||
// Setting it to .regular would fix that problem too, but at this point, we don't know
|
||||
// whether the app was launched at login or not, so we're not sure whether we should
|
||||
// show the app icon in the dock or not.
|
||||
NSApp.setActivationPolicy(.prohibited)
|
||||
}
|
||||
|
||||
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
||||
Logger.configureGlobal(tagged: "APP", withFilePath: FileManager.logFileURL?.path)
|
||||
registerLoginItem(shouldLaunchAtLogin: true)
|
||||
|
||||
var isLaunchedAtLogin = false
|
||||
if let appleEvent = NSAppleEventManager.shared().currentAppleEvent {
|
||||
isLaunchedAtLogin = LaunchedAtLoginDetector.isLaunchedAtLogin(openAppleEvent: appleEvent)
|
||||
}
|
||||
|
||||
NSApp.mainMenu = MainMenu()
|
||||
setDockIconAndMainMenuVisibility(isVisible: !isLaunchedAtLogin)
|
||||
|
||||
TunnelsManager.create { [weak self] result in
|
||||
guard let self = self else { return }
|
||||
if let error = result.error {
|
||||
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
ErrorPresenter.showErrorAlert(error: error, from: nil)
|
||||
return
|
||||
case .success(let tunnelsManager):
|
||||
let statusMenu = StatusMenu(tunnelsManager: tunnelsManager)
|
||||
statusMenu.windowDelegate = self
|
||||
|
||||
let statusItemController = StatusItemController()
|
||||
statusItemController.statusItem.menu = statusMenu
|
||||
|
||||
let tunnelsTracker = TunnelsTracker(tunnelsManager: tunnelsManager)
|
||||
tunnelsTracker.statusMenu = statusMenu
|
||||
tunnelsTracker.statusItemController = statusItemController
|
||||
|
||||
self.tunnelsManager = tunnelsManager
|
||||
self.tunnelsTracker = tunnelsTracker
|
||||
self.statusItemController = statusItemController
|
||||
|
||||
if !isLaunchedAtLogin {
|
||||
self.showManageTunnelsWindow(completion: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let tunnelsManager: TunnelsManager = result.value!
|
||||
func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows: Bool) -> Bool {
|
||||
if let appleEvent = NSAppleEventManager.shared().currentAppleEvent {
|
||||
if LaunchedAtLoginDetector.isReopenedByLoginItemHelper(reopenAppleEvent: appleEvent) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if hasVisibleWindows {
|
||||
return true
|
||||
}
|
||||
showManageTunnelsWindow(completion: nil)
|
||||
return false
|
||||
}
|
||||
|
||||
let statusMenu = StatusMenu(tunnelsManager: tunnelsManager)
|
||||
statusMenu.windowDelegate = self
|
||||
@objc func confirmAndQuit() {
|
||||
let alert = NSAlert()
|
||||
alert.messageText = tr("macConfirmAndQuitAlertMessage")
|
||||
if let currentTunnel = tunnelsTracker?.currentTunnel, currentTunnel.status == .active || currentTunnel.status == .activating {
|
||||
alert.informativeText = tr(format: "macConfirmAndQuitInfoWithActiveTunnel (%@)", currentTunnel.name)
|
||||
} else {
|
||||
alert.informativeText = tr("macConfirmAndQuitAlertInfo")
|
||||
}
|
||||
alert.addButton(withTitle: tr("macConfirmAndQuitAlertCloseWindow"))
|
||||
alert.addButton(withTitle: tr("macConfirmAndQuitAlertQuitWireGuard"))
|
||||
|
||||
let statusItemController = StatusItemController()
|
||||
statusItemController.statusItem.menu = statusMenu
|
||||
|
||||
let tunnelsTracker = TunnelsTracker(tunnelsManager: tunnelsManager)
|
||||
tunnelsTracker.statusMenu = statusMenu
|
||||
tunnelsTracker.statusItemController = statusItemController
|
||||
|
||||
self.tunnelsManager = tunnelsManager
|
||||
self.tunnelsTracker = tunnelsTracker
|
||||
self.statusItemController = statusItemController
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
if let manageWindow = manageTunnelsWindowObject {
|
||||
manageWindow.orderFront(self)
|
||||
alert.beginSheetModal(for: manageWindow) { response in
|
||||
switch response {
|
||||
case .alertFirstButtonReturn:
|
||||
manageWindow.close()
|
||||
case .alertSecondButtonReturn:
|
||||
NSApp.terminate(nil)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,12 +130,105 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
NSApp.terminate(nil)
|
||||
}
|
||||
}
|
||||
|
||||
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
|
||||
guard let currentTunnel = tunnelsTracker?.currentTunnel, currentTunnel.status == .active || currentTunnel.status == .activating else {
|
||||
return .terminateNow
|
||||
}
|
||||
guard let appleEvent = NSAppleEventManager.shared().currentAppleEvent else {
|
||||
return .terminateNow
|
||||
}
|
||||
guard MacAppStoreUpdateDetector.isUpdatingFromMacAppStore(quitAppleEvent: appleEvent) else {
|
||||
return .terminateNow
|
||||
}
|
||||
let alert = NSAlert()
|
||||
alert.messageText = tr("macAppStoreUpdatingAlertMessage")
|
||||
if currentTunnel.isActivateOnDemandEnabled {
|
||||
alert.informativeText = tr(format: "macAppStoreUpdatingAlertInfoWithOnDemand (%@)", currentTunnel.name)
|
||||
} else {
|
||||
alert.informativeText = tr(format: "macAppStoreUpdatingAlertInfoWithoutOnDemand (%@)", currentTunnel.name)
|
||||
}
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
if let manageWindow = manageTunnelsWindowObject {
|
||||
alert.beginSheetModal(for: manageWindow) { _ in }
|
||||
} else {
|
||||
alert.runModal()
|
||||
}
|
||||
return .terminateCancel
|
||||
}
|
||||
|
||||
func applicationShouldTerminateAfterLastWindowClosed(_ application: NSApplication) -> Bool {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(200)) { [weak self] in
|
||||
self?.setDockIconAndMainMenuVisibility(isVisible: false)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private func setDockIconAndMainMenuVisibility(isVisible: Bool, completion: (() -> Void)? = nil) {
|
||||
let currentActivationPolicy = NSApp.activationPolicy()
|
||||
let newActivationPolicy: NSApplication.ActivationPolicy = isVisible ? .regular : .accessory
|
||||
guard currentActivationPolicy != newActivationPolicy else {
|
||||
if newActivationPolicy == .regular {
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
}
|
||||
completion?()
|
||||
return
|
||||
}
|
||||
if newActivationPolicy == .regular && NSApp.isActive {
|
||||
// To workaround a possible AppKit bug that causes the main menu to become unresponsive,
|
||||
// we should deactivate the app first and then set the activation policy.
|
||||
// NSApp.deactivate() doesn't always deactivate the app, so we instead use
|
||||
// setActivationPolicy(.prohibited).
|
||||
onAppDeactivation = {
|
||||
NSApp.setActivationPolicy(.regular)
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
completion?()
|
||||
}
|
||||
NSApp.setActivationPolicy(.prohibited)
|
||||
} else {
|
||||
NSApp.setActivationPolicy(newActivationPolicy)
|
||||
if newActivationPolicy == .regular {
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
}
|
||||
completion?()
|
||||
}
|
||||
}
|
||||
|
||||
func applicationDidResignActive(_ notification: Notification) {
|
||||
onAppDeactivation?()
|
||||
onAppDeactivation = nil
|
||||
}
|
||||
}
|
||||
|
||||
extension AppDelegate {
|
||||
@objc func aboutClicked() {
|
||||
var appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown"
|
||||
if let appBuild = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
|
||||
appVersion += " (\(appBuild))"
|
||||
}
|
||||
let appVersionString = [
|
||||
tr(format: "macAppVersion (%@)", appVersion),
|
||||
tr(format: "macGoBackendVersion (%@)", WIREGUARD_GO_VERSION)
|
||||
].joined(separator: "\n")
|
||||
let donateString = NSMutableAttributedString(string: tr("donateLink"))
|
||||
donateString.addAttribute(.link, value: "https://www.wireguard.com/donations/", range: NSRange(location: 0, length: donateString.length))
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
NSApp.orderFrontStandardAboutPanel(options: [
|
||||
.applicationVersion: appVersionString,
|
||||
.version: "",
|
||||
.credits: donateString
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
extension AppDelegate: StatusMenuWindowDelegate {
|
||||
func manageTunnelsWindow() -> NSWindow {
|
||||
func showManageTunnelsWindow(completion: ((NSWindow?) -> Void)?) {
|
||||
guard let tunnelsManager = tunnelsManager else {
|
||||
completion?(nil)
|
||||
return
|
||||
}
|
||||
if manageTunnelsWindowObject == nil {
|
||||
manageTunnelsRootVC = ManageTunnelsRootViewController(tunnelsManager: tunnelsManager!)
|
||||
manageTunnelsRootVC = ManageTunnelsRootViewController(tunnelsManager: tunnelsManager)
|
||||
let window = NSWindow(contentViewController: manageTunnelsRootVC!)
|
||||
window.title = tr("macWindowTitleManageTunnels")
|
||||
window.setContentSize(NSSize(width: 800, height: 480))
|
||||
@ -81,7 +236,10 @@ extension AppDelegate: StatusMenuWindowDelegate {
|
||||
manageTunnelsWindowObject = window
|
||||
tunnelsTracker?.manageTunnelsRootVC = manageTunnelsRootVC
|
||||
}
|
||||
return manageTunnelsWindowObject!
|
||||
setDockIconAndMainMenuVisibility(isVisible: true) { [weak manageTunnelsWindowObject] in
|
||||
manageTunnelsWindowObject?.makeKeyAndOrderFront(self)
|
||||
completion?(manageTunnelsWindowObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,18 +5,6 @@ import Cocoa
|
||||
|
||||
class Application: NSApplication {
|
||||
|
||||
private let characterKeyCommands = [
|
||||
"x": #selector(NSText.cut(_:)),
|
||||
"c": #selector(NSText.copy(_:)),
|
||||
"v": #selector(NSText.paste(_:)),
|
||||
"z": #selector(UndoActionRespondable.undo(_:)),
|
||||
"a": #selector(NSResponder.selectAll(_:)),
|
||||
"Z": #selector(UndoActionRespondable.redo(_:)),
|
||||
"w": #selector(NSWindow.performClose(_:)),
|
||||
"m": #selector(NSWindow.performMiniaturize(_:)),
|
||||
"q": #selector(AppDelegate.quit)
|
||||
]
|
||||
|
||||
private var appDelegate: AppDelegate? //swiftlint:disable:this weak_delegate
|
||||
|
||||
override init() {
|
||||
@ -28,21 +16,4 @@ class Application: NSApplication {
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func sendEvent(_ event: NSEvent) {
|
||||
let modifierFlags = event.modifierFlags.rawValue & NSEvent.ModifierFlags.deviceIndependentFlagsMask.rawValue
|
||||
|
||||
if event.type == .keyDown,
|
||||
(modifierFlags == NSEvent.ModifierFlags.command.rawValue || modifierFlags == NSEvent.ModifierFlags.command.rawValue | NSEvent.ModifierFlags.shift.rawValue),
|
||||
let selector = characterKeyCommands[event.charactersIgnoringModifiers ?? ""] {
|
||||
sendAction(selector, to: nil, from: self)
|
||||
} else {
|
||||
super.sendEvent(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc protocol UndoActionRespondable {
|
||||
func undo(_ sender: AnyObject)
|
||||
func redo(_ sender: AnyObject)
|
||||
}
|
||||
|
@ -65,4 +65,4 @@
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 88 KiB |
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 995 B After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.9 KiB |
28
WireGuard/WireGuard/UI/macOS/LaunchedAtLoginDetector.swift
Normal file
@ -0,0 +1,28 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
||||
|
||||
import Cocoa
|
||||
|
||||
class LaunchedAtLoginDetector {
|
||||
static let launchCode = "LaunchedByWireGuardLoginItemHelper"
|
||||
|
||||
static func isLaunchedAtLogin(openAppleEvent: NSAppleEventDescriptor) -> Bool {
|
||||
guard isOpenEvent(openAppleEvent) else { return false }
|
||||
guard let propData = openAppleEvent.paramDescriptor(forKeyword: keyAEPropData) else { return false }
|
||||
return propData.stringValue == launchCode
|
||||
}
|
||||
|
||||
static func isReopenedByLoginItemHelper(reopenAppleEvent: NSAppleEventDescriptor) -> Bool {
|
||||
guard isReopenEvent(reopenAppleEvent) else { return false }
|
||||
guard let propData = reopenAppleEvent.paramDescriptor(forKeyword: keyAEPropData) else { return false }
|
||||
return propData.stringValue == launchCode
|
||||
}
|
||||
}
|
||||
|
||||
private func isOpenEvent(_ event: NSAppleEventDescriptor) -> Bool {
|
||||
return event.eventClass == kCoreEventClass && event.eventID == kAEOpenApplication
|
||||
}
|
||||
|
||||
private func isReopenEvent(_ event: NSAppleEventDescriptor) -> Bool {
|
||||
return event.eventClass == kCoreEventClass && event.eventID == kAEReopenApplication
|
||||
}
|
@ -19,9 +19,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<string>$(VERSION_NAME)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<string>$(VERSION_ID)</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
@ -30,5 +30,7 @@
|
||||
<string>NSApplication</string>
|
||||
<key>LSBackgroundOnly</key>
|
||||
<true/>
|
||||
<key>com.wireguard.macos.app_id</key>
|
||||
<string>$(APP_ID_MACOS)</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -5,12 +5,13 @@
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
NSURL *bundleURL = [NSBundle.mainBundle bundleURL];
|
||||
NSString *appIdInfoDictionaryKey = @"com.wireguard.macos.app_id";
|
||||
NSString *appId = [NSBundle.mainBundle objectForInfoDictionaryKey:appIdInfoDictionaryKey];
|
||||
|
||||
// From <path>/WireGuard.app/Contents/Library/LoginItems/WireGuardLoginItemHelper.app, derive <path>/WireGuard.app
|
||||
for (int i = 0; i < 4; ++i)
|
||||
bundleURL = [bundleURL URLByDeletingLastPathComponent];
|
||||
NSString *launchCode = @"LaunchedByWireGuardLoginItemHelper";
|
||||
NSAppleEventDescriptor *paramDescriptor = [NSAppleEventDescriptor descriptorWithString:launchCode];
|
||||
|
||||
[NSWorkspace.sharedWorkspace launchApplication:[bundleURL path]];
|
||||
[NSWorkspace.sharedWorkspace launchAppWithBundleIdentifier:appId options:NSWorkspaceLaunchWithoutActivation
|
||||
additionalEventParamDescriptor:paramDescriptor launchIdentifier:NULL];
|
||||
return 0;
|
||||
}
|
||||
|
35
WireGuard/WireGuard/UI/macOS/MacAppStoreUpdateDetector.swift
Normal file
@ -0,0 +1,35 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
||||
|
||||
import Cocoa
|
||||
|
||||
class MacAppStoreUpdateDetector {
|
||||
static func isUpdatingFromMacAppStore(quitAppleEvent: NSAppleEventDescriptor) -> Bool {
|
||||
guard isQuitEvent(quitAppleEvent) else { return false }
|
||||
guard let senderPIDDescriptor = quitAppleEvent.attributeDescriptor(forKeyword: keySenderPIDAttr) else { return false }
|
||||
let pid = senderPIDDescriptor.int32Value
|
||||
guard let executablePath = getExecutablePath(from: pid) else { return false }
|
||||
wg_log(.debug, message: "aevt/quit Apple event received from: \(executablePath)")
|
||||
if executablePath.hasPrefix("/System/Library/") {
|
||||
let executableName = URL(fileURLWithPath: executablePath, isDirectory: false).lastPathComponent
|
||||
return executableName == "com.apple.CommerceKit.StoreAEService"
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private func isQuitEvent(_ event: NSAppleEventDescriptor) -> Bool {
|
||||
return event.eventClass == kCoreEventClass && event.eventID == kAEQuitApplication
|
||||
}
|
||||
|
||||
private func getExecutablePath(from pid: pid_t) -> String? {
|
||||
let bufferSize = Int(PATH_MAX)
|
||||
var buffer = Data(capacity: bufferSize)
|
||||
return buffer.withUnsafeMutableBytes { (ptr: UnsafeMutableRawBufferPointer) -> String? in
|
||||
if let basePtr = ptr.baseAddress {
|
||||
let byteCount = proc_pidpath(pid, basePtr, UInt32(bufferSize))
|
||||
return byteCount > 0 ? String(cString: basePtr.bindMemory(to: CChar.self, capacity: bufferSize)) : nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
130
WireGuard/WireGuard/UI/macOS/MainMenu.swift
Normal file
@ -0,0 +1,130 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright © 2018 WireGuard LLC. All Rights Reserved.
|
||||
|
||||
import Cocoa
|
||||
|
||||
// swiftlint:disable colon
|
||||
|
||||
class MainMenu: NSMenu {
|
||||
init() {
|
||||
super.init(title: "")
|
||||
addSubmenu(createApplicationMenu())
|
||||
addSubmenu(createFileMenu())
|
||||
addSubmenu(createEditMenu())
|
||||
addSubmenu(createTunnelMenu())
|
||||
addSubmenu(createWindowMenu())
|
||||
}
|
||||
|
||||
required init(coder decoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
private func addSubmenu(_ menu: NSMenu) {
|
||||
let menuItem = self.addItem(withTitle: "", action: nil, keyEquivalent: "")
|
||||
self.setSubmenu(menu, for: menuItem)
|
||||
}
|
||||
|
||||
private func createApplicationMenu() -> NSMenu {
|
||||
let menu = NSMenu()
|
||||
|
||||
let aboutMenuItem = menu.addItem(withTitle: tr("macMenuAbout"),
|
||||
action: #selector(AppDelegate.aboutClicked), keyEquivalent: "")
|
||||
aboutMenuItem.target = NSApp.delegate
|
||||
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
|
||||
menu.addItem(withTitle: tr("macMenuViewLog"),
|
||||
action: #selector(TunnelsListTableViewController.handleViewLogAction), keyEquivalent: "")
|
||||
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
|
||||
let hideMenuItem = menu.addItem(withTitle: tr("macMenuHideApp"),
|
||||
action: #selector(NSApplication.hide), keyEquivalent: "h")
|
||||
hideMenuItem.target = NSApp
|
||||
let hideOthersMenuItem = menu.addItem(withTitle: tr("macMenuHideOtherApps"),
|
||||
action: #selector(NSApplication.hideOtherApplications), keyEquivalent: "h")
|
||||
hideOthersMenuItem.keyEquivalentModifierMask = [.command, .option]
|
||||
hideOthersMenuItem.target = NSApp
|
||||
let showAllMenuItem = menu.addItem(withTitle: tr("macMenuShowAllApps"),
|
||||
action: #selector(NSApplication.unhideAllApplications), keyEquivalent: "")
|
||||
showAllMenuItem.target = NSApp
|
||||
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
|
||||
menu.addItem(withTitle: tr("macMenuQuit"),
|
||||
action: #selector(AppDelegate.confirmAndQuit), keyEquivalent: "q")
|
||||
|
||||
return menu
|
||||
}
|
||||
|
||||
private func createFileMenu() -> NSMenu {
|
||||
let menu = NSMenu(title: tr("macMenuFile"))
|
||||
|
||||
menu.addItem(withTitle: tr("macMenuAddEmptyTunnel"),
|
||||
action: #selector(TunnelsListTableViewController.handleAddEmptyTunnelAction), keyEquivalent: "n")
|
||||
menu.addItem(withTitle: tr("macMenuImportTunnels"),
|
||||
action: #selector(TunnelsListTableViewController.handleImportTunnelAction), keyEquivalent: "o")
|
||||
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
|
||||
menu.addItem(withTitle: tr("macMenuExportTunnels"),
|
||||
action: #selector(TunnelsListTableViewController.handleExportTunnelsAction), keyEquivalent: "")
|
||||
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
|
||||
menu.addItem(withTitle: tr("macMenuCloseWindow"), action: #selector(NSWindow.performClose(_:)), keyEquivalent:"w")
|
||||
|
||||
return menu
|
||||
}
|
||||
|
||||
private func createEditMenu() -> NSMenu {
|
||||
let menu = NSMenu(title: tr("macMenuEdit"))
|
||||
|
||||
menu.addItem(withTitle: "", action: #selector(UndoActionRespondable.undo(_:)), keyEquivalent:"z")
|
||||
menu.addItem(withTitle: "", action: #selector(UndoActionRespondable.redo(_:)), keyEquivalent:"Z")
|
||||
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
|
||||
menu.addItem(withTitle: tr("macMenuCut"), action: #selector(NSText.cut(_:)), keyEquivalent:"x")
|
||||
menu.addItem(withTitle: tr("macMenuCopy"), action: #selector(NSText.copy(_:)), keyEquivalent:"c")
|
||||
menu.addItem(withTitle: tr("macMenuPaste"), action: #selector(NSText.paste(_:)), keyEquivalent:"v")
|
||||
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
|
||||
menu.addItem(withTitle: tr("macMenuSelectAll"), action: #selector(NSText.selectAll(_:)), keyEquivalent:"a")
|
||||
|
||||
return menu
|
||||
}
|
||||
|
||||
private func createTunnelMenu() -> NSMenu {
|
||||
let menu = NSMenu(title: tr("macMenuTunnel"))
|
||||
|
||||
menu.addItem(withTitle: tr("macMenuToggleStatus"), action: #selector(TunnelDetailTableViewController.handleToggleActiveStatusAction), keyEquivalent:"t")
|
||||
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
|
||||
menu.addItem(withTitle: tr("macMenuEditTunnel"), action: #selector(TunnelDetailTableViewController.handleEditTunnelAction), keyEquivalent:"e")
|
||||
menu.addItem(withTitle: tr("macMenuDeleteSelected"), action: #selector(TunnelsListTableViewController.handleRemoveTunnelAction), keyEquivalent: "")
|
||||
|
||||
return menu
|
||||
}
|
||||
|
||||
private func createWindowMenu() -> NSMenu {
|
||||
let menu = NSMenu(title: tr("macMenuWindow"))
|
||||
|
||||
menu.addItem(withTitle: tr("macMenuMinimize"), action: #selector(NSWindow.performMiniaturize(_:)), keyEquivalent:"m")
|
||||
menu.addItem(withTitle: tr("macMenuZoom"), action: #selector(NSWindow.performZoom(_:)), keyEquivalent:"")
|
||||
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
|
||||
let fullScreenMenuItem = menu.addItem(withTitle: "", action: #selector(NSWindow.toggleFullScreen(_:)), keyEquivalent:"f")
|
||||
fullScreenMenuItem.keyEquivalentModifierMask = [.command, .control]
|
||||
|
||||
return menu
|
||||
}
|
||||
}
|
||||
|
||||
@objc protocol UndoActionRespondable {
|
||||
func undo(_ sender: AnyObject)
|
||||
func redo(_ sender: AnyObject)
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
import Cocoa
|
||||
|
||||
protocol StatusMenuWindowDelegate: class {
|
||||
func manageTunnelsWindow() -> NSWindow
|
||||
func showManageTunnelsWindow(completion: ((NSWindow?) -> Void)?)
|
||||
}
|
||||
|
||||
class StatusMenu: NSMenu {
|
||||
@ -127,8 +127,8 @@ class StatusMenu: NSMenu {
|
||||
}
|
||||
|
||||
func addApplicationItems() {
|
||||
let aboutItem = NSMenuItem(title: tr("macMenuAbout"), action: #selector(aboutClicked), keyEquivalent: "")
|
||||
aboutItem.target = self
|
||||
let aboutItem = NSMenuItem(title: tr("macMenuAbout"), action: #selector(AppDelegate.aboutClicked), keyEquivalent: "")
|
||||
aboutItem.target = NSApp.delegate
|
||||
addItem(aboutItem)
|
||||
let quitItem = NSMenuItem(title: tr("macMenuQuit"), action: #selector(AppDelegate.quit), keyEquivalent: "")
|
||||
quitItem.target = NSApp.delegate
|
||||
@ -151,32 +151,16 @@ class StatusMenu: NSMenu {
|
||||
}
|
||||
|
||||
@objc func manageTunnelsClicked() {
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
guard let manageTunnelsWindow = windowDelegate?.manageTunnelsWindow() else { return }
|
||||
manageTunnelsWindow.makeKeyAndOrderFront(self)
|
||||
windowDelegate?.showManageTunnelsWindow(completion: nil)
|
||||
}
|
||||
|
||||
@objc func importTunnelsClicked() {
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
guard let manageTunnelsWindow = windowDelegate?.manageTunnelsWindow() else { return }
|
||||
manageTunnelsWindow.makeKeyAndOrderFront(self)
|
||||
ImportPanelPresenter.presentImportPanel(tunnelsManager: tunnelsManager, sourceVC: manageTunnelsWindow.contentViewController)
|
||||
}
|
||||
|
||||
@objc func aboutClicked() {
|
||||
var appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown"
|
||||
if let appBuild = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
|
||||
appVersion += " (\(appBuild))"
|
||||
windowDelegate?.showManageTunnelsWindow { [weak self] manageTunnelsWindow in
|
||||
guard let self = self else { return }
|
||||
guard let manageTunnelsWindow = manageTunnelsWindow else { return }
|
||||
ImportPanelPresenter.presentImportPanel(tunnelsManager: self.tunnelsManager,
|
||||
sourceVC: manageTunnelsWindow.contentViewController)
|
||||
}
|
||||
let appVersionString = [
|
||||
tr(format: "macAppVersion (%@)", appVersion),
|
||||
tr(format: "macGoBackendVersion (%@)", WIREGUARD_GO_VERSION)
|
||||
].joined(separator: "\n")
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
NSApp.orderFrontStandardAboutPanel(options: [
|
||||
.applicationVersion: appVersionString,
|
||||
.version: ""
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,7 +168,7 @@ extension StatusMenu {
|
||||
func insertTunnelMenuItem(for tunnel: TunnelContainer, at tunnelIndex: Int) {
|
||||
let menuItem = TunnelMenuItem(tunnel: tunnel, action: #selector(tunnelClicked(sender:)))
|
||||
menuItem.target = self
|
||||
menuItem.isHidden = !tunnel.isTunnelConfigurationAvailableInKeychain
|
||||
menuItem.isHidden = !tunnel.isTunnelAvailableToUser
|
||||
insertItem(menuItem, at: firstTunnelMenuItemIndex + tunnelIndex)
|
||||
if numberOfTunnelMenuItems == 0 {
|
||||
insertItem(NSMenuItem.separator(), at: firstTunnelMenuItemIndex + tunnelIndex + 1)
|
||||
|
@ -3,13 +3,25 @@
|
||||
|
||||
import Cocoa
|
||||
|
||||
class LogViewCell: NSTextField {
|
||||
class LogViewCell: NSTableCellView {
|
||||
var text: String = "" {
|
||||
didSet { textField?.stringValue = text }
|
||||
}
|
||||
|
||||
init() {
|
||||
super.init(frame: .zero)
|
||||
isSelectable = false
|
||||
isEditable = false
|
||||
isBordered = false
|
||||
backgroundColor = .clear
|
||||
|
||||
let textField = NSTextField(wrappingLabelWithString: "")
|
||||
addSubview(textField)
|
||||
textField.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
textField.leadingAnchor.constraint(equalTo: self.leadingAnchor),
|
||||
textField.trailingAnchor.constraint(equalTo: self.trailingAnchor),
|
||||
textField.topAnchor.constraint(equalTo: self.topAnchor),
|
||||
textField.bottomAnchor.constraint(equalTo: self.bottomAnchor)
|
||||
])
|
||||
|
||||
self.textField = textField
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
@ -17,19 +29,19 @@ class LogViewCell: NSTextField {
|
||||
}
|
||||
|
||||
override func prepareForReuse() {
|
||||
stringValue = ""
|
||||
preferredMaxLayoutWidth = 0
|
||||
textField?.stringValue = ""
|
||||
}
|
||||
}
|
||||
|
||||
class LogViewTimestampCell: LogViewCell {
|
||||
override init() {
|
||||
super.init()
|
||||
maximumNumberOfLines = 1
|
||||
lineBreakMode = .byClipping
|
||||
preferredMaxLayoutWidth = 0
|
||||
setContentCompressionResistancePriority(.defaultHigh, for: .vertical)
|
||||
setContentHuggingPriority(.defaultLow, for: .vertical)
|
||||
if let textField = textField {
|
||||
textField.maximumNumberOfLines = 1
|
||||
textField.lineBreakMode = .byClipping
|
||||
textField.setContentCompressionResistancePriority(.defaultHigh, for: .vertical)
|
||||
textField.setContentHuggingPriority(.defaultLow, for: .vertical)
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
@ -40,10 +52,12 @@ class LogViewTimestampCell: LogViewCell {
|
||||
class LogViewMessageCell: LogViewCell {
|
||||
override init() {
|
||||
super.init()
|
||||
maximumNumberOfLines = 0
|
||||
lineBreakMode = .byWordWrapping
|
||||
setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
setContentHuggingPriority(.required, for: .vertical)
|
||||
if let textField = textField {
|
||||
textField.maximumNumberOfLines = 0
|
||||
textField.lineBreakMode = .byWordWrapping
|
||||
textField.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
textField.setContentHuggingPriority(.required, for: .vertical)
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
|
@ -146,7 +146,8 @@ class LogViewController: NSViewController {
|
||||
])
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
containerView.widthAnchor.constraint(equalToConstant: 640),
|
||||
containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: 640),
|
||||
containerView.widthAnchor.constraint(lessThanOrEqualToConstant: 1200),
|
||||
containerView.heightAnchor.constraint(greaterThanOrEqualToConstant: 240)
|
||||
])
|
||||
|
||||
@ -192,6 +193,10 @@ class LogViewController: NSViewController {
|
||||
updateLogEntriesTimer = nil
|
||||
}
|
||||
|
||||
override func viewWillAppear() {
|
||||
view.window?.setFrameAutosaveName(NSWindow.FrameAutosaveName("LogWindow"))
|
||||
}
|
||||
|
||||
override func viewWillDisappear() {
|
||||
super.viewWillDisappear()
|
||||
stopUpdatingLogEntries()
|
||||
@ -220,7 +225,8 @@ class LogViewController: NSViewController {
|
||||
return
|
||||
}
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.dismiss(self)
|
||||
guard let self = self else { return }
|
||||
self.presentingViewController?.dismiss(self)
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,7 +234,7 @@ class LogViewController: NSViewController {
|
||||
}
|
||||
|
||||
@objc func closeClicked() {
|
||||
dismiss(self)
|
||||
presentingViewController?.dismiss(self)
|
||||
}
|
||||
|
||||
@objc func copy(_ sender: Any?) {
|
||||
@ -249,15 +255,20 @@ extension LogViewController: NSTableViewDelegate {
|
||||
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
|
||||
if LogColumn.time.isRepresenting(tableColumn: tableColumn) {
|
||||
let cell: LogViewTimestampCell = tableView.dequeueReusableCell()
|
||||
cell.stringValue = logEntries[row].timestamp
|
||||
cell.text = logEntries[row].timestamp
|
||||
return cell
|
||||
} else if LogColumn.logMessage.isRepresenting(tableColumn: tableColumn) {
|
||||
let cell: LogViewMessageCell = tableView.dequeueReusableCell()
|
||||
cell.stringValue = logEntries[row].message
|
||||
cell.preferredMaxLayoutWidth = tableColumn?.width ?? 0
|
||||
cell.text = logEntries[row].message
|
||||
return cell
|
||||
} else {
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension LogViewController {
|
||||
override func cancelOperation(_ sender: Any?) {
|
||||
closeClicked()
|
||||
}
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ extension ManageTunnelsRootViewController: TunnelsListTableViewControllerDelegat
|
||||
assert(!tunnelIndices.isEmpty)
|
||||
if tunnelIndices.count == 1 {
|
||||
let tunnel = tunnelsManager.tunnel(at: tunnelIndices.first!)
|
||||
if tunnel.isTunnelConfigurationAvailableInKeychain {
|
||||
if tunnel.isTunnelAvailableToUser {
|
||||
let tunnelDetailVC = TunnelDetailTableViewController(tunnelsManager: tunnelsManager, tunnel: tunnel)
|
||||
setTunnelDetailContentVC(tunnelDetailVC)
|
||||
self.tunnelDetailVC = tunnelDetailVC
|
||||
@ -117,25 +117,19 @@ extension ManageTunnelsRootViewController: TunnelsListTableViewControllerDelegat
|
||||
}
|
||||
|
||||
extension ManageTunnelsRootViewController {
|
||||
override func keyDown(with event: NSEvent) {
|
||||
let modifierFlags = event.modifierFlags.rawValue & NSEvent.ModifierFlags.deviceIndependentFlagsMask.rawValue
|
||||
let isCmdOrCmdShiftDown = (modifierFlags == NSEvent.ModifierFlags.command.rawValue || modifierFlags == NSEvent.ModifierFlags.command.rawValue | NSEvent.ModifierFlags.shift.rawValue)
|
||||
|
||||
if event.specialKey == .delete {
|
||||
tunnelsListVC?.handleRemoveTunnelAction()
|
||||
} else if isCmdOrCmdShiftDown {
|
||||
switch event.charactersIgnoringModifiers {
|
||||
case "n":
|
||||
tunnelsListVC?.handleAddEmptyTunnelAction()
|
||||
case "o":
|
||||
tunnelsListVC?.handleImportTunnelAction()
|
||||
case "t":
|
||||
tunnelDetailVC?.handleToggleActiveStatusAction()
|
||||
case "e":
|
||||
tunnelDetailVC?.handleEditTunnelAction()
|
||||
default:
|
||||
break
|
||||
}
|
||||
override func supplementalTarget(forAction action: Selector, sender: Any?) -> Any? {
|
||||
switch action {
|
||||
case #selector(TunnelsListTableViewController.handleViewLogAction),
|
||||
#selector(TunnelsListTableViewController.handleAddEmptyTunnelAction),
|
||||
#selector(TunnelsListTableViewController.handleImportTunnelAction),
|
||||
#selector(TunnelsListTableViewController.handleExportTunnelsAction),
|
||||
#selector(TunnelsListTableViewController.handleRemoveTunnelAction):
|
||||
return tunnelsListVC
|
||||
case #selector(TunnelDetailTableViewController.handleToggleActiveStatusAction),
|
||||
#selector(TunnelDetailTableViewController.handleEditTunnelAction):
|
||||
return tunnelDetailVC
|
||||
default:
|
||||
return super.supplementalTarget(forAction: action, sender: sender)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,9 +101,14 @@ class TunnelDetailTableViewController: NSViewController {
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
updateTableViewModelRowsBySection()
|
||||
updateTableViewModelRows()
|
||||
updateStatus()
|
||||
statusObservationToken = tunnel.observe(\TunnelContainer.status) { [weak self] _, _ in
|
||||
self?.updateStatus()
|
||||
guard let self = self else { return }
|
||||
if tunnel.status == .active {
|
||||
self.startUpdatingRuntimeConfiguration()
|
||||
} else if tunnel.status == .inactive {
|
||||
self.reloadRuntimeConfiguration()
|
||||
self.stopUpdatingRuntimeConfiguration()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -200,15 +205,6 @@ class TunnelDetailTableViewController: NSViewController {
|
||||
tableViewModelRows = tableViewModelRowsBySection.flatMap { $0.filter { $0.isVisible }.map { $0.modelRow } }
|
||||
}
|
||||
|
||||
func updateStatus() {
|
||||
if tunnel.status == .active {
|
||||
startUpdatingRuntimeConfiguration()
|
||||
} else if tunnel.status == .inactive {
|
||||
reloadRuntimeConfiguration()
|
||||
stopUpdatingRuntimeConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func handleEditTunnelAction() {
|
||||
PrivateDataConfirmation.confirmAccess(to: tr("macViewPrivateData")) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
@ -227,6 +223,12 @@ class TunnelDetailTableViewController: NSViewController {
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillAppear() {
|
||||
if tunnel.status == .active {
|
||||
startUpdatingRuntimeConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillDisappear() {
|
||||
super.viewWillDisappear()
|
||||
if let tunnelEditVC = tunnelEditVC {
|
||||
@ -503,7 +505,6 @@ extension TunnelDetailTableViewController: TunnelEditViewControllerDelegate {
|
||||
onDemandViewModel = ActivateOnDemandViewModel(tunnel: tunnel)
|
||||
updateTableViewModelRowsBySection()
|
||||
updateTableViewModelRows()
|
||||
updateStatus()
|
||||
tableView.reloadData()
|
||||
self.tunnelEditVC = nil
|
||||
}
|
||||
|
@ -73,6 +73,8 @@ class TunnelEditViewController: NSViewController {
|
||||
button.title = tr("macEditSave")
|
||||
button.setButtonType(.momentaryPushIn)
|
||||
button.bezelStyle = .rounded
|
||||
button.keyEquivalent = "s"
|
||||
button.keyEquivalentModifierMask = [.command]
|
||||
return button
|
||||
}()
|
||||
|
||||
@ -235,32 +237,34 @@ class TunnelEditViewController: NSViewController {
|
||||
if let tunnel = tunnel {
|
||||
// We're modifying an existing tunnel
|
||||
tunnelsManager.modify(tunnel: tunnel, tunnelConfiguration: tunnelConfiguration, onDemandOption: onDemandOption) { [weak self] error in
|
||||
self?.setUserInteractionEnabled(true)
|
||||
guard let self = self else { return }
|
||||
self.setUserInteractionEnabled(true)
|
||||
if let error = error {
|
||||
ErrorPresenter.showErrorAlert(error: error, from: self)
|
||||
return
|
||||
}
|
||||
self?.dismiss(self)
|
||||
self?.delegate?.tunnelSaved(tunnel: tunnel)
|
||||
self.delegate?.tunnelSaved(tunnel: tunnel)
|
||||
self.presentingViewController?.dismiss(self)
|
||||
}
|
||||
} else {
|
||||
// We're creating a new tunnel
|
||||
self.tunnelsManager.add(tunnelConfiguration: tunnelConfiguration, onDemandOption: onDemandOption) { [weak self] result in
|
||||
self?.setUserInteractionEnabled(true)
|
||||
if let error = result.error {
|
||||
guard let self = self else { return }
|
||||
self.setUserInteractionEnabled(true)
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
ErrorPresenter.showErrorAlert(error: error, from: self)
|
||||
return
|
||||
case .success(let tunnel):
|
||||
self.delegate?.tunnelSaved(tunnel: tunnel)
|
||||
self.presentingViewController?.dismiss(self)
|
||||
}
|
||||
let tunnel: TunnelContainer = result.value!
|
||||
self?.dismiss(self)
|
||||
self?.delegate?.tunnelSaved(tunnel: tunnel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc func handleDiscardAction() {
|
||||
delegate?.tunnelEditingCancelled()
|
||||
dismiss(self)
|
||||
presentingViewController?.dismiss(self)
|
||||
}
|
||||
|
||||
func updateExcludePrivateIPsVisibility(singlePeerAllowedIPs: [String]?) {
|
||||
@ -287,3 +291,9 @@ class TunnelEditViewController: NSViewController {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension TunnelEditViewController {
|
||||
override func cancelOperation(_ sender: Any?) {
|
||||
handleDiscardAction()
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ class TunnelsListTableViewController: NSViewController {
|
||||
|
||||
let tunnelsManager: TunnelsManager
|
||||
weak var delegate: TunnelsListTableViewControllerDelegate?
|
||||
var isRemovingTunnels = false
|
||||
var isRemovingTunnelsFromWithinTheApp = false
|
||||
|
||||
let tableView: NSTableView = {
|
||||
let tableView = NSTableView()
|
||||
@ -183,8 +183,10 @@ class TunnelsListTableViewController: NSViewController {
|
||||
guard let self = self else { return }
|
||||
self.selectTunnel(at: nextSelection)
|
||||
let selectedTunnels = selectedTunnelIndices.map { self.tunnelsManager.tunnel(at: $0) }
|
||||
self.isRemovingTunnelsFromWithinTheApp = true
|
||||
self.tunnelsManager.removeMultiple(tunnels: selectedTunnels) { [weak self] error in
|
||||
guard let self = self else { return }
|
||||
self.isRemovingTunnelsFromWithinTheApp = false
|
||||
defer { completion() }
|
||||
if let error = error {
|
||||
ErrorPresenter.showErrorAlert(error: error, from: self)
|
||||
@ -281,9 +283,14 @@ extension TunnelsListTableViewController {
|
||||
}
|
||||
|
||||
func tunnelRemoved(at index: Int) {
|
||||
let selectedIndices = tableView.selectedRowIndexes
|
||||
let isSingleSelectedTunnelBeingRemoved = selectedIndices.contains(index) && selectedIndices.count == 1
|
||||
tableView.removeRows(at: IndexSet(integer: index), withAnimation: .slideLeft)
|
||||
if tunnelsManager.numberOfTunnels() == 0 {
|
||||
delegate?.tunnelsListEmpty()
|
||||
} else if !isRemovingTunnelsFromWithinTheApp && isSingleSelectedTunnelBeingRemoved {
|
||||
let newSelection = min(index, tunnelsManager.numberOfTunnels() - 1)
|
||||
tableView.selectRowIndexes(IndexSet(integer: newSelection), byExtendingSelection: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -309,6 +316,23 @@ extension TunnelsListTableViewController: NSTableViewDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
extension TunnelsListTableViewController {
|
||||
override func keyDown(with event: NSEvent) {
|
||||
if event.specialKey == .delete {
|
||||
handleRemoveTunnelAction()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension TunnelsListTableViewController: NSMenuItemValidation {
|
||||
func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
|
||||
if menuItem.action == #selector(TunnelsListTableViewController.handleRemoveTunnelAction) {
|
||||
return !tableView.selectedRowIndexes.isEmpty
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
class FillerButton: NSButton {
|
||||
override var intrinsicContentSize: NSSize {
|
||||
return NSSize(width: NSView.noIntrinsicMetric, height: NSView.noIntrinsicMetric)
|
||||
|
@ -5,3 +5,8 @@
|
||||
#include "ringlogger.h"
|
||||
#include "highlighter.h"
|
||||
#include "key.h"
|
||||
|
||||
#import "TargetConditionals.h"
|
||||
#if TARGET_OS_OSX
|
||||
#include <libproc.h>
|
||||
#endif
|
||||
|
@ -7,6 +7,7 @@ enum ZipArchiveError: WireGuardAppError {
|
||||
case cantOpenInputZipFile
|
||||
case cantOpenOutputZipFileForWriting
|
||||
case badArchive
|
||||
case noTunnelsInZipArchive
|
||||
|
||||
var alertText: AlertText {
|
||||
switch self {
|
||||
@ -16,6 +17,8 @@ enum ZipArchiveError: WireGuardAppError {
|
||||
return (tr("alertCantOpenOutputZipFileForWritingTitle"), tr("alertCantOpenOutputZipFileForWritingMessage"))
|
||||
case .badArchive:
|
||||
return (tr("alertBadArchiveTitle"), tr("alertBadArchiveMessage"))
|
||||
case .noTunnelsInZipArchive:
|
||||
return (tr("alertNoTunnelsInImportedZipArchiveTitle"), tr("alertNoTunnelsInImportedZipArchiveMessage"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,16 +3,8 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
enum ZipImporterError: WireGuardAppError {
|
||||
case noTunnelsInZipArchive
|
||||
|
||||
var alertText: AlertText {
|
||||
return (tr("alertNoTunnelsInImportedZipArchiveTitle"), tr("alertNoTunnelsInImportedZipArchiveMessage"))
|
||||
}
|
||||
}
|
||||
|
||||
class ZipImporter {
|
||||
static func importConfigFiles(from url: URL, completion: @escaping (WireGuardResult<[TunnelConfiguration?]>) -> Void) {
|
||||
static func importConfigFiles(from url: URL, completion: @escaping (Result<[TunnelConfiguration?], ZipArchiveError>) -> Void) {
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
var unarchivedFiles: [(fileBaseName: String, contents: Data)]
|
||||
do {
|
||||
@ -28,9 +20,9 @@ class ZipImporter {
|
||||
}
|
||||
|
||||
if unarchivedFiles.isEmpty {
|
||||
throw ZipImporterError.noTunnelsInZipArchive
|
||||
throw ZipArchiveError.noTunnelsInZipArchive
|
||||
}
|
||||
} catch let error as WireGuardAppError {
|
||||
} catch let error as ZipArchiveError {
|
||||
DispatchQueue.main.async { completion(.failure(error)) }
|
||||
return
|
||||
} catch {
|
||||
|
@ -143,18 +143,13 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
private func pathUpdate(path: Network.NWPath) {
|
||||
guard let handle = handle else { return }
|
||||
wg_log(.debug, message: "Network change detected with \(path.status) route and interface order \(path.availableInterfaces)")
|
||||
|
||||
#if os(iOS)
|
||||
if let packetTunnelSettingsGenerator = packetTunnelSettingsGenerator {
|
||||
_ = packetTunnelSettingsGenerator.endpointUapiConfiguration().withGoString { return wgSetConfig(handle, $0) }
|
||||
}
|
||||
#endif
|
||||
var interfaces = path.availableInterfaces
|
||||
if let ifname = ifname {
|
||||
interfaces = interfaces.filter { $0.name != ifname }
|
||||
}
|
||||
if let ifscope = interfaces.first?.index {
|
||||
wgBindInterfaceScope(handle, Int32(ifscope))
|
||||
}
|
||||
wgBumpSockets(handle)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,60 +14,37 @@ LIPO ?= lipo
|
||||
DESTDIR ?= $(CONFIGURATION_BUILD_DIR)
|
||||
BUILDDIR ?= $(CONFIGURATION_TEMP_DIR)/wireguard-go-bridge
|
||||
|
||||
UPSTREAM_FILES := $(filter-out %/main.go %/queueconstants.go,$(wildcard ../wireguard-go/*/*.go) $(wildcard ../wireguard-go/*.go)) ../wireguard-go/go.mod ../wireguard-go/go.sum
|
||||
DOWNSTREAM_FILES := $(wildcard src/*.go) $(wildcard src/*/*.go)
|
||||
CFLAGS_PREFIX := $(if $(DEPLOYMENT_TARGET_CLANG_FLAG_NAME),-$(DEPLOYMENT_TARGET_CLANG_FLAG_NAME)=$($(DEPLOYMENT_TARGET_CLANG_ENV_NAME)),) -Wno-unused-command-line-argument -isysroot $(SDKROOT) -arch
|
||||
GOARCH_arm64 := arm64
|
||||
GOARCH_armv7 := arm
|
||||
GOARCH_x86_64 := amd64
|
||||
export GOOS := darwin
|
||||
export CGO_ENABLED := 1
|
||||
|
||||
build: $(DESTDIR)/libwg-go.a
|
||||
version-header: $(DESTDIR)/wireguard-go-version.h
|
||||
|
||||
GOBUILDVERSION_NEEDED := go version go1.12.1 darwin/amd64
|
||||
GOBUILDVERSION_CURRENT := $(shell go version 2>/dev/null)
|
||||
export REAL_GOROOT := $(shell go env GOROOT 2>/dev/null)
|
||||
REAL_GOROOT := $(shell go env GOROOT 2>/dev/null)
|
||||
export GOROOT := $(BUILDDIR)/goroot
|
||||
export GOPATH := $(BUILDDIR)/gopath
|
||||
export PATH := $(GOPATH)/bin:$(PATH)
|
||||
GOBUILDVERSION_FAKE := $(shell $(GOROOT)/bin/go version 2>/dev/null)
|
||||
ifneq ($(GOBUILDVERSION_NEEDED),$(GOBUILDVERSION_CURRENT))
|
||||
$(error This requires $(GOBUILDVERSION_NEEDED))
|
||||
endif
|
||||
ifneq ($(GOBUILDVERSION_NEEDED),$(GOBUILDVERSION_FAKE))
|
||||
$(shell rm -f $(GOROOT)/.prepared)
|
||||
endif
|
||||
|
||||
$(GOROOT)/.prepared:
|
||||
[ -n "$(REAL_GOROOT)" ]
|
||||
mkdir -p "$(GOROOT)"
|
||||
rsync -a --delete --exclude=pkg/obj/go-build "$(REAL_GOROOT)/" "$(GOROOT)/"
|
||||
cat goruntime-*.diff | patch -p1 -f -N -r- -d "$(GOROOT)"
|
||||
rm -rf "$(GOPATH)/pkg/mod"
|
||||
go get -d -tags ios; chmod -fR +w "$(GOPATH)/pkg/mod"
|
||||
for sys in "$(GOPATH)/pkg/mod/golang.org/x/sys@"*; do cat sys-unix-*.diff | patch -p1 -f -N -r- -d "$$sys"; done
|
||||
patch -p1 -f -N -r- -d "$(GOROOT)" < goruntime-boottime-over-monotonic.diff
|
||||
touch "$@"
|
||||
|
||||
$(shell test "$$(cat "$(BUILDDIR)/.gobuildversion" 2>/dev/null)" = "$(GOBUILDVERSION_CURRENT)" || rm -f "$(DESTDIR)/libwg-go.a")
|
||||
|
||||
define libwg-go-a
|
||||
$(BUILDDIR)/libwg-go-$(1).a: $(GOROOT)/.prepared
|
||||
CGO_CFLAGS="$(CFLAGS_PREFIX) $(ARCH)" \
|
||||
CGO_LDFLAGS="$(CFLAGS_PREFIX) $(ARCH)" \
|
||||
GOARCH="$(GOARCH_$(1))" \
|
||||
go build -tags ios -ldflags=-w -v -o "$(BUILDDIR)/libwg-go-$(1).a" -buildmode c-archive && go version > "$(BUILDDIR)/.gobuildversion"; \
|
||||
chmod -fR +w "$(GOPATH)/pkg/mod"; \
|
||||
ret=$$$$?; \
|
||||
rm -f "$(BUILDDIR)/libwg-go-$(1).h"; \
|
||||
exit $$$$ret
|
||||
$(BUILDDIR)/libwg-go-$(1).a: export CGO_ENABLED := 1
|
||||
$(BUILDDIR)/libwg-go-$(1).a: export CGO_CFLAGS := $(CFLAGS_PREFIX) $(ARCH)
|
||||
$(BUILDDIR)/libwg-go-$(1).a: export CGO_LDFLAGS := $(CFLAGS_PREFIX) $(ARCH)
|
||||
$(BUILDDIR)/libwg-go-$(1).a: export GOOS := darwin
|
||||
$(BUILDDIR)/libwg-go-$(1).a: export GOARCH := $(GOARCH_$(1))
|
||||
$(BUILDDIR)/libwg-go-$(1).a: $(GOROOT)/.prepared go.mod
|
||||
go build -tags ios -ldflags=-w -trimpath -v -o "$(BUILDDIR)/libwg-go-$(1).a" -buildmode c-archive
|
||||
rm -f "$(BUILDDIR)/libwg-go-$(1).h"
|
||||
endef
|
||||
$(foreach ARCH,$(ARCHS),$(eval $(call libwg-go-a,$(ARCH))))
|
||||
|
||||
$(DESTDIR)/wireguard-go-version.h: go.mod $(GOROOT)/.prepared
|
||||
wggo="$(GOPATH)/pkg/mod/$$(sed -n 's/.*\(golang\.zx2c4\.com\/wireguard\) \(.*\)$$/\1@\2/p' go.mod)"; \
|
||||
sed -n 's/.*WireGuardGoVersion = "\(.*\)"/#define WIREGUARD_GO_VERSION "\1"/p' "$$wggo/device/version.go" > "$@"
|
||||
$(DESTDIR)/wireguard-go-version.h: $(GOROOT)/.prepared go.mod
|
||||
go list -m golang.zx2c4.com/wireguard | sed -n 's/.*v\([0-9.]*\).*/#define WIREGUARD_GO_VERSION "\1"/p' > "$@"
|
||||
|
||||
$(DESTDIR)/libwg-go.a: $(foreach ARCH,$(ARCHS),$(BUILDDIR)/libwg-go-$(ARCH).a)
|
||||
@mkdir -vp "$(DESTDIR)"
|
||||
|
@ -165,22 +165,14 @@ func wgGetConfig(tunnelHandle int32) *C.char {
|
||||
writer.Flush()
|
||||
return C.CString(settings.String())
|
||||
}
|
||||
|
||||
//export wgBindInterfaceScope
|
||||
func wgBindInterfaceScope(tunnelHandle int32, ifscope int32) {
|
||||
//export wgBumpSockets
|
||||
func wgBumpSockets(tunnelHandle int32) {
|
||||
device, ok := tunnelHandles[tunnelHandle]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
device.Info.Printf("Binding sockets to interface %d\n", ifscope)
|
||||
err := device.BindSocketToInterface4(uint32(ifscope))
|
||||
if err != nil {
|
||||
device.Error.Printf("Unable to bind v4 socket to interface:", err)
|
||||
}
|
||||
err = device.BindSocketToInterface6(uint32(ifscope))
|
||||
if err != nil {
|
||||
device.Error.Printf("Unable to bind v6 socket to interface:", err)
|
||||
}
|
||||
device.BindUpdate()
|
||||
device.SendKeepalivesToPeersWithCurrentKeypair()
|
||||
}
|
||||
|
||||
//export wgVersion
|
||||
|
@ -1,8 +1,9 @@
|
||||
module golang.zx2c4.com/wireguard/ios
|
||||
|
||||
go 1.12
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67
|
||||
golang.zx2c4.com/wireguard v0.0.0-20190409083948-18fa27047265
|
||||
golang.org/x/net v0.0.0-20191007182048-72f939374954 // indirect
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be
|
||||
golang.zx2c4.com/wireguard v0.0.20190909-0.20191008144818-222f0f8000e8
|
||||
)
|
||||
|
@ -1,13 +1,20 @@
|
||||
github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576 h1:aUX/1G2gFSs4AsJJg2cL3HuoRhCSCz733FE5GUSuaT4=
|
||||
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53 h1:kcXqo9vE6fsZY5X5Rd7R1l7fTgnWaDCVmln65REefiE=
|
||||
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc h1:c0o/qxkaO2LF5t6fQrT4b5hzyggAkLLlCUjqfRxd8Q4=
|
||||
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20191003171128-d98b1b443823 h1:Ypyv6BNJh07T1pUSrehkLemqPKXhus2MkfktJ91kRh4=
|
||||
golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191007182048-72f939374954 h1:JGZucVF/L/TotR719NbujzadOZ2AgnYlqphQGHDCKaU=
|
||||
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67 h1:1Fzlr8kkDLQwqMP8GxrhptBLqZG/EDpiATneiZHY998=
|
||||
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191003212358-c178f38b412c h1:6Zx7DRlKXf79yfxuQ/7GqV3w2y7aDsk6bGg0MzF5RVU=
|
||||
golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20190409083948-18fa27047265 h1:ujM5BaP4MD/2MJZ1n7pmw6IIsyyS7SyPl0fDefnx/2o=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20190409083948-18fa27047265/go.mod h1:u0Cl3X+pyWdXaax3S583DQrnGDuTASO0QdlKFrs8r/8=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.zx2c4.com/wireguard v0.0.20190909-0.20191008144818-222f0f8000e8 h1:BqfQHKZLrdq0j5Z/R9coISbr1nYcSE+3BdyF5LidO+g=
|
||||
golang.zx2c4.com/wireguard v0.0.20190909-0.20191008144818-222f0f8000e8/go.mod h1:P2HsVp8SKwZEufsnezXZA4GRX/T49/HlU7DGuelXsU4=
|
||||
|
@ -1,4 +1,4 @@
|
||||
From 74523c5a12d37fa792e77a252bcc569484c3d41a Mon Sep 17 00:00:00 2001
|
||||
From 04f5695b83cd221e99e9fa6171b57e45177d5ad3 Mon Sep 17 00:00:00 2001
|
||||
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
|
||||
Date: Wed, 27 Feb 2019 05:33:01 +0100
|
||||
Subject: [PATCH] runtime: use libc_mach_continuous_time in nanotime on Darwin
|
||||
@ -18,10 +18,10 @@ Fixes #24595
|
||||
5 files changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go
|
||||
index f34ac88352..416fcb673f 100644
|
||||
index 376f76dbc5..a0677a83f6 100644
|
||||
--- a/src/runtime/sys_darwin.go
|
||||
+++ b/src/runtime/sys_darwin.go
|
||||
@@ -403,7 +403,7 @@ func closeonexec(fd int32) {
|
||||
@@ -431,7 +431,7 @@ func setNonblock(fd int32) {
|
||||
//go:cgo_import_dynamic libc_usleep usleep "/usr/lib/libSystem.B.dylib"
|
||||
|
||||
//go:cgo_import_dynamic libc_mach_timebase_info mach_timebase_info "/usr/lib/libSystem.B.dylib"
|
||||
@ -31,10 +31,10 @@ index f34ac88352..416fcb673f 100644
|
||||
//go:cgo_import_dynamic libc_sigaction sigaction "/usr/lib/libSystem.B.dylib"
|
||||
//go:cgo_import_dynamic libc_pthread_sigmask pthread_sigmask "/usr/lib/libSystem.B.dylib"
|
||||
diff --git a/src/runtime/sys_darwin_386.s b/src/runtime/sys_darwin_386.s
|
||||
index 1bc1a63c28..34a3561350 100644
|
||||
index e653c54f61..5a43fcbdc1 100644
|
||||
--- a/src/runtime/sys_darwin_386.s
|
||||
+++ b/src/runtime/sys_darwin_386.s
|
||||
@@ -184,7 +184,7 @@ TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0
|
||||
@@ -199,7 +199,7 @@ TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0
|
||||
PUSHL BP
|
||||
MOVL SP, BP
|
||||
SUBL $8+(machTimebaseInfo__size+15)/16*16, SP
|
||||
@ -44,10 +44,10 @@ index 1bc1a63c28..34a3561350 100644
|
||||
MOVL AX, 0(CX)
|
||||
MOVL DX, 4(CX)
|
||||
diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s
|
||||
index f99cb00ab8..8b99316983 100644
|
||||
index 87c8db8c82..f962f24339 100644
|
||||
--- a/src/runtime/sys_darwin_amd64.s
|
||||
+++ b/src/runtime/sys_darwin_amd64.s
|
||||
@@ -86,7 +86,7 @@ TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0
|
||||
@@ -97,7 +97,7 @@ TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0
|
||||
PUSHQ BP
|
||||
MOVQ SP, BP
|
||||
MOVQ DI, BX
|
||||
@ -57,10 +57,10 @@ index f99cb00ab8..8b99316983 100644
|
||||
MOVL timebase<>+machTimebaseInfo_numer(SB), SI
|
||||
MOVL timebase<>+machTimebaseInfo_denom(SB), DI // atomic read
|
||||
diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s
|
||||
index 54c7afbf34..a4f06fdb85 100644
|
||||
index 996f8028a3..5bd34b51be 100644
|
||||
--- a/src/runtime/sys_darwin_arm.s
|
||||
+++ b/src/runtime/sys_darwin_arm.s
|
||||
@@ -118,7 +118,7 @@ GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size)
|
||||
@@ -126,7 +126,7 @@ GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size)
|
||||
|
||||
TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0
|
||||
MOVW R0, R8
|
||||
@ -70,10 +70,10 @@ index 54c7afbf34..a4f06fdb85 100644
|
||||
MOVW R1, 4(R8)
|
||||
MOVW timebase<>+machTimebaseInfo_numer(SB), R6
|
||||
diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s
|
||||
index 29951d8ad7..cdaf0a630e 100644
|
||||
index ac3ca74f63..5e91540f94 100644
|
||||
--- a/src/runtime/sys_darwin_arm64.s
|
||||
+++ b/src/runtime/sys_darwin_arm64.s
|
||||
@@ -113,7 +113,7 @@ GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size)
|
||||
@@ -121,7 +121,7 @@ GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size)
|
||||
|
||||
TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$40
|
||||
MOVD R0, R19
|
||||
@ -83,5 +83,5 @@ index 29951d8ad7..cdaf0a630e 100644
|
||||
MOVW timebase<>+machTimebaseInfo_numer(SB), R20
|
||||
MOVD $timebase<>+machTimebaseInfo_denom(SB), R21
|
||||
--
|
||||
2.20.1
|
||||
2.23.0
|
||||
|
||||
|
@ -1,279 +0,0 @@
|
||||
From bc77ad792117829909eeeca3aa492d6f292d004d Mon Sep 17 00:00:00 2001
|
||||
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
|
||||
Date: Tue, 19 Mar 2019 13:55:44 -0600
|
||||
Subject: [PATCH] syscall: do not link against ___getdirentries64
|
||||
|
||||
---
|
||||
.../x/sys/unix/syscall_darwin_386.go | 5 ++++-
|
||||
.../x/sys/unix/syscall_darwin_amd64.go | 5 ++++-
|
||||
.../x/sys/unix/zsyscall_darwin_386.go | 22 -------------------
|
||||
.../x/sys/unix/zsyscall_darwin_386.s | 2 --
|
||||
.../x/sys/unix/zsyscall_darwin_amd64.go | 22 -------------------
|
||||
.../x/sys/unix/zsyscall_darwin_amd64.s | 2 --
|
||||
src/syscall/syscall_darwin_386.go | 5 ++++-
|
||||
src/syscall/syscall_darwin_amd64.go | 5 ++++-
|
||||
src/syscall/zsyscall_darwin_386.go | 20 -----------------
|
||||
src/syscall/zsyscall_darwin_386.s | 2 --
|
||||
src/syscall/zsyscall_darwin_amd64.go | 20 -----------------
|
||||
src/syscall/zsyscall_darwin_amd64.s | 2 --
|
||||
12 files changed, 16 insertions(+), 96 deletions(-)
|
||||
|
||||
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_386.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_386.go
|
||||
index 489726fa9b..900dd7c91f 100644
|
||||
--- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_386.go
|
||||
+++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_386.go
|
||||
@@ -56,8 +56,11 @@ const SYS___SYSCTL = SYS_SYSCTL
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
|
||||
//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
|
||||
//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64
|
||||
-//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) = SYS_GETDIRENTRIES64
|
||||
//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT64
|
||||
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
|
||||
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
|
||||
//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64
|
||||
+
|
||||
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
|
||||
+ return 0, ENOSYS
|
||||
+}
|
||||
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go
|
||||
index 914b89bde5..95e245fff7 100644
|
||||
--- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go
|
||||
+++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go
|
||||
@@ -56,8 +56,11 @@ const SYS___SYSCTL = SYS_SYSCTL
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
|
||||
//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
|
||||
//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64
|
||||
-//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) = SYS_GETDIRENTRIES64
|
||||
//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT64
|
||||
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
|
||||
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
|
||||
//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64
|
||||
+
|
||||
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
|
||||
+ return 0, ENOSYS
|
||||
+}
|
||||
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go
|
||||
index 23346dc68f..db4f1eaf1c 100644
|
||||
--- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go
|
||||
+++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go
|
||||
@@ -2408,28 +2408,6 @@ func libc_fstatfs64_trampoline()
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
|
||||
- var _p0 unsafe.Pointer
|
||||
- if len(buf) > 0 {
|
||||
- _p0 = unsafe.Pointer(&buf[0])
|
||||
- } else {
|
||||
- _p0 = unsafe.Pointer(&_zero)
|
||||
- }
|
||||
- r0, _, e1 := syscall_syscall6(funcPC(libc___getdirentries64_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
|
||||
- n = int(r0)
|
||||
- if e1 != 0 {
|
||||
- err = errnoErr(e1)
|
||||
- }
|
||||
- return
|
||||
-}
|
||||
-
|
||||
-func libc___getdirentries64_trampoline()
|
||||
-
|
||||
-//go:linkname libc___getdirentries64 libc___getdirentries64
|
||||
-//go:cgo_import_dynamic libc___getdirentries64 __getdirentries64 "/usr/lib/libSystem.B.dylib"
|
||||
-
|
||||
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
-
|
||||
func getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) {
|
||||
r0, _, e1 := syscall_syscall(funcPC(libc_getfsstat64_trampoline), uintptr(buf), uintptr(size), uintptr(flags))
|
||||
n = int(r0)
|
||||
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.s b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.s
|
||||
index 37b85b4f61..6165f70e33 100644
|
||||
--- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.s
|
||||
+++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.s
|
||||
@@ -272,8 +272,6 @@ TEXT ·libc_fstatat64_trampoline(SB),NOSPLIT,$0-0
|
||||
JMP libc_fstatat64(SB)
|
||||
TEXT ·libc_fstatfs64_trampoline(SB),NOSPLIT,$0-0
|
||||
JMP libc_fstatfs64(SB)
|
||||
-TEXT ·libc___getdirentries64_trampoline(SB),NOSPLIT,$0-0
|
||||
- JMP libc___getdirentries64(SB)
|
||||
TEXT ·libc_getfsstat64_trampoline(SB),NOSPLIT,$0-0
|
||||
JMP libc_getfsstat64(SB)
|
||||
TEXT ·libc_lstat64_trampoline(SB),NOSPLIT,$0-0
|
||||
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go
|
||||
index b50178d679..dea5dee75e 100644
|
||||
--- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go
|
||||
+++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go
|
||||
@@ -2408,28 +2408,6 @@ func libc_fstatfs64_trampoline()
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
|
||||
- var _p0 unsafe.Pointer
|
||||
- if len(buf) > 0 {
|
||||
- _p0 = unsafe.Pointer(&buf[0])
|
||||
- } else {
|
||||
- _p0 = unsafe.Pointer(&_zero)
|
||||
- }
|
||||
- r0, _, e1 := syscall_syscall6(funcPC(libc___getdirentries64_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
|
||||
- n = int(r0)
|
||||
- if e1 != 0 {
|
||||
- err = errnoErr(e1)
|
||||
- }
|
||||
- return
|
||||
-}
|
||||
-
|
||||
-func libc___getdirentries64_trampoline()
|
||||
-
|
||||
-//go:linkname libc___getdirentries64 libc___getdirentries64
|
||||
-//go:cgo_import_dynamic libc___getdirentries64 __getdirentries64 "/usr/lib/libSystem.B.dylib"
|
||||
-
|
||||
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
-
|
||||
func getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) {
|
||||
r0, _, e1 := syscall_syscall(funcPC(libc_getfsstat64_trampoline), uintptr(buf), uintptr(size), uintptr(flags))
|
||||
n = int(r0)
|
||||
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s
|
||||
index da9b900a8c..f1e2d7e9a4 100644
|
||||
--- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s
|
||||
+++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s
|
||||
@@ -272,8 +272,6 @@ TEXT ·libc_fstatat64_trampoline(SB),NOSPLIT,$0-0
|
||||
JMP libc_fstatat64(SB)
|
||||
TEXT ·libc_fstatfs64_trampoline(SB),NOSPLIT,$0-0
|
||||
JMP libc_fstatfs64(SB)
|
||||
-TEXT ·libc___getdirentries64_trampoline(SB),NOSPLIT,$0-0
|
||||
- JMP libc___getdirentries64(SB)
|
||||
TEXT ·libc_getfsstat64_trampoline(SB),NOSPLIT,$0-0
|
||||
JMP libc_getfsstat64(SB)
|
||||
TEXT ·libc_lstat64_trampoline(SB),NOSPLIT,$0-0
|
||||
diff --git a/src/syscall/syscall_darwin_386.go b/src/syscall/syscall_darwin_386.go
|
||||
index 045ebc726b..826d76f569 100644
|
||||
--- a/src/syscall/syscall_darwin_386.go
|
||||
+++ b/src/syscall/syscall_darwin_386.go
|
||||
@@ -16,7 +16,6 @@ func setTimeval(sec, usec int64) Timeval {
|
||||
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_fstat64
|
||||
//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_fstatfs64
|
||||
-//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) = SYS___getdirentries64
|
||||
//sysnb Gettimeofday(tp *Timeval) (err error)
|
||||
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_lstat64
|
||||
//sys Stat(path string, stat *Stat_t) (err error) = SYS_stat64
|
||||
@@ -63,3 +62,7 @@ func libc_sendfile_trampoline()
|
||||
func syscall9(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
|
||||
|
||||
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // sic
|
||||
+
|
||||
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
|
||||
+ return 0, ENOSYS
|
||||
+}
|
||||
diff --git a/src/syscall/syscall_darwin_amd64.go b/src/syscall/syscall_darwin_amd64.go
|
||||
index 7b6493bf9f..3868790049 100644
|
||||
--- a/src/syscall/syscall_darwin_amd64.go
|
||||
+++ b/src/syscall/syscall_darwin_amd64.go
|
||||
@@ -16,7 +16,6 @@ func setTimeval(sec, usec int64) Timeval {
|
||||
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_fstat64
|
||||
//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_fstatfs64
|
||||
-//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) = SYS___getdirentries64
|
||||
//sysnb Gettimeofday(tp *Timeval) (err error)
|
||||
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_lstat64
|
||||
//sys Stat(path string, stat *Stat_t) (err error) = SYS_stat64
|
||||
@@ -63,3 +62,7 @@ func libc_sendfile_trampoline()
|
||||
func syscallX(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
|
||||
|
||||
func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
|
||||
+
|
||||
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
|
||||
+ return 0, ENOSYS
|
||||
+}
|
||||
diff --git a/src/syscall/zsyscall_darwin_386.go b/src/syscall/zsyscall_darwin_386.go
|
||||
index 758ff7b129..a666a1f65e 100644
|
||||
--- a/src/syscall/zsyscall_darwin_386.go
|
||||
+++ b/src/syscall/zsyscall_darwin_386.go
|
||||
@@ -1845,27 +1845,7 @@ func libc_fstatfs64_trampoline()
|
||||
|
||||
//go:linkname libc_fstatfs64 libc_fstatfs64
|
||||
//go:cgo_import_dynamic libc_fstatfs64 fstatfs64 "/usr/lib/libSystem.B.dylib"
|
||||
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
-
|
||||
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
|
||||
- var _p0 unsafe.Pointer
|
||||
- if len(buf) > 0 {
|
||||
- _p0 = unsafe.Pointer(&buf[0])
|
||||
- } else {
|
||||
- _p0 = unsafe.Pointer(&_zero)
|
||||
- }
|
||||
- r0, _, e1 := syscall6(funcPC(libc___getdirentries64_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
|
||||
- n = int(r0)
|
||||
- if e1 != 0 {
|
||||
- err = errnoErr(e1)
|
||||
- }
|
||||
- return
|
||||
-}
|
||||
-
|
||||
-func libc___getdirentries64_trampoline()
|
||||
|
||||
-//go:linkname libc___getdirentries64 libc___getdirentries64
|
||||
-//go:cgo_import_dynamic libc___getdirentries64 __getdirentries64 "/usr/lib/libSystem.B.dylib"
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Gettimeofday(tp *Timeval) (err error) {
|
||||
diff --git a/src/syscall/zsyscall_darwin_386.s b/src/syscall/zsyscall_darwin_386.s
|
||||
index a688192501..a5af9b64b9 100644
|
||||
--- a/src/syscall/zsyscall_darwin_386.s
|
||||
+++ b/src/syscall/zsyscall_darwin_386.s
|
||||
@@ -235,8 +235,6 @@ TEXT ·libc_fstat64_trampoline(SB),NOSPLIT,$0-0
|
||||
JMP libc_fstat64(SB)
|
||||
TEXT ·libc_fstatfs64_trampoline(SB),NOSPLIT,$0-0
|
||||
JMP libc_fstatfs64(SB)
|
||||
-TEXT ·libc___getdirentries64_trampoline(SB),NOSPLIT,$0-0
|
||||
- JMP libc___getdirentries64(SB)
|
||||
TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0
|
||||
JMP libc_gettimeofday(SB)
|
||||
TEXT ·libc_lstat64_trampoline(SB),NOSPLIT,$0-0
|
||||
diff --git a/src/syscall/zsyscall_darwin_amd64.go b/src/syscall/zsyscall_darwin_amd64.go
|
||||
index afc3d72d8d..bb87aef1f9 100644
|
||||
--- a/src/syscall/zsyscall_darwin_amd64.go
|
||||
+++ b/src/syscall/zsyscall_darwin_amd64.go
|
||||
@@ -1845,27 +1845,7 @@ func libc_fstatfs64_trampoline()
|
||||
|
||||
//go:linkname libc_fstatfs64 libc_fstatfs64
|
||||
//go:cgo_import_dynamic libc_fstatfs64 fstatfs64 "/usr/lib/libSystem.B.dylib"
|
||||
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
-
|
||||
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
|
||||
- var _p0 unsafe.Pointer
|
||||
- if len(buf) > 0 {
|
||||
- _p0 = unsafe.Pointer(&buf[0])
|
||||
- } else {
|
||||
- _p0 = unsafe.Pointer(&_zero)
|
||||
- }
|
||||
- r0, _, e1 := syscall6(funcPC(libc___getdirentries64_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
|
||||
- n = int(r0)
|
||||
- if e1 != 0 {
|
||||
- err = errnoErr(e1)
|
||||
- }
|
||||
- return
|
||||
-}
|
||||
-
|
||||
-func libc___getdirentries64_trampoline()
|
||||
|
||||
-//go:linkname libc___getdirentries64 libc___getdirentries64
|
||||
-//go:cgo_import_dynamic libc___getdirentries64 __getdirentries64 "/usr/lib/libSystem.B.dylib"
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Gettimeofday(tp *Timeval) (err error) {
|
||||
diff --git a/src/syscall/zsyscall_darwin_amd64.s b/src/syscall/zsyscall_darwin_amd64.s
|
||||
index 21ab38e3ee..409320dea5 100644
|
||||
--- a/src/syscall/zsyscall_darwin_amd64.s
|
||||
+++ b/src/syscall/zsyscall_darwin_amd64.s
|
||||
@@ -235,8 +235,6 @@ TEXT ·libc_fstat64_trampoline(SB),NOSPLIT,$0-0
|
||||
JMP libc_fstat64(SB)
|
||||
TEXT ·libc_fstatfs64_trampoline(SB),NOSPLIT,$0-0
|
||||
JMP libc_fstatfs64(SB)
|
||||
-TEXT ·libc___getdirentries64_trampoline(SB),NOSPLIT,$0-0
|
||||
- JMP libc___getdirentries64(SB)
|
||||
TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0
|
||||
JMP libc_gettimeofday(SB)
|
||||
TEXT ·libc_lstat64_trampoline(SB),NOSPLIT,$0-0
|
||||
--
|
||||
2.21.0
|
||||
|
@ -1,143 +0,0 @@
|
||||
From 3efe4df9b66d4af86363e37768ea469abb8f7bdc Mon Sep 17 00:00:00 2001
|
||||
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
|
||||
Date: Tue, 19 Mar 2019 14:01:21 -0600
|
||||
Subject: [PATCH] unix: do not link against ___getdirentries64
|
||||
|
||||
---
|
||||
unix/syscall_darwin_386.go | 5 ++++-
|
||||
unix/syscall_darwin_amd64.go | 5 ++++-
|
||||
unix/zsyscall_darwin_386.go | 22 ----------------------
|
||||
unix/zsyscall_darwin_386.s | 2 --
|
||||
unix/zsyscall_darwin_amd64.go | 22 ----------------------
|
||||
unix/zsyscall_darwin_amd64.s | 2 --
|
||||
6 files changed, 8 insertions(+), 50 deletions(-)
|
||||
|
||||
diff --git a/unix/syscall_darwin_386.go b/unix/syscall_darwin_386.go
|
||||
index 489726f..900dd7c 100644
|
||||
--- a/unix/syscall_darwin_386.go
|
||||
+++ b/unix/syscall_darwin_386.go
|
||||
@@ -56,8 +56,11 @@ const SYS___SYSCTL = SYS_SYSCTL
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
|
||||
//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
|
||||
//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64
|
||||
-//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) = SYS_GETDIRENTRIES64
|
||||
//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT64
|
||||
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
|
||||
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
|
||||
//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64
|
||||
+
|
||||
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
|
||||
+ return 0, ENOSYS
|
||||
+}
|
||||
diff --git a/unix/syscall_darwin_amd64.go b/unix/syscall_darwin_amd64.go
|
||||
index 914b89b..95e245f 100644
|
||||
--- a/unix/syscall_darwin_amd64.go
|
||||
+++ b/unix/syscall_darwin_amd64.go
|
||||
@@ -56,8 +56,11 @@ const SYS___SYSCTL = SYS_SYSCTL
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
|
||||
//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
|
||||
//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64
|
||||
-//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) = SYS_GETDIRENTRIES64
|
||||
//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT64
|
||||
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
|
||||
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
|
||||
//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64
|
||||
+
|
||||
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
|
||||
+ return 0, ENOSYS
|
||||
+}
|
||||
diff --git a/unix/zsyscall_darwin_386.go b/unix/zsyscall_darwin_386.go
|
||||
index 23346dc..db4f1ea 100644
|
||||
--- a/unix/zsyscall_darwin_386.go
|
||||
+++ b/unix/zsyscall_darwin_386.go
|
||||
@@ -2408,28 +2408,6 @@ func libc_fstatfs64_trampoline()
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
|
||||
- var _p0 unsafe.Pointer
|
||||
- if len(buf) > 0 {
|
||||
- _p0 = unsafe.Pointer(&buf[0])
|
||||
- } else {
|
||||
- _p0 = unsafe.Pointer(&_zero)
|
||||
- }
|
||||
- r0, _, e1 := syscall_syscall6(funcPC(libc___getdirentries64_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
|
||||
- n = int(r0)
|
||||
- if e1 != 0 {
|
||||
- err = errnoErr(e1)
|
||||
- }
|
||||
- return
|
||||
-}
|
||||
-
|
||||
-func libc___getdirentries64_trampoline()
|
||||
-
|
||||
-//go:linkname libc___getdirentries64 libc___getdirentries64
|
||||
-//go:cgo_import_dynamic libc___getdirentries64 __getdirentries64 "/usr/lib/libSystem.B.dylib"
|
||||
-
|
||||
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
-
|
||||
func getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) {
|
||||
r0, _, e1 := syscall_syscall(funcPC(libc_getfsstat64_trampoline), uintptr(buf), uintptr(size), uintptr(flags))
|
||||
n = int(r0)
|
||||
diff --git a/unix/zsyscall_darwin_386.s b/unix/zsyscall_darwin_386.s
|
||||
index 37b85b4..6165f70 100644
|
||||
--- a/unix/zsyscall_darwin_386.s
|
||||
+++ b/unix/zsyscall_darwin_386.s
|
||||
@@ -272,8 +272,6 @@ TEXT ·libc_fstatat64_trampoline(SB),NOSPLIT,$0-0
|
||||
JMP libc_fstatat64(SB)
|
||||
TEXT ·libc_fstatfs64_trampoline(SB),NOSPLIT,$0-0
|
||||
JMP libc_fstatfs64(SB)
|
||||
-TEXT ·libc___getdirentries64_trampoline(SB),NOSPLIT,$0-0
|
||||
- JMP libc___getdirentries64(SB)
|
||||
TEXT ·libc_getfsstat64_trampoline(SB),NOSPLIT,$0-0
|
||||
JMP libc_getfsstat64(SB)
|
||||
TEXT ·libc_lstat64_trampoline(SB),NOSPLIT,$0-0
|
||||
diff --git a/unix/zsyscall_darwin_amd64.go b/unix/zsyscall_darwin_amd64.go
|
||||
index c142e33..126f993 100644
|
||||
--- a/unix/zsyscall_darwin_amd64.go
|
||||
+++ b/unix/zsyscall_darwin_amd64.go
|
||||
@@ -2423,28 +2423,6 @@ func libc_fstatfs64_trampoline()
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
|
||||
- var _p0 unsafe.Pointer
|
||||
- if len(buf) > 0 {
|
||||
- _p0 = unsafe.Pointer(&buf[0])
|
||||
- } else {
|
||||
- _p0 = unsafe.Pointer(&_zero)
|
||||
- }
|
||||
- r0, _, e1 := syscall_syscall6(funcPC(libc___getdirentries64_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
|
||||
- n = int(r0)
|
||||
- if e1 != 0 {
|
||||
- err = errnoErr(e1)
|
||||
- }
|
||||
- return
|
||||
-}
|
||||
-
|
||||
-func libc___getdirentries64_trampoline()
|
||||
-
|
||||
-//go:linkname libc___getdirentries64 libc___getdirentries64
|
||||
-//go:cgo_import_dynamic libc___getdirentries64 __getdirentries64 "/usr/lib/libSystem.B.dylib"
|
||||
-
|
||||
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
-
|
||||
func getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) {
|
||||
r0, _, e1 := syscall_syscall(funcPC(libc_getfsstat64_trampoline), uintptr(buf), uintptr(size), uintptr(flags))
|
||||
n = int(r0)
|
||||
diff --git a/unix/zsyscall_darwin_amd64.s b/unix/zsyscall_darwin_amd64.s
|
||||
index 1a39151..a19c4f5 100644
|
||||
--- a/unix/zsyscall_darwin_amd64.s
|
||||
+++ b/unix/zsyscall_darwin_amd64.s
|
||||
@@ -274,8 +274,6 @@ TEXT ·libc_fstatat64_trampoline(SB),NOSPLIT,$0-0
|
||||
JMP libc_fstatat64(SB)
|
||||
TEXT ·libc_fstatfs64_trampoline(SB),NOSPLIT,$0-0
|
||||
JMP libc_fstatfs64(SB)
|
||||
-TEXT ·libc___getdirentries64_trampoline(SB),NOSPLIT,$0-0
|
||||
- JMP libc___getdirentries64(SB)
|
||||
TEXT ·libc_getfsstat64_trampoline(SB),NOSPLIT,$0-0
|
||||
JMP libc_getfsstat64(SB)
|
||||
TEXT ·libc_lstat64_trampoline(SB),NOSPLIT,$0-0
|
||||
--
|
||||
2.21.0
|
||||
|
@ -18,7 +18,7 @@ extern int wgTurnOn(gostring_t settings, int32_t tun_fd);
|
||||
extern void wgTurnOff(int handle);
|
||||
extern int64_t wgSetConfig(int handle, gostring_t settings);
|
||||
extern char *wgGetConfig(int handle);
|
||||
extern void wgBindInterfaceScope(int handle, int32_t ifscope);
|
||||
extern void wgBumpSockets(int handle);
|
||||
extern const char *wgVersion();
|
||||
|
||||
#endif
|
||||
|