Skip to content

Commit 8f00a87

Browse files
committedJun 13, 2018
first commit
0 parents  commit 8f00a87

24 files changed

+1526
-0
lines changed
 

‎.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Country.mmdb

‎ClashX.xcodeproj/project.pbxproj

+489
Large diffs are not rendered by default.

‎ClashX/AppDelegate.swift

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//
2+
// AppDelegate.swift
3+
// ClashX
4+
//
5+
// Created by 称一称 on 2018/6/10.
6+
// Copyright © 2018年 west2online. All rights reserved.
7+
//
8+
9+
import Cocoa
10+
@NSApplicationMain
11+
class AppDelegate: NSObject, NSApplicationDelegate {
12+
var statusItem: NSStatusItem!
13+
static let StatusItemIconWidth: CGFloat = NSStatusItem.variableLength
14+
15+
16+
@IBOutlet weak var statusMenu: NSMenu!
17+
@IBOutlet weak var proxySettingMenuItem: NSMenuItem!
18+
19+
let ssQueue = DispatchQueue(label: "com.w2fzu.ssqueue", attributes: .concurrent)
20+
21+
func applicationDidFinishLaunching(_ aNotification: Notification) {
22+
// Insert code here to initialize your application
23+
24+
_ = ProxyConfigManager.install()
25+
26+
statusItem = NSStatusBar.system.statusItem(withLength: AppDelegate.StatusItemIconWidth)
27+
let image : NSImage = NSImage(named: NSImage.Name(rawValue: "menu_icon"))!
28+
image.isTemplate = true
29+
statusItem.image = image
30+
statusItem.menu = statusMenu
31+
updateMenuItem()
32+
startProxy()
33+
34+
}
35+
36+
func applicationWillTerminate(_ aNotification: Notification) {
37+
if ConfigManager.proxyPortAutoSet {
38+
_ = ProxyConfigManager.setUpSystemProxy(port: nil,socksPort: nil)
39+
}
40+
}
41+
42+
func updateMenuItem(){
43+
proxySettingMenuItem.state = ConfigManager.proxyPortAutoSet ? .on : .off
44+
}
45+
46+
func startProxy() {
47+
ssQueue.async {
48+
run()
49+
}
50+
51+
let ports = getPortsC()
52+
ConfigManager.httpProxyPort = Int(String(cString: ports.r0))!
53+
ConfigManager.socksProxyPort = Int(String(cString: ports.r1))!
54+
55+
if ConfigManager.proxyPortAutoSet {
56+
_ = ProxyConfigManager.setUpSystemProxy(port: ConfigManager.httpProxyPort,socksPort: ConfigManager.socksProxyPort)
57+
}
58+
}
59+
60+
@IBAction func actionQuit(_ sender: Any) {
61+
NSApplication.shared.terminate(self)
62+
}
63+
64+
65+
66+
@IBAction func actionSetSystemProxy(_ sender: Any) {
67+
ConfigManager.proxyPortAutoSet = !ConfigManager.proxyPortAutoSet
68+
updateMenuItem()
69+
if ConfigManager.proxyPortAutoSet {
70+
_ = ProxyConfigManager.setUpSystemProxy(port: ConfigManager.httpProxyPort,socksPort: ConfigManager.socksProxyPort)
71+
} else {
72+
_ = ProxyConfigManager.setUpSystemProxy(port: nil,socksPort: nil)
73+
}
74+
75+
}
76+
77+
@IBAction func actionCopyExportCommand(_ sender: Any) {
78+
let pasteboard = NSPasteboard.general
79+
pasteboard.clearContents()
80+
pasteboard.setString("export https_proxy=http://127.0.0.1:\(ConfigManager.httpProxyPort);export http_proxy=http://127.0.0.1:\(ConfigManager.httpProxyPort)", forType: .string)
81+
}
82+
83+
84+
@IBAction func openConfigFolder(_ sender: Any) {
85+
let path = (NSHomeDirectory() as NSString).appendingPathComponent("/.config/clash/config.ini")
86+
NSWorkspace.shared.openFile(path)
87+
}
88+
@IBAction func actionUpdateConfig(_ sender: Any) {
89+
ssQueue.async {
90+
updateConfigC()
91+
}
92+
}
93+
}
94+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
{
2+
"images" : [
3+
{
4+
"idiom" : "mac",
5+
"size" : "16x16",
6+
"scale" : "1x"
7+
},
8+
{
9+
"idiom" : "mac",
10+
"size" : "16x16",
11+
"scale" : "2x"
12+
},
13+
{
14+
"idiom" : "mac",
15+
"size" : "32x32",
16+
"scale" : "1x"
17+
},
18+
{
19+
"idiom" : "mac",
20+
"size" : "32x32",
21+
"scale" : "2x"
22+
},
23+
{
24+
"idiom" : "mac",
25+
"size" : "128x128",
26+
"scale" : "1x"
27+
},
28+
{
29+
"idiom" : "mac",
30+
"size" : "128x128",
31+
"scale" : "2x"
32+
},
33+
{
34+
"idiom" : "mac",
35+
"size" : "256x256",
36+
"scale" : "1x"
37+
},
38+
{
39+
"idiom" : "mac",
40+
"size" : "256x256",
41+
"scale" : "2x"
42+
},
43+
{
44+
"idiom" : "mac",
45+
"size" : "512x512",
46+
"scale" : "1x"
47+
},
48+
{
49+
"idiom" : "mac",
50+
"size" : "512x512",
51+
"scale" : "2x"
52+
}
53+
],
54+
"info" : {
55+
"version" : 1,
56+
"author" : "xcode"
57+
}
58+
}

‎ClashX/Assets.xcassets/Contents.json

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"info" : {
3+
"version" : 1,
4+
"author" : "xcode"
5+
}
6+
}

‎ClashX/Base.lproj/Main.storyboard

+213
Large diffs are not rendered by default.

‎ClashX/ClashX-Bridging-Header.h

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
//
2+
// Use this file to import your target's public headers that you would like to expose to Swift.
3+
//
4+
#import "clash.h"

‎ClashX/ClashX.entitlements

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict/>
5+
</plist>

‎ClashX/Info.plist

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>LSUIElement</key>
6+
<true/>
7+
<key>CFBundleDevelopmentRegion</key>
8+
<string>$(DEVELOPMENT_LANGUAGE)</string>
9+
<key>CFBundleExecutable</key>
10+
<string>$(EXECUTABLE_NAME)</string>
11+
<key>CFBundleIconFile</key>
12+
<string></string>
13+
<key>CFBundleIdentifier</key>
14+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
15+
<key>CFBundleInfoDictionaryVersion</key>
16+
<string>6.0</string>
17+
<key>CFBundleName</key>
18+
<string>$(PRODUCT_NAME)</string>
19+
<key>CFBundlePackageType</key>
20+
<string>APPL</string>
21+
<key>CFBundleShortVersionString</key>
22+
<string>1.0</string>
23+
<key>CFBundleVersion</key>
24+
<string>1</string>
25+
<key>LSMinimumSystemVersion</key>
26+
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
27+
<key>NSHumanReadableCopyright</key>
28+
<string>Copyright © 2018年 west2online. All rights reserved.</string>
29+
<key>NSMainStoryboardFile</key>
30+
<string>Main</string>
31+
<key>NSPrincipalClass</key>
32+
<string>NSApplication</string>
33+
</dict>
34+
</plist>

‎ClashX/Managers/ConfigManager.swift

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//
2+
// ConfigManager.swift
3+
// ClashX
4+
//
5+
// Created by 称一称 on 2018/6/12.
6+
// Copyright © 2018年 west2online. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import Cocoa
11+
12+
class ConfigManager {
13+
14+
private static let instance = ConfigManager()
15+
var _httpProxyPort = 0
16+
var _socksProxyPort = 0
17+
18+
static var proxyPortAutoSet:Bool {
19+
get{
20+
return UserDefaults.standard.bool(forKey: "proxyPortAutoSet")
21+
}
22+
set {
23+
UserDefaults.standard.set(newValue, forKey: "proxyPortAutoSet")
24+
}
25+
}
26+
27+
static var httpProxyPort:Int {
28+
get{
29+
return instance._httpProxyPort
30+
}
31+
set {
32+
instance._httpProxyPort = newValue
33+
}
34+
}
35+
36+
static var socksProxyPort:Int {
37+
get{
38+
return instance._socksProxyPort
39+
}
40+
set {
41+
instance._socksProxyPort = newValue
42+
}
43+
}
44+
}
+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
2+
import Foundation
3+
class ProxyConfigManager {
4+
static let kProxyConfigPath = (NSHomeDirectory() as NSString).appendingPathComponent("/.config/clash/")
5+
static let kProxyHelperPath = "/Library/Application Support/clashX/ProxyConfig"
6+
// static let kProxyConfigPath = Bundle.main.path(forResource: "ProxyConfig", ofType: nil)
7+
static let kVersion = "0.4.0"
8+
9+
10+
open static func checkVersion() -> Bool {
11+
let scriptPath = "\(Bundle.main.resourcePath!)/check_proxy_helper.sh"
12+
print(scriptPath)
13+
let appleScriptStr = "do shell script \"bash \(scriptPath)\""
14+
let appleScript = NSAppleScript(source: appleScriptStr)
15+
var dict: NSDictionary?
16+
if let res = appleScript?.executeAndReturnError(&dict) {
17+
print(res.stringValue ?? "")
18+
if (res.stringValue?.contains("root")) ?? false {
19+
return true
20+
}
21+
}
22+
return false
23+
24+
}
25+
26+
open static func install() -> Bool {
27+
checkMMDB()
28+
if !checkVersion() {
29+
let scriptPath = "\(Bundle.main.resourcePath!)/install_proxy_helper.sh"
30+
let appleScriptStr = "do shell script \"bash \(scriptPath)\" with administrator privileges"
31+
let appleScript = NSAppleScript(source: appleScriptStr)
32+
var dict: NSDictionary?
33+
if let res = appleScript?.executeAndReturnError(&dict) {
34+
print(res)
35+
return true
36+
} else {
37+
return false
38+
}
39+
}
40+
return true
41+
}
42+
43+
static func checkMMDB() {
44+
let fileManage = FileManager.default
45+
let destMMDBPath = (NSHomeDirectory() as NSString).appendingPathComponent("/.config/clash/Country.mmdb")
46+
if !fileManage.fileExists(atPath: destMMDBPath) {
47+
let mmdbPath = Bundle.main.path(forResource: "Country", ofType: "mmdb")
48+
try! fileManage.copyItem(at: URL(fileURLWithPath: mmdbPath!), to: URL(fileURLWithPath: destMMDBPath))
49+
}
50+
}
51+
52+
open static func setUpSystemProxy(port: Int?,socksPort: Int?) -> Bool {
53+
let task = Process()
54+
task.launchPath = kProxyHelperPath
55+
if let port = port,let socksPort = socksPort {
56+
task.arguments = [String(port),String(socksPort), "enable"]
57+
} else {
58+
task.arguments = ["0", "0", "disable"]
59+
}
60+
61+
task.launch()
62+
63+
task.waitUntilExit()
64+
65+
if task.terminationStatus != 0 {
66+
return false
67+
}
68+
return true
69+
}
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
// !$*UTF8*$!
2+
{
3+
archiveVersion = 1;
4+
classes = {
5+
};
6+
objectVersion = 46;
7+
objects = {
8+
9+
/* Begin PBXBuildFile section */
10+
36B6A3271E263590002B5B1D /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B6A3261E263590002B5B1D /* main.swift */; };
11+
/* End PBXBuildFile section */
12+
13+
/* Begin PBXCopyFilesBuildPhase section */
14+
36B6A3211E263590002B5B1D /* CopyFiles */ = {
15+
isa = PBXCopyFilesBuildPhase;
16+
buildActionMask = 2147483647;
17+
dstPath = /usr/share/man/man1/;
18+
dstSubfolderSpec = 0;
19+
files = (
20+
);
21+
runOnlyForDeploymentPostprocessing = 1;
22+
};
23+
/* End PBXCopyFilesBuildPhase section */
24+
25+
/* Begin PBXFileReference section */
26+
36B6A3231E263590002B5B1D /* ProxyConfig */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ProxyConfig; sourceTree = BUILT_PRODUCTS_DIR; };
27+
36B6A3261E263590002B5B1D /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
28+
/* End PBXFileReference section */
29+
30+
/* Begin PBXFrameworksBuildPhase section */
31+
36B6A3201E263590002B5B1D /* Frameworks */ = {
32+
isa = PBXFrameworksBuildPhase;
33+
buildActionMask = 2147483647;
34+
files = (
35+
);
36+
runOnlyForDeploymentPostprocessing = 0;
37+
};
38+
/* End PBXFrameworksBuildPhase section */
39+
40+
/* Begin PBXGroup section */
41+
36B6A31A1E263590002B5B1D = {
42+
isa = PBXGroup;
43+
children = (
44+
36B6A3251E263590002B5B1D /* ProxyConfig */,
45+
36B6A3241E263590002B5B1D /* Products */,
46+
);
47+
sourceTree = "<group>";
48+
};
49+
36B6A3241E263590002B5B1D /* Products */ = {
50+
isa = PBXGroup;
51+
children = (
52+
36B6A3231E263590002B5B1D /* ProxyConfig */,
53+
);
54+
name = Products;
55+
sourceTree = "<group>";
56+
};
57+
36B6A3251E263590002B5B1D /* ProxyConfig */ = {
58+
isa = PBXGroup;
59+
children = (
60+
36B6A3261E263590002B5B1D /* main.swift */,
61+
);
62+
path = ProxyConfig;
63+
sourceTree = "<group>";
64+
};
65+
/* End PBXGroup section */
66+
67+
/* Begin PBXNativeTarget section */
68+
36B6A3221E263590002B5B1D /* ProxyConfig */ = {
69+
isa = PBXNativeTarget;
70+
buildConfigurationList = 36B6A32A1E263590002B5B1D /* Build configuration list for PBXNativeTarget "ProxyConfig" */;
71+
buildPhases = (
72+
36B6A31F1E263590002B5B1D /* Sources */,
73+
36B6A3201E263590002B5B1D /* Frameworks */,
74+
36B6A3211E263590002B5B1D /* CopyFiles */,
75+
);
76+
buildRules = (
77+
);
78+
dependencies = (
79+
);
80+
name = ProxyConfig;
81+
productName = ProxyConfig;
82+
productReference = 36B6A3231E263590002B5B1D /* ProxyConfig */;
83+
productType = "com.apple.product-type.tool";
84+
};
85+
/* End PBXNativeTarget section */
86+
87+
/* Begin PBXProject section */
88+
36B6A31B1E263590002B5B1D /* Project object */ = {
89+
isa = PBXProject;
90+
attributes = {
91+
LastSwiftUpdateCheck = 0820;
92+
LastUpgradeCheck = 0820;
93+
ORGANIZATIONNAME = "Zhuhao Wang";
94+
TargetAttributes = {
95+
36B6A3221E263590002B5B1D = {
96+
CreatedOnToolsVersion = 8.2.1;
97+
ProvisioningStyle = Automatic;
98+
};
99+
};
100+
};
101+
buildConfigurationList = 36B6A31E1E263590002B5B1D /* Build configuration list for PBXProject "ProxyConfig" */;
102+
compatibilityVersion = "Xcode 3.2";
103+
developmentRegion = English;
104+
hasScannedForEncodings = 0;
105+
knownRegions = (
106+
en,
107+
);
108+
mainGroup = 36B6A31A1E263590002B5B1D;
109+
productRefGroup = 36B6A3241E263590002B5B1D /* Products */;
110+
projectDirPath = "";
111+
projectRoot = "";
112+
targets = (
113+
36B6A3221E263590002B5B1D /* ProxyConfig */,
114+
);
115+
};
116+
/* End PBXProject section */
117+
118+
/* Begin PBXSourcesBuildPhase section */
119+
36B6A31F1E263590002B5B1D /* Sources */ = {
120+
isa = PBXSourcesBuildPhase;
121+
buildActionMask = 2147483647;
122+
files = (
123+
36B6A3271E263590002B5B1D /* main.swift in Sources */,
124+
);
125+
runOnlyForDeploymentPostprocessing = 0;
126+
};
127+
/* End PBXSourcesBuildPhase section */
128+
129+
/* Begin XCBuildConfiguration section */
130+
36B6A3281E263590002B5B1D /* Debug */ = {
131+
isa = XCBuildConfiguration;
132+
buildSettings = {
133+
ALWAYS_SEARCH_USER_PATHS = NO;
134+
CLANG_ANALYZER_NONNULL = YES;
135+
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
136+
CLANG_CXX_LIBRARY = "libc++";
137+
CLANG_ENABLE_MODULES = YES;
138+
CLANG_ENABLE_OBJC_ARC = YES;
139+
CLANG_WARN_BOOL_CONVERSION = YES;
140+
CLANG_WARN_CONSTANT_CONVERSION = YES;
141+
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
142+
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
143+
CLANG_WARN_EMPTY_BODY = YES;
144+
CLANG_WARN_ENUM_CONVERSION = YES;
145+
CLANG_WARN_INFINITE_RECURSION = YES;
146+
CLANG_WARN_INT_CONVERSION = YES;
147+
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
148+
CLANG_WARN_SUSPICIOUS_MOVE = YES;
149+
CLANG_WARN_UNREACHABLE_CODE = YES;
150+
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
151+
CODE_SIGN_IDENTITY = "-";
152+
COPY_PHASE_STRIP = NO;
153+
DEBUG_INFORMATION_FORMAT = dwarf;
154+
ENABLE_STRICT_OBJC_MSGSEND = YES;
155+
ENABLE_TESTABILITY = YES;
156+
GCC_C_LANGUAGE_STANDARD = gnu99;
157+
GCC_DYNAMIC_NO_PIC = NO;
158+
GCC_NO_COMMON_BLOCKS = YES;
159+
GCC_OPTIMIZATION_LEVEL = 0;
160+
GCC_PREPROCESSOR_DEFINITIONS = (
161+
"DEBUG=1",
162+
"$(inherited)",
163+
);
164+
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
165+
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
166+
GCC_WARN_UNDECLARED_SELECTOR = YES;
167+
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
168+
GCC_WARN_UNUSED_FUNCTION = YES;
169+
GCC_WARN_UNUSED_VARIABLE = YES;
170+
MACOSX_DEPLOYMENT_TARGET = 10.12;
171+
MTL_ENABLE_DEBUG_INFO = YES;
172+
ONLY_ACTIVE_ARCH = YES;
173+
SDKROOT = macosx;
174+
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
175+
};
176+
name = Debug;
177+
};
178+
36B6A3291E263590002B5B1D /* Release */ = {
179+
isa = XCBuildConfiguration;
180+
buildSettings = {
181+
ALWAYS_SEARCH_USER_PATHS = NO;
182+
CLANG_ANALYZER_NONNULL = YES;
183+
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
184+
CLANG_CXX_LIBRARY = "libc++";
185+
CLANG_ENABLE_MODULES = YES;
186+
CLANG_ENABLE_OBJC_ARC = YES;
187+
CLANG_WARN_BOOL_CONVERSION = YES;
188+
CLANG_WARN_CONSTANT_CONVERSION = YES;
189+
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
190+
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
191+
CLANG_WARN_EMPTY_BODY = YES;
192+
CLANG_WARN_ENUM_CONVERSION = YES;
193+
CLANG_WARN_INFINITE_RECURSION = YES;
194+
CLANG_WARN_INT_CONVERSION = YES;
195+
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
196+
CLANG_WARN_SUSPICIOUS_MOVE = YES;
197+
CLANG_WARN_UNREACHABLE_CODE = YES;
198+
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
199+
CODE_SIGN_IDENTITY = "-";
200+
COPY_PHASE_STRIP = NO;
201+
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
202+
ENABLE_NS_ASSERTIONS = NO;
203+
ENABLE_STRICT_OBJC_MSGSEND = YES;
204+
GCC_C_LANGUAGE_STANDARD = gnu99;
205+
GCC_NO_COMMON_BLOCKS = YES;
206+
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
207+
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
208+
GCC_WARN_UNDECLARED_SELECTOR = YES;
209+
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
210+
GCC_WARN_UNUSED_FUNCTION = YES;
211+
GCC_WARN_UNUSED_VARIABLE = YES;
212+
MACOSX_DEPLOYMENT_TARGET = 10.12;
213+
MTL_ENABLE_DEBUG_INFO = NO;
214+
SDKROOT = macosx;
215+
};
216+
name = Release;
217+
};
218+
36B6A32B1E263590002B5B1D /* Debug */ = {
219+
isa = XCBuildConfiguration;
220+
buildSettings = {
221+
PRODUCT_NAME = "$(TARGET_NAME)";
222+
SWIFT_VERSION = 3.0;
223+
};
224+
name = Debug;
225+
};
226+
36B6A32C1E263590002B5B1D /* Release */ = {
227+
isa = XCBuildConfiguration;
228+
buildSettings = {
229+
PRODUCT_NAME = "$(TARGET_NAME)";
230+
SWIFT_VERSION = 3.0;
231+
};
232+
name = Release;
233+
};
234+
/* End XCBuildConfiguration section */
235+
236+
/* Begin XCConfigurationList section */
237+
36B6A31E1E263590002B5B1D /* Build configuration list for PBXProject "ProxyConfig" */ = {
238+
isa = XCConfigurationList;
239+
buildConfigurations = (
240+
36B6A3281E263590002B5B1D /* Debug */,
241+
36B6A3291E263590002B5B1D /* Release */,
242+
);
243+
defaultConfigurationIsVisible = 0;
244+
defaultConfigurationName = Release;
245+
};
246+
36B6A32A1E263590002B5B1D /* Build configuration list for PBXNativeTarget "ProxyConfig" */ = {
247+
isa = XCConfigurationList;
248+
buildConfigurations = (
249+
36B6A32B1E263590002B5B1D /* Debug */,
250+
36B6A32C1E263590002B5B1D /* Release */,
251+
);
252+
defaultConfigurationIsVisible = 0;
253+
};
254+
/* End XCConfigurationList section */
255+
};
256+
rootObject = 36B6A31B1E263590002B5B1D /* Project object */;
257+
}

‎ClashX/ProxyConfig/ProxyConfig.xcodeproj/project.xcworkspace/contents.xcworkspacedata

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import Foundation
2+
import SystemConfiguration
3+
4+
let version = "0.1.0"
5+
6+
func main(_ args: [String]) {
7+
var port: Int = 0
8+
var socksPort = 0
9+
var flag: Bool = false
10+
11+
if args.count > 3 {
12+
guard let _port = Int(args[1]),
13+
let _socksPort = Int(args[2]) else {
14+
print("ERROR: port is invalid.")
15+
exit(EXIT_FAILURE)
16+
}
17+
guard args[3] == "enable" || args[3] == "disable" else {
18+
print("ERROR: flag is invalid.")
19+
exit(EXIT_FAILURE)
20+
}
21+
port = _port
22+
socksPort = _socksPort
23+
flag = args[3] == "enable"
24+
} else if args.count == 2 {
25+
if args[1] == "version" {
26+
print(version)
27+
exit(EXIT_SUCCESS)
28+
}
29+
} else {
30+
print("Usage: ProxyConfig <port> <socksPort> <enable/disable>")
31+
exit(EXIT_FAILURE)
32+
}
33+
34+
var authRef: AuthorizationRef? = nil
35+
let authFlags: AuthorizationFlags = [.extendRights, .interactionAllowed, .preAuthorize]
36+
37+
let authErr = AuthorizationCreate(nil, nil, authFlags, &authRef)
38+
39+
guard authErr == noErr else {
40+
print("Error: Failed to create administration authorization due to error \(authErr).")
41+
exit(EXIT_FAILURE)
42+
}
43+
44+
guard authRef != nil else {
45+
print("Error: No authorization has been granted to modify network configuration.")
46+
exit(EXIT_FAILURE)
47+
}
48+
49+
if let prefRef = SCPreferencesCreateWithAuthorization(nil, "ClashX" as CFString, nil, authRef),
50+
let sets = SCPreferencesGetValue(prefRef, kSCPrefNetworkServices) {
51+
52+
for key in sets.allKeys {
53+
let dict = sets.object(forKey: key) as? NSDictionary
54+
let hardware = ((dict?["Interface"]) as? NSDictionary)?["Hardware"] as? String
55+
if hardware == "AirPort" || hardware == "Ethernet" {
56+
let ip = flag ? "127.0.0.1" : ""
57+
let enableInt = flag ? 1 : 0
58+
59+
var proxySettings: [String:AnyObject] = [:]
60+
proxySettings[kCFNetworkProxiesHTTPProxy as String] = ip as AnyObject
61+
proxySettings[kCFNetworkProxiesHTTPEnable as String] = enableInt as AnyObject
62+
proxySettings[kCFNetworkProxiesHTTPSProxy as String] = ip as AnyObject
63+
proxySettings[kCFNetworkProxiesHTTPSEnable as String] = enableInt as AnyObject
64+
proxySettings[kCFNetworkProxiesSOCKSProxy as String] = ip as AnyObject
65+
proxySettings[kCFNetworkProxiesSOCKSEnable as String] = enableInt as AnyObject
66+
if flag {
67+
proxySettings[kCFNetworkProxiesHTTPPort as String] = port as AnyObject
68+
proxySettings[kCFNetworkProxiesHTTPSPort as String] = port as AnyObject
69+
proxySettings[kCFNetworkProxiesSOCKSPort as String] = port + 1 as AnyObject
70+
} else {
71+
proxySettings[kCFNetworkProxiesHTTPPort as String] = nil
72+
proxySettings[kCFNetworkProxiesHTTPSPort as String] = nil
73+
proxySettings[kCFNetworkProxiesSOCKSPort as String] = nil
74+
}
75+
proxySettings[kCFNetworkProxiesExceptionsList as String] = [
76+
"192.168.0.0/16",
77+
"10.0.0.0/8",
78+
"172.16.0.0/12",
79+
"127.0.0.1",
80+
"localhost",
81+
"*.local"
82+
] as AnyObject
83+
84+
let path = "/\(kSCPrefNetworkServices)/\(key)/\(kSCEntNetProxies)"
85+
SCPreferencesPathSetValue(prefRef, path as CFString, proxySettings as CFDictionary)
86+
}
87+
}
88+
89+
SCPreferencesCommitChanges(prefRef)
90+
SCPreferencesApplyChanges(prefRef)
91+
}
92+
93+
AuthorizationFree(authRef!, AuthorizationFlags())
94+
95+
exit(EXIT_SUCCESS)
96+
}
97+
98+
main(CommandLine.arguments)

‎ClashX/Support Files/menu_icon.png

331 Bytes
Loading

‎ClashX/Support Files/menu_icon@2x.png

553 Bytes
Loading
338 Bytes
Loading
575 Bytes
Loading

‎ClashX/Support Files/sampleConfig.ini

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[General]
2+
port = 7890
3+
socks-port = 7891
4+
5+
[Proxy]
6+
# name = ss, server, port, cipter, password
7+
{{placeHolder}}
8+
9+
[Rule]
10+
DOMAIN-SUFFIX,google.com,Proxy
11+
DOMAIN-KEYWORD,google,Proxy
12+
DOMAIN-SUFFIX,ad.com,REJECT
13+
GEOIP,CN,DIRECT
14+
FINAL,,Proxy

‎ClashX/ViewController.swift

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//
2+
// ViewController.swift
3+
// ClashX
4+
//
5+
// Created by 称一称 on 2018/6/10.
6+
// Copyright © 2018年 west2online. All rights reserved.
7+
//
8+
9+
import Cocoa
10+
11+
class ViewController: NSViewController {
12+
13+
override func viewDidLoad() {
14+
super.viewDidLoad()
15+
run()
16+
// Do any additional setup after loading the view.
17+
}
18+
19+
override var representedObject: Any? {
20+
didSet {
21+
// Update the view, if already loaded.
22+
}
23+
}
24+
25+
26+
}
27+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//
2+
// SampleConfigViewController.swift
3+
// ClashX
4+
//
5+
// Created by 称一称 on 2018/6/13.
6+
// Copyright © 2018年 west2online. All rights reserved.
7+
//
8+
9+
import Cocoa
10+
11+
class SampleConfigViewController: NSViewController {
12+
13+
@IBOutlet weak var serverAddressTextField: NSTextField!
14+
@IBOutlet weak var serverPortTextField: NSTextField!
15+
@IBOutlet weak var serverPasswordTextField: NSSecureTextField!
16+
@IBOutlet weak var serverencryptMethodBox: NSComboBox!
17+
override func viewDidLoad() {
18+
super.viewDidLoad()
19+
serverencryptMethodBox.addItems(withObjectValues: [
20+
"AES-128-CTR",
21+
"AES-192-CTR",
22+
"AES-256-CTR",
23+
"AES-128-CFB",
24+
"AES-192-CFB",
25+
"AES-256-CFB",
26+
"CHACHA20-IETF",
27+
"XCHACHA20",
28+
"AEAD_AES_128_GCM",
29+
"AEAD_AES_192_GCM",
30+
"AEAD_AES_256_GCM",
31+
"AEAD_CHACHA20_POLY1305"
32+
])
33+
34+
}
35+
36+
func vaildConfig()->Bool {
37+
if let port = Int(serverPortTextField.stringValue) {
38+
if port > 0 && port <= 65535 {
39+
return serverPortTextField.stringValue.count > 0 &&
40+
serverPasswordTextField.stringValue.count > 0
41+
}
42+
}
43+
return false
44+
}
45+
46+
func generateConfig() {
47+
let originalConfig = NSData(contentsOfFile: Bundle.main.path(forResource: "sampleConfig", ofType: "ini")!)
48+
49+
var configStr = String(data: originalConfig! as Data, encoding: .utf8)
50+
51+
let targetStr = "Proxy = ss, \(serverAddressTextField.stringValue), \(serverPortTextField.stringValue), \(serverencryptMethodBox.stringValue), \(serverPasswordTextField.stringValue)"
52+
53+
configStr = configStr?.replacingOccurrences(of: "{{placeHolder}}", with: targetStr)
54+
55+
// save to ~/.config/clash/config.ini
56+
let path = (NSHomeDirectory() as NSString).appendingPathComponent("/.config/clash/config.ini")
57+
58+
if (FileManager.default.fileExists(atPath: path)) {
59+
try? FileManager.default.removeItem(at: URL(fileURLWithPath: path))
60+
}
61+
try? configStr?.write(to: URL(fileURLWithPath: path), atomically: true, encoding: .utf8)
62+
63+
}
64+
65+
66+
@IBAction func actionConfirm(_ sender: Any) {
67+
if (vaildConfig()) {
68+
generateConfig()
69+
}
70+
self.view.window?.windowController?.close()
71+
72+
}
73+
74+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11134" systemVersion="15F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
3+
<dependencies>
4+
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11134"/>
5+
</dependencies>
6+
<objects>
7+
<customObject id="-2" userLabel="File's Owner" customClass="SampleConfigViewController" customModuleProvider="target">
8+
<connections>
9+
<outlet property="view" destination="Hz6-mo-xeY" id="0bl-1N-x8E"/>
10+
</connections>
11+
</customObject>
12+
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
13+
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
14+
<customView id="Hz6-mo-xeY">
15+
<rect key="frame" x="0.0" y="0.0" width="480" height="272"/>
16+
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
17+
</customView>
18+
</objects>
19+
</document>

‎ClashX/script/check_proxy_helper.sh

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/sh
2+
3+
cd "/Library/Application Support/clashX/ProxyConfig"
4+
echo `ls -l ProxyConfig`
5+
6+

‎ClashX/script/install_proxy_helper.sh

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
cd `dirname "${BASH_SOURCE[0]}"`
2+
sudo mkdir -p "/Library/Application Support/clashX/"
3+
sudo cp ProxyConfig "/Library/Application Support/clashX/"
4+
sudo chown root:admin "/Library/Application Support/clashX/ProxyConfig"
5+
sudo chmod +s "/Library/Application Support/clashX/ProxyConfig"
6+
echo done

0 commit comments

Comments
 (0)
Please sign in to comment.