diff --git a/README.md b/README.md index 89fb73e..32dc8a2 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ ref: [GitFlow](http://nvie.com/posts/a-successful-git-branching-model/) ## TODO List -- [ ] Embed the http proxy server [privoxy](http://www.privoxy.org/). +- [x] Embed the http proxy server [privoxy](http://www.privoxy.org/), [get it](https://homebrew.bintray.com/bottles/privoxy-3.0.26.sierra.bottle.tar.gz). ## License diff --git a/ShadowsocksX-NG.xcodeproj/project.pbxproj b/ShadowsocksX-NG.xcodeproj/project.pbxproj index f186387..2afa29a 100755 --- a/ShadowsocksX-NG.xcodeproj/project.pbxproj +++ b/ShadowsocksX-NG.xcodeproj/project.pbxproj @@ -52,6 +52,14 @@ 9BEEF0751D04EF3E00FC52B3 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BEEF0731D04EF3E00FC52B3 /* PreferencesWindowController.swift */; }; 9BEEF0781D04FE8A00FC52B3 /* LaunchAgentUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BEEF0771D04FE8A00FC52B3 /* LaunchAgentUtils.swift */; }; 9BEEF07B1D05631500FC52B3 /* AdvPreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BEEF0791D05631500FC52B3 /* AdvPreferencesWindowController.swift */; }; + C6D429931DA75988002A5711 /* install_privoxy.sh in Resources */ = {isa = PBXBuildFile; fileRef = C6D4298E1DA75988002A5711 /* install_privoxy.sh */; }; + C6D429941DA75988002A5711 /* privoxy in Resources */ = {isa = PBXBuildFile; fileRef = C6D4298F1DA75988002A5711 /* privoxy */; }; + C6D429951DA75988002A5711 /* reload_conf_privoxy.sh in Resources */ = {isa = PBXBuildFile; fileRef = C6D429901DA75988002A5711 /* reload_conf_privoxy.sh */; }; + C6D429961DA75988002A5711 /* start_privoxy.sh in Resources */ = {isa = PBXBuildFile; fileRef = C6D429911DA75988002A5711 /* start_privoxy.sh */; }; + C6D429971DA75988002A5711 /* stop_privoxy.sh in Resources */ = {isa = PBXBuildFile; fileRef = C6D429921DA75988002A5711 /* stop_privoxy.sh */; }; + C6D429991DA76FBC002A5711 /* privoxy.config.example in Resources */ = {isa = PBXBuildFile; fileRef = C6D429981DA76FBC002A5711 /* privoxy.config.example */; }; + C6E28E921DA79380004F8330 /* HTTPPreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6E28E911DA79380004F8330 /* HTTPPreferencesWindowController.swift */; }; + C6E28E951DA79705004F8330 /* HTTPPreferencesWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C6E28E971DA79705004F8330 /* HTTPPreferencesWindowController.xib */; }; C8E42A6C1D4F270A0074C7EA /* UserRulesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8E42A6A1D4F270A0074C7EA /* UserRulesController.swift */; }; C8E42A6E1D4F2CAF0074C7EA /* UserRulesController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C8E42A701D4F2CAF0074C7EA /* UserRulesController.xib */; }; E0E57CCA7EB34B90F9D340F2 /* Pods_ShadowsocksX_NGTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 388120F062D7EB7DD0D8DDCA /* Pods_ShadowsocksX_NGTests.framework */; }; @@ -88,6 +96,18 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 083BF8311D82731900831C68 /* SimplePing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimplePing.h; sourceTree = ""; }; + 083BF8321D82731900831C68 /* SimplePing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SimplePing.m; sourceTree = ""; }; + 083BF8341D82742200831C68 /* NetWorkMonitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetWorkMonitor.swift; sourceTree = ""; }; + 083BF8351D82742200831C68 /* PingClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PingClient.swift; sourceTree = ""; }; + 083BF8381D82759600831C68 /* StatusItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusItemView.swift; sourceTree = ""; }; + 083BF83A1D8275A800831C68 /* SystemThemeChangeHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SystemThemeChangeHelper.swift; sourceTree = ""; }; + 085641E91D7188C400116B27 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; + 08805F181D878CA5009B53E7 /* PingTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PingTest.swift; sourceTree = ""; }; + 0880CE3F1D6FE6D900BD39E2 /* example-gui-config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "example-gui-config.json"; sourceTree = ""; }; + 088EC3961D5F5B8600E40791 /* whitelist.pac */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = whitelist.pac; sourceTree = ""; }; + 088EC3981D5F5BA300E40791 /* whiteiplist.pac */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = whiteiplist.pac; sourceTree = ""; }; + 08AF56C01D6AFA7C00DC4F46 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/PreferencesWindowController.strings"; sourceTree = ""; }; 19083CFCED87354F006967FF /* Pods_ShadowsocksX_NGUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ShadowsocksX_NGUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1E7783AEDB4A3BDDC9FF16AC /* libPods-proxy_conf_helper.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-proxy_conf_helper.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 283ED1A8E9B711AC65670031 /* Pods_ShadowsocksX_NG.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ShadowsocksX_NG.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -161,6 +181,16 @@ 9BEEF0771D04FE8A00FC52B3 /* LaunchAgentUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LaunchAgentUtils.swift; sourceTree = ""; }; 9BEEF0791D05631500FC52B3 /* AdvPreferencesWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvPreferencesWindowController.swift; sourceTree = ""; }; B4E6A97CA843F3943524B686 /* Pods-proxy_conf_helper.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-proxy_conf_helper.debug.xcconfig"; path = "Pods/Target Support Files/Pods-proxy_conf_helper/Pods-proxy_conf_helper.debug.xcconfig"; sourceTree = ""; }; + C6D4298E1DA75988002A5711 /* install_privoxy.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = install_privoxy.sh; sourceTree = ""; }; + C6D4298F1DA75988002A5711 /* privoxy */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = privoxy; sourceTree = ""; }; + C6D429901DA75988002A5711 /* reload_conf_privoxy.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = reload_conf_privoxy.sh; sourceTree = ""; }; + C6D429911DA75988002A5711 /* start_privoxy.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = start_privoxy.sh; sourceTree = ""; }; + C6D429921DA75988002A5711 /* stop_privoxy.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = stop_privoxy.sh; sourceTree = ""; }; + C6D429981DA76FBC002A5711 /* privoxy.config.example */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = privoxy.config.example; sourceTree = ""; }; + C6E28E911DA79380004F8330 /* HTTPPreferencesWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPPreferencesWindowController.swift; sourceTree = ""; }; + C6E28E961DA79705004F8330 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/HTTPPreferencesWindowController.xib; sourceTree = ""; }; + C6E28E991DA79709004F8330 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/HTTPPreferencesWindowController.strings"; sourceTree = ""; }; + C6E28E9B1DA79FB9004F8330 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/MainMenu.strings"; sourceTree = ""; }; C8E42A6A1D4F270A0074C7EA /* UserRulesController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserRulesController.swift; sourceTree = ""; }; C8E42A6F1D4F2CAF0074C7EA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UserRulesController.xib; sourceTree = ""; }; C8E42A721D4F2CB10074C7EA /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/UserRulesController.strings"; sourceTree = ""; }; @@ -215,6 +245,11 @@ 9B07EFB01D048E900052D9DF /* Support Files */ = { isa = PBXGroup; children = ( + C6D4298E1DA75988002A5711 /* install_privoxy.sh */, + C6D4298F1DA75988002A5711 /* privoxy */, + C6D429901DA75988002A5711 /* reload_conf_privoxy.sh */, + C6D429911DA75988002A5711 /* start_privoxy.sh */, + C6D429921DA75988002A5711 /* stop_privoxy.sh */, 9BE8FBBD1D0B1FB900CAFD01 /* libcrypto.1.0.0.dylib */, 9B172A6C1D0ADDDD00B87B9A /* Localizable.strings */, 9B3FFF4B1D09D8F70019A709 /* install_helper.sh */, @@ -233,6 +268,7 @@ 9BEEF0661D04CE8D00FC52B3 /* start_ss_local.sh */, 9BEEF0671D04CE9A00FC52B3 /* stop_ss_local.sh */, 9BEEF0681D04CFE500FC52B3 /* reload_conf_ss_local.sh */, + C6D429981DA76FBC002A5711 /* privoxy.config.example */, ); name = "Support Files"; sourceTree = ""; @@ -314,6 +350,8 @@ 9B0D55481D2CC85400A4A8E2 /* ProxyPreferencesController.xib */, C8E42A6A1D4F270A0074C7EA /* UserRulesController.swift */, C8E42A701D4F2CAF0074C7EA /* UserRulesController.xib */, + C6E28E911DA79380004F8330 /* HTTPPreferencesWindowController.swift */, + C6E28E971DA79705004F8330 /* HTTPPreferencesWindowController.xib */, ); name = UI; sourceTree = ""; @@ -455,26 +493,34 @@ files = ( 9BE8FBBF1D0B211600CAFD01 /* libcrypto.1.0.0.dylib in Resources */, 9B3FFF541D09E2D10019A709 /* proxy_conf_helper in Resources */, + C6E28E951DA79705004F8330 /* HTTPPreferencesWindowController.xib in Resources */, 9BEEF0691D04D4D500FC52B3 /* install_ss_local.sh in Resources */, 9B0D55461D2CC85400A4A8E2 /* ProxyPreferencesController.xib in Resources */, 9B2491B41D0ACC3A003BBECC /* PreferencesWindowController.xib in Resources */, 9B3FFF291D08A1DF0019A709 /* user-rule.txt in Resources */, + C6D429971DA75988002A5711 /* stop_privoxy.sh in Resources */, C8E42A6E1D4F2CAF0074C7EA /* UserRulesController.xib in Resources */, 9BEEF06A1D04D4D500FC52B3 /* start_ss_local.sh in Resources */, 9B3FFF391D08CF110019A709 /* qrcode.min.js in Resources */, 9B3FFF3A1D08CF110019A709 /* qrcode.htm in Resources */, + C6D429941DA75988002A5711 /* privoxy in Resources */, + C6D429991DA76FBC002A5711 /* privoxy.config.example in Resources */, + 0880CE401D6FE6D900BD39E2 /* example-gui-config.json in Resources */, 9BEEF06B1D04D4D500FC52B3 /* stop_ss_local.sh in Resources */, 9B3FFF341D08CEF70019A709 /* SWBQRCodeWindowController.xib in Resources */, 9BEEF06C1D04D4D500FC52B3 /* reload_conf_ss_local.sh in Resources */, 9B3FFF231D088E8D0019A709 /* abp.js in Resources */, 9B07EFAD1D048E880052D9DF /* menu_icon.png in Resources */, + C6D429951DA75988002A5711 /* reload_conf_privoxy.sh in Resources */, 9B0BFFEB1D0460A70040E62B /* Assets.xcassets in Resources */, 9B2491B71D0ACC3E003BBECC /* AdvPreferencesWindowController.xib in Resources */, 9B3FFF381D08CF110019A709 /* jquery.min.js in Resources */, 9B3FFF271D0898EB0019A709 /* gfwlist.txt in Resources */, + C6D429931DA75988002A5711 /* install_privoxy.sh in Resources */, 9BC70EDC1D2E3E3100EDA4CA /* Localizable.strings in Resources */, 9B0BFFEE1D0460A70040E62B /* MainMenu.xib in Resources */, 9B3FFF4C1D09D8F70019A709 /* install_helper.sh in Resources */, + C6D429961DA75988002A5711 /* start_privoxy.sh in Resources */, 9B07EFAC1D048E880052D9DF /* menu_icon@2x.png in Resources */, 9B07EFA71D048BBB0052D9DF /* ss-local in Resources */, 9B07EFAF1D048E880052D9DF /* menu_icon_disabled@2x.png in Resources */, @@ -635,6 +681,7 @@ 9B0BFFE91D0460A70040E62B /* AppDelegate.swift in Sources */, 9BA04B231D23D5A5005AAD7F /* ProxyConfTool.m in Sources */, 9BEEF0781D04FE8A00FC52B3 /* LaunchAgentUtils.swift in Sources */, + C6E28E921DA79380004F8330 /* HTTPPreferencesWindowController.swift in Sources */, C8E42A6C1D4F270A0074C7EA /* UserRulesController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -676,6 +723,7 @@ children = ( 9B0BFFED1D0460A70040E62B /* Base */, 9B0D55451D2CC1B800A4A8E2 /* zh-Hans */, + C6E28E9B1DA79FB9004F8330 /* zh-Hans */, ); name = MainMenu.xib; sourceTree = ""; @@ -716,6 +764,15 @@ name = AdvPreferencesWindowController.xib; sourceTree = ""; }; + C6E28E971DA79705004F8330 /* HTTPPreferencesWindowController.xib */ = { + isa = PBXVariantGroup; + children = ( + C6E28E961DA79705004F8330 /* Base */, + C6E28E991DA79709004F8330 /* zh-Hans */, + ); + name = HTTPPreferencesWindowController.xib; + sourceTree = ""; + }; C8E42A701D4F2CAF0074C7EA /* UserRulesController.xib */ = { isa = PBXVariantGroup; children = ( diff --git a/ShadowsocksX-NG/AppDelegate.swift b/ShadowsocksX-NG/AppDelegate.swift index 1b678af..60796e8 100755 --- a/ShadowsocksX-NG/AppDelegate.swift +++ b/ShadowsocksX-NG/AppDelegate.swift @@ -17,6 +17,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele var advPreferencesWinCtrl: AdvPreferencesWindowController! var proxyPreferencesWinCtrl: ProxyPreferencesController! var editUserRulesWinCtrl: UserRulesController! + var httpPreferencesWinCtrl : HTTPPreferencesWindowController! var launchAtLoginController: LaunchAtLoginController = LaunchAtLoginController() @@ -49,7 +50,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele // Prepare ss-local InstallSSLocal() - + InstallPrivoxy() // Prepare defaults let defaults = UserDefaults.standard defaults.register(defaults: [ @@ -63,7 +64,11 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele "LocalSocks5.EnableUDPRelay": NSNumber(value: false as Bool), "LocalSocks5.EnableVerboseMode": NSNumber(value: false as Bool), "GFWListURL": "https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt", - "AutoConfigureNetworkServices": NSNumber(value: true as Bool) + "AutoConfigureNetworkServices": NSNumber(value: true as Bool), + "LocalHTTP.ListenAddress": "127.0.0.1", + "LocalHTTP.ListenPort": NSNumber(value: 1087 as UInt16), + "LocalHTTPOn": true, + "LocalHTTP.FollowGlobel": true ]) statusItem = NSStatusBar.system().statusItem(withLength: AppDelegate.StatusItemIconWidth) @@ -101,6 +106,13 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele self.applyConfig() } ) + notifyCenter.addObserver(forName: NSNotification.Name(rawValue: NOTIFY_HTTP_CONF_CHANGED), object: nil, queue: nil + , using: { + (note) in + SyncPrivoxy() + self.applyConfig() + } + ) notifyCenter.addObserver(forName: NSNotification.Name(rawValue: "NOTIFY_FOUND_SS_URL"), object: nil, queue: nil) { (note: Notification) in if let userInfo = (note as NSNotification).userInfo { @@ -158,6 +170,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele func applicationWillTerminate(_ aNotification: Notification) { // Insert code here to tear down your application StopSSLocal() + StopPrivoxy() ProxyConfHelper.disableProxy("hi") let defaults = UserDefaults.standard defaults.set(false, forKey: "ShadowsocksOn") @@ -171,6 +184,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele if isOn { StartSSLocal() + StartPrivoxy() if mode == "auto" { ProxyConfHelper.enablePACProxy("hi") } else if mode == "global" { @@ -180,6 +194,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele } } else { StopSSLocal() + StopPrivoxy() ProxyConfHelper.disableProxy("hi") } } @@ -294,6 +309,18 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele ctrl.window?.makeKeyAndOrderFront(self) } + @IBAction func editHTTPPreferences(_ sender: NSMenuItem) { + if httpPreferencesWinCtrl != nil { + httpPreferencesWinCtrl.close() + } + let ctrl = HTTPPreferencesWindowController(windowNibName: "HTTPPreferencesWindowController") + httpPreferencesWinCtrl = ctrl + + ctrl.showWindow(self) + NSApp.activate(ignoringOtherApps: true) + ctrl.window?.makeKeyAndOrderFront(self) + } + @IBAction func editProxyPreferences(_ sender: NSObject) { if proxyPreferencesWinCtrl != nil { proxyPreferencesWinCtrl.close() diff --git a/ShadowsocksX-NG/Base.lproj/HTTPPreferencesWindowController.xib b/ShadowsocksX-NG/Base.lproj/HTTPPreferencesWindowController.xib new file mode 100644 index 0000000..a3cd38c --- /dev/null +++ b/ShadowsocksX-NG/Base.lproj/HTTPPreferencesWindowController.xib @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ShadowsocksX-NG/Base.lproj/MainMenu.xib b/ShadowsocksX-NG/Base.lproj/MainMenu.xib index 40e65f0..92b450c 100755 --- a/ShadowsocksX-NG/Base.lproj/MainMenu.xib +++ b/ShadowsocksX-NG/Base.lproj/MainMenu.xib @@ -126,6 +126,12 @@ + + + + + + @@ -160,5 +166,18 @@ + + + + + + + + + + + + + diff --git a/ShadowsocksX-NG/HTTPPreferencesWindowController.swift b/ShadowsocksX-NG/HTTPPreferencesWindowController.swift new file mode 100644 index 0000000..36326e6 --- /dev/null +++ b/ShadowsocksX-NG/HTTPPreferencesWindowController.swift @@ -0,0 +1,27 @@ +// +// HTTPPreferencesWindowController.swift +// ShadowsocksX-NG +// +// Created by 王晨 on 2016/10/7. +// Copyright © 2016年 qiuyuzhou. All rights reserved. +// + +import Cocoa + +class HTTPPreferencesWindowController: NSWindowController, NSWindowDelegate { + + override func windowDidLoad() { + super.windowDidLoad() + + // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. + self.window?.delegate = self + } + + //------------------------------------------------------------ + // NSWindowDelegate + func windowWillClose(_ notification: Notification) { + NotificationCenter.default + .post(name: Notification.Name(rawValue: NOTIFY_HTTP_CONF_CHANGED), object: nil) + } + +} diff --git a/ShadowsocksX-NG/LaunchAgentUtils.swift b/ShadowsocksX-NG/LaunchAgentUtils.swift index ad44279..e5357c9 100644 --- a/ShadowsocksX-NG/LaunchAgentUtils.swift +++ b/ShadowsocksX-NG/LaunchAgentUtils.swift @@ -9,9 +9,11 @@ import Foundation let SS_LOCAL_VERSION = "2.4.6" +let PRIVOXY_VERSION = "3.0.26.static" let APP_SUPPORT_DIR = "/Library/Application Support/ShadowsocksX-NG/" let LAUNCH_AGENT_DIR = "/Library/LaunchAgents/" -let LAUNCH_AGENT_CONF_NAME = "com.qiuyuzhou.shadowsocksX-NG.local.plist" +let LAUNCH_AGENT_CONF_SSLOCAL_NAME = "com.qiuyuzhou.shadowsocksX-NG.local.plist" +let LAUNCH_AGENT_CONF_PRIVOXY_NAME = "com.qiuyuzhou.shadowsocksX-NG.http.plist" func getFileSHA1Sum(_ filepath: String) -> String { @@ -23,11 +25,14 @@ func getFileSHA1Sum(_ filepath: String) -> String { // Ref: https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html // Genarate the mac launch agent service plist + +// MARK: sslocal + func generateSSLocalLauchAgentPlist() -> Bool { let sslocalPath = NSHomeDirectory() + APP_SUPPORT_DIR + "ss-local" let logFilePath = NSHomeDirectory() + "/Library/Logs/ss-local.log" let launchAgentDirPath = NSHomeDirectory() + LAUNCH_AGENT_DIR - let plistFilepath = launchAgentDirPath + LAUNCH_AGENT_CONF_NAME + let plistFilepath = launchAgentDirPath + LAUNCH_AGENT_CONF_SSLOCAL_NAME // Ensure launch agent directory is existed. let fileMgr = FileManager.default @@ -168,4 +173,150 @@ func SyncSSLocal() { StopSSLocal() } SyncPac() + SyncPrivoxy() +} + +// MARK: privoxy + +func generatePrivoxyLauchAgentPlist() -> Bool { + let privoxyPath = NSHomeDirectory() + APP_SUPPORT_DIR + "privoxy" + let logFilePath = NSHomeDirectory() + "/Library/Logs/privoxy.log" + let launchAgentDirPath = NSHomeDirectory() + LAUNCH_AGENT_DIR + let plistFilepath = launchAgentDirPath + LAUNCH_AGENT_CONF_PRIVOXY_NAME + + // Ensure launch agent directory is existed. + let fileMgr = FileManager.default + if !fileMgr.fileExists(atPath: launchAgentDirPath) { + try! fileMgr.createDirectory(atPath: launchAgentDirPath, withIntermediateDirectories: true, attributes: nil) + } + + let oldSha1Sum = getFileSHA1Sum(plistFilepath) + + let arguments = [privoxyPath, "--no-daemon", "privoxy.config"] + + // For a complete listing of the keys, see the launchd.plist manual page. + let dict: NSMutableDictionary = [ + "Label": "com.qiuyuzhou.shadowsocksX-NG.http", + "WorkingDirectory": NSHomeDirectory() + APP_SUPPORT_DIR, + "KeepAlive": true, + "StandardOutPath": logFilePath, + "StandardErrorPath": logFilePath, + "ProgramArguments": arguments + ] + dict.write(toFile: plistFilepath, atomically: true) + let Sha1Sum = getFileSHA1Sum(plistFilepath) + if oldSha1Sum != Sha1Sum { + return true + } else { + return false + } +} + + +func ReloadConfPrivoxy() { + let bundle = Bundle.main + let installerPath = bundle.path(forResource: "reload_conf_privoxy.sh", ofType: nil) + let task = Process.launchedProcess(launchPath: installerPath!, arguments: [""]) + task.waitUntilExit() + if task.terminationStatus == 0 { + NSLog("reload privoxy succeeded.") + } else { + NSLog("reload privoxy failed.") + } +} + +func StartPrivoxy() { + let bundle = Bundle.main + let installerPath = bundle.path(forResource: "start_privoxy.sh", ofType: nil) + let task = Process.launchedProcess(launchPath: installerPath!, arguments: [""]) + task.waitUntilExit() + if task.terminationStatus == 0 { + NSLog("Start privoxy succeeded.") + } else { + NSLog("Start privoxy failed.") + } +} + +func StopPrivoxy() { + let bundle = Bundle.main + let installerPath = bundle.path(forResource: "stop_privoxy.sh", ofType: nil) + let task = Process.launchedProcess(launchPath: installerPath!, arguments: [""]) + task.waitUntilExit() + if task.terminationStatus == 0 { + NSLog("Stop privoxy succeeded.") + } else { + NSLog("Stop privoxy failed.") + } +} + +func InstallPrivoxy() { + let fileMgr = FileManager.default + let homeDir = NSHomeDirectory() + let appSupportDir = homeDir+APP_SUPPORT_DIR + if !fileMgr.fileExists(atPath: appSupportDir + "privoxy-\(PRIVOXY_VERSION)/privoxy") { + let bundle = Bundle.main + let installerPath = bundle.path(forResource: "install_privoxy.sh", ofType: nil) + let task = Process.launchedProcess(launchPath: installerPath!, arguments: [""]) + task.waitUntilExit() + if task.terminationStatus == 0 { + NSLog("Install privoxy succeeded.") + } else { + NSLog("Install privoxy failed.") + } + } +} + +func writePrivoxyConfFile() -> Bool { + do { + let defaults = UserDefaults.standard + let bundle = Bundle.main + let examplePath = bundle.path(forResource: "privoxy.config.example", ofType: nil) + var example = try String(contentsOfFile: examplePath!, encoding: .utf8) + example = example.replacingOccurrences(of: "{http}", with: defaults.string(forKey: "LocalHTTP.ListenAddress")! + ":" + String(defaults.integer(forKey: "LocalHTTP.ListenPort"))) + example = example.replacingOccurrences(of: "{socks5}", with: defaults.string(forKey: "LocalSocks5.ListenAddress")! + ":" + String(defaults.integer(forKey: "LocalSocks5.ListenPort"))) + let data = example.data(using: .utf8) + + let filepath = NSHomeDirectory() + APP_SUPPORT_DIR + "privoxy.config" + + let oldSum = getFileSHA1Sum(filepath) + try data?.write(to: URL(fileURLWithPath: filepath), options: .atomic) + let newSum = getFileSHA1Sum(filepath) + + if oldSum == newSum { + return false + } + + return true + } catch { + NSLog("Write privoxy file failed.") + } + return false +} + +func removePrivoxyConfFile() { + do { + let filepath = NSHomeDirectory() + APP_SUPPORT_DIR + "privoxy.config" + try FileManager.default.removeItem(atPath: filepath) + } catch { + + } +} + +func SyncPrivoxy() { + var changed: Bool = false + changed = changed || generatePrivoxyLauchAgentPlist() + let mgr = ServerProfileManager.instance + if mgr.activeProfileId != nil { + changed = changed || writePrivoxyConfFile() + + let on = UserDefaults.standard.bool(forKey: "LocalHTTPOn") + if on { +// StartPrivoxy() + ReloadConfPrivoxy() + } + else { + removePrivoxyConfFile() + StopPrivoxy() + } + } } diff --git a/ShadowsocksX-NG/Notifications.swift b/ShadowsocksX-NG/Notifications.swift index 69b798f..09da2db 100644 --- a/ShadowsocksX-NG/Notifications.swift +++ b/ShadowsocksX-NG/Notifications.swift @@ -10,4 +10,6 @@ import Foundation let NOTIFY_SERVER_PROFILES_CHANGED = "NOTIFY_SERVER_PROFILES_CHANGED" let NOTIFY_ADV_PROXY_CONF_CHANGED = "NOTIFY_ADV_PROXY_CONF_CHANGED" -let NOTIFY_ADV_CONF_CHANGED = "NOTIFY_ADV_CONF_CHANGED" \ No newline at end of file +let NOTIFY_ADV_CONF_CHANGED = "NOTIFY_ADV_CONF_CHANGED" +let NOTIFY_HTTP_CONF_CHANGED = "NOTIFY_HTTP_CONF_CHANGED" +let NOTIFY_INVALIDE_QR = "NOTIFY_INVALIDE_QR" diff --git a/ShadowsocksX-NG/ProxyConfHelper.m b/ShadowsocksX-NG/ProxyConfHelper.m index c716e93..6089ae0 100644 --- a/ShadowsocksX-NG/ProxyConfHelper.m +++ b/ShadowsocksX-NG/ProxyConfHelper.m @@ -134,6 +134,13 @@ GCDWebServer *webServer =nil; NSMutableArray* args = [@[@"--mode", @"global", @"--port" , [NSString stringWithFormat:@"%lu", (unsigned long)port]]mutableCopy]; + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"LocalHTTPOn"] && [[NSUserDefaults standardUserDefaults] boolForKey:@"LocalHTTP.FollowGlobel"]) { + NSUInteger privoxyPort = [[NSUserDefaults standardUserDefaults]integerForKey:@"LocalHTTP.ListenPort"]; + + [args addObject:@"--privoxy-port"]; + [args addObject:[NSString stringWithFormat:@"%lu", (unsigned long)privoxyPort]]; + } + [self addArguments4ManualSpecifyNetworkServices:args]; [self callHelper:args]; [self stopPACServer]; diff --git a/ShadowsocksX-NG/install_privoxy.sh b/ShadowsocksX-NG/install_privoxy.sh new file mode 100755 index 0000000..a89d9e8 --- /dev/null +++ b/ShadowsocksX-NG/install_privoxy.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +# install_privoxy.sh +# ShadowsocksX-NG +# +# Created by 王晨 on 16/10/7. +# Copyright © 2016年 zhfish. All rights reserved. + + +cd `dirname "${BASH_SOURCE[0]}"` +privoxyVersion=3.0.26.static +mkdir -p "$HOME/Library/Application Support/ShadowsocksX-NG/privoxy-$privoxyVersion" +cp -f privoxy "$HOME/Library/Application Support/ShadowsocksX-NG/privoxy-$privoxyVersion/" +rm -f "$HOME/Library/Application Support/ShadowsocksX-NG/privoxy" +ln -s "$HOME/Library/Application Support/ShadowsocksX-NG/privoxy-$privoxyVersion/privoxy" "$HOME/Library/Application Support/ShadowsocksX-NG/privoxy" + +echo done diff --git a/ShadowsocksX-NG/privoxy b/ShadowsocksX-NG/privoxy new file mode 100755 index 0000000..8c84e79 Binary files /dev/null and b/ShadowsocksX-NG/privoxy differ diff --git a/ShadowsocksX-NG/privoxy.config.example b/ShadowsocksX-NG/privoxy.config.example new file mode 100644 index 0000000..41fa850 --- /dev/null +++ b/ShadowsocksX-NG/privoxy.config.example @@ -0,0 +1,18 @@ +listen-address {http} +toggle 1 +enable-remote-toggle 1 +enable-remote-http-toggle 1 +enable-edit-actions 0 +enforce-blocks 0 +buffer-limit 4096 +forwarded-connect-retries 0 +accept-intercepted-requests 0 +allow-cgi-request-crunching 0 +split-large-forms 0 +keep-alive-timeout 5 +socket-timeout 60 + +forward-socks5 / {socks5} . +forward 192.168.*.*/ . +forward 10.*.*.*/ . +forward 127.*.*.*/ . diff --git a/ShadowsocksX-NG/proxy_conf_helper_version.h b/ShadowsocksX-NG/proxy_conf_helper_version.h index da95803..959f3c9 100644 --- a/ShadowsocksX-NG/proxy_conf_helper_version.h +++ b/ShadowsocksX-NG/proxy_conf_helper_version.h @@ -9,6 +9,6 @@ #ifndef proxy_conf_helper_version_h #define proxy_conf_helper_version_h -#define kProxyConfHelperVersion @"1.3.1" +#define kProxyConfHelperVersion @"1.3.2" #endif /* proxy_conf_helper_version_h */ diff --git a/ShadowsocksX-NG/reload_conf_privoxy.sh b/ShadowsocksX-NG/reload_conf_privoxy.sh new file mode 100755 index 0000000..f8e435c --- /dev/null +++ b/ShadowsocksX-NG/reload_conf_privoxy.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +# reload_privoxy.sh +# ShadowsocksX-NG +# +# Created by 王晨 on 16/10/7. +# Copyright © 2016年 zhfish. All rights reserved. + +#launchctl kill SIGHUP "$HOME/Library/LaunchAgents/com.qiuyuzhou.shadowsocksX-NG.http.plist" + +launchctl unload "$HOME/Library/LaunchAgents/com.qiuyuzhou.shadowsocksX-NG.http.plist" +launchctl load "$HOME/Library/LaunchAgents/com.qiuyuzhou.shadowsocksX-NG.http.plist" diff --git a/ShadowsocksX-NG/start_privoxy.sh b/ShadowsocksX-NG/start_privoxy.sh new file mode 100755 index 0000000..bedef6a --- /dev/null +++ b/ShadowsocksX-NG/start_privoxy.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +# start_privoxy.sh +# ShadowsocksX-NG +# +# Created by 王晨 on 16/10/7. +# Copyright © 2016年 zhfish. All rights reserved. + +launchctl load "$HOME/Library/LaunchAgents/com.qiuyuzhou.shadowsocksX-NG.http.plist" diff --git a/ShadowsocksX-NG/stop_privoxy.sh b/ShadowsocksX-NG/stop_privoxy.sh new file mode 100755 index 0000000..8cb6a2b --- /dev/null +++ b/ShadowsocksX-NG/stop_privoxy.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +# stop_privoxy.sh +# ShadowsocksX-NG +# +# Created by 王晨 on 16/10/7. +# Copyright © 2016年 zhfish. All rights reserved. + + + +launchctl unload "$HOME/Library/LaunchAgents/com.qiuyuzhou.shadowsocksX-NG.http.plist" diff --git a/ShadowsocksX-NG/zh-Hans.lproj/AdvPreferencesWindowController.strings b/ShadowsocksX-NG/zh-Hans.lproj/AdvPreferencesWindowController.strings index bcde501..f01ad9b 100644 --- a/ShadowsocksX-NG/zh-Hans.lproj/AdvPreferencesWindowController.strings +++ b/ShadowsocksX-NG/zh-Hans.lproj/AdvPreferencesWindowController.strings @@ -18,10 +18,22 @@ "cwr-n0-zwn.title" = "本地 Socks5 监听地址:"; /* Class = "NSTextFieldCell"; title = "GFW List URL:"; ObjectID = "dg0-gS-z5V"; */ -"dg0-gS-z5V.title" = "GFW List URL:"; +"dg0-gS-z5V.title" = "GFW LIST URL:"; /* Class = "NSTextFieldCell"; title = "Timeout:"; ObjectID = "i4l-2S-gOQ"; */ "i4l-2S-gOQ.title" = "超时:"; /* Class = "NSTextFieldCell"; title = "本地 Socks5 监听端口:"; ObjectID = "qRs-ow-vVB"; */ "qRs-ow-vVB.title" = "本地 Socks5 监听端口:"; + +/* Class = "NSTextFieldCell"; title = "Local PAC Listen Address:"; ObjectID = "dvL-Ic-Wae"; */ +"dvL-Ic-Wae.title" = "本地 PAC 监听地址:"; + +/* Class = "NSTextFieldCell"; title = "Local PAC Listen Port:"; ObjectID = "PSg-XK-qhl"; */ +"PSg-XK-qhl.title" = "本地 PAC 监听端口:"; + +/* Class = "NSTextFieldCell"; title = "White List URL:"; ObjectID = "aif-uV-Lxk"; */ +"aif-uV-Lxk.title" = "白名单列表 URL:"; + +/* Class = "NSTextFieldCell"; title = "White IP List URL:"; ObjectID = "qhu-d1-qgq"; */ +"qhu-d1-qgq.title" = "白名单IP列表 URL:"; diff --git a/ShadowsocksX-NG/zh-Hans.lproj/HTTPPreferencesWindowController.strings b/ShadowsocksX-NG/zh-Hans.lproj/HTTPPreferencesWindowController.strings new file mode 100644 index 0000000..7a2e9e9 --- /dev/null +++ b/ShadowsocksX-NG/zh-Hans.lproj/HTTPPreferencesWindowController.strings @@ -0,0 +1,15 @@ + +/* Class = "NSTextFieldCell"; title = "HTTP Proxy Listen Port:"; ObjectID = "2Sd-yn-gdY"; */ +"2Sd-yn-gdY.title" = "HTTP 代理 监听端口:"; + +/* Class = "NSButtonCell"; title = "HTTP Proxy Enable"; ObjectID = "dqU-MG-Sum"; */ +"dqU-MG-Sum.title" = "HTTP 代理 开启"; + +/* Class = "NSTextFieldCell"; title = "HTTP Proxy Listen Address:"; ObjectID = "qd0-kc-ttB"; */ +"qd0-kc-ttB.title" = "HTTP 代理 监听地址:"; + +/* Class = "NSWindow"; title = "HTTP Proxy Preferences"; ObjectID = "vS3-DL-Nq3"; */ +"vS3-DL-Nq3.title" = "HTTP 代理 设置"; + +/* Class = "NSButtonCell"; title = "Follow Globel Mode"; ObjectID = "ofk-Pc-c8f"; */ +"ofk-Pc-c8f.title" = "跟随全局模式"; diff --git a/ShadowsocksX-NG/zh-Hans.lproj/MainMenu.strings b/ShadowsocksX-NG/zh-Hans.lproj/MainMenu.strings index 29dde32..99145f2 100644 --- a/ShadowsocksX-NG/zh-Hans.lproj/MainMenu.strings +++ b/ShadowsocksX-NG/zh-Hans.lproj/MainMenu.strings @@ -67,3 +67,16 @@ /* Class = "NSMenuItem"; title = "退出"; ObjectID = "vJS-JW-byz"; */ "vJS-JW-byz.title" = "退出"; + +/* Class = "NSMenuItem"; title = "Ping server"; ObjectID = "zfR-Jt-GmS"; */ +"zfR-Jt-GmS.title" = "服务器测速"; + +/* Class = "NSMenuItem"; title = "Show network speed"; ObjectID = "a3h-uQ-DuO"; */ +"a3h-uQ-DuO.title" = "显示网速"; + +/* Class = "NSMenuItem"; title = "Connect At Launch"; ObjectID = "aB3-cf-5j0"; */ +"aB3-cf-5j0.title" = "打开时自动连接"; + +/* Class = "NSMenuItem"; title = "HTTP Proxy Preference ..."; ObjectID = "uEp-Gz-cu0"; */ +"uEp-Gz-cu0.title" = "HTTP代理设置..."; + diff --git a/proxy_conf_helper/main.m b/proxy_conf_helper/main.m index 039846b..e1f39db 100644 --- a/proxy_conf_helper/main.m +++ b/proxy_conf_helper/main.m @@ -22,9 +22,10 @@ int main(int argc, const char * argv[]) NSString* mode; NSString* pacURL; NSString* portString; + NSString* privoxyPortString; BRLOptionParser *options = [BRLOptionParser new]; - [options setBanner:@"Usage: %s [-v] [-m auto|global|off] [-u ] [-p ]", argv[0]]; + [options setBanner:@"Usage: %s [-v] [-m auto|global|off] [-u ] [-p ] [-r ]", argv[0]]; // Version [options addOption:"version" flag:'v' description:@"Print the version number." block:^{ @@ -40,11 +41,13 @@ int main(int argc, const char * argv[]) }]; // Mode - [options addOption:"mode" flag:'m' description:@"Proxy mode, may be: auto,blobal,off" argument:&mode]; + [options addOption:"mode" flag:'m' description:@"Proxy mode, may be: auto,global,off" argument:&mode]; [options addOption:"pac-url" flag:'u' description:@"PAC file url for auto mode." argument:&pacURL]; [options addOption:"port" flag:'p' description:@"Listen port for global mode." argument:&portString]; + [options addOption:"privoxy-port" flag:'r' description:@"Privoxy Port for global mode." argument:&privoxyPortString]; + NSMutableSet* networkServiceKeys = [NSMutableSet set]; [options addOption:"network-service" flag:'n' description:@"Manual specify the network profile need to set proxy." blockWithArgument:^(NSString* value){ [networkServiceKeys addObject:value]; @@ -57,7 +60,6 @@ int main(int argc, const char * argv[]) exit(EXIT_FAILURE); } - NSInteger port = 0; if (mode) { if ([@"auto" isEqualToString:mode]) { if (!pacURL) { @@ -75,6 +77,7 @@ int main(int argc, const char * argv[]) return 0; } + NSInteger port = 0; if (portString) { port = [portString integerValue]; if (0 == port) { @@ -82,6 +85,14 @@ int main(int argc, const char * argv[]) } } + NSInteger privoxyPort = 0; + if (privoxyPortString) { + privoxyPort = [privoxyPortString integerValue]; + if (0 == privoxyPort) { + return 1; + } + } + static AuthorizationRef authRef; static AuthorizationFlags authFlags; authFlags = kAuthorizationFlagDefaults @@ -149,6 +160,22 @@ int main(int argc, const char * argv[]) kCFNetworkProxiesSOCKSEnable]; [proxies setObject:@[@"127.0.0.1", @"localhost"] forKey:(NSString *)kCFNetworkProxiesExceptionsList]; + if (privoxyPort != 0) { + [proxies setObject:@"127.0.0.1" forKey:(NSString *) + kCFNetworkProxiesHTTPProxy]; + [proxies setObject:[NSNumber numberWithInteger:privoxyPort] forKey:(NSString*) + kCFNetworkProxiesHTTPPort]; + [proxies setObject:[NSNumber numberWithInt:1] forKey:(NSString*) + kCFNetworkProxiesHTTPEnable]; + + [proxies setObject:@"127.0.0.1" forKey:(NSString *) + kCFNetworkProxiesHTTPSProxy]; + [proxies setObject:[NSNumber numberWithInteger:privoxyPort] forKey:(NSString*) + kCFNetworkProxiesHTTPSPort]; + [proxies setObject:[NSNumber numberWithInt:1] forKey:(NSString*) + kCFNetworkProxiesHTTPSEnable]; + } + SCPreferencesPathSetValue(prefRef, (__bridge CFStringRef)prefPath , (__bridge CFDictionaryRef)proxies); } else if ([mode isEqualToString:@"off"]) {