@@ -0,0 +1,30 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace Shadowsocks.Net.Settings | |||
{ | |||
public class ForwardProxySettings | |||
{ | |||
public bool NoProxy { get; set; } | |||
public bool UseSocks5Proxy { get; set; } | |||
public bool UseHttpProxy { get; set; } | |||
public string Address { get; set; } | |||
public int Port { get; set; } | |||
public string Username { get; set; } | |||
public string Password { get; set; } | |||
public ForwardProxySettings() | |||
{ | |||
NoProxy = true; | |||
UseSocks5Proxy = false; | |||
UseHttpProxy = false; | |||
Address = ""; | |||
Port = 1088; | |||
Username = ""; | |||
Password = ""; | |||
} | |||
} | |||
} |
@@ -12,6 +12,8 @@ namespace Shadowsocks.Net.Settings | |||
public string HttpListeningAddress { get; set; } | |||
public int Socks5ListeningPort { get; set; } | |||
public int HttpListeningPort { get; set; } | |||
public ForwardProxySettings ForwardProxy { get; set; } | |||
public NetSettings() | |||
{ | |||
@@ -21,6 +23,8 @@ namespace Shadowsocks.Net.Settings | |||
HttpListeningAddress = "::1"; | |||
Socks5ListeningPort = 1080; | |||
HttpListeningPort = 1080; | |||
ForwardProxy = new ForwardProxySettings(); | |||
} | |||
} | |||
} |
@@ -0,0 +1,76 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> | |||
<assemblyIdentity version="5.0.0.0" name="Shadowsocks.WPF"/> | |||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> | |||
<security> | |||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> | |||
<!-- UAC Manifest Options | |||
If you want to change the Windows User Account Control level replace the | |||
requestedExecutionLevel node with one of the following. | |||
<requestedExecutionLevel level="asInvoker" uiAccess="false" /> | |||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> | |||
<requestedExecutionLevel level="highestAvailable" uiAccess="false" /> | |||
Specifying requestedExecutionLevel element will disable file and registry virtualization. | |||
Remove this element if your application requires this virtualization for backwards | |||
compatibility. | |||
--> | |||
<requestedExecutionLevel level="asInvoker" uiAccess="false" /> | |||
</requestedPrivileges> | |||
</security> | |||
</trustInfo> | |||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> | |||
<application> | |||
<!-- A list of the Windows versions that this application has been tested on | |||
and is designed to work with. Uncomment the appropriate elements | |||
and Windows will automatically select the most compatible environment. --> | |||
<!-- Windows Vista --> | |||
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />--> | |||
<!-- Windows 7 --> | |||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" /> | |||
<!-- Windows 8 --> | |||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" /> | |||
<!-- Windows 8.1 --> | |||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" /> | |||
<!-- Windows 10 --> | |||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" /> | |||
</application> | |||
</compatibility> | |||
<!-- Indicates that the application is DPI-aware and will not be automatically scaled by Windows at higher | |||
DPIs. Windows Presentation Foundation (WPF) applications are automatically DPI-aware and do not need | |||
to opt in. Windows Forms applications targeting .NET Framework 4.6 that opt into this setting, should | |||
also set the 'EnableWindowsFormsHighDpiAutoResizing' setting to 'true' in their app.config. --> | |||
<application xmlns="urn:schemas-microsoft-com:asm.v3"> | |||
<windowsSettings> | |||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor, System</dpiAwareness> | |||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware> | |||
</windowsSettings> | |||
</application> | |||
<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) --> | |||
<!-- | |||
<dependency> | |||
<dependentAssembly> | |||
<assemblyIdentity | |||
type="win32" | |||
name="Microsoft.Windows.Common-Controls" | |||
version="6.0.0.0" | |||
processorArchitecture="*" | |||
publicKeyToken="6595b64144ccf1df" | |||
language="*" | |||
/> | |||
</dependentAssembly> | |||
</dependency> | |||
--> | |||
</assembly> |
@@ -1,43 +0,0 @@ | |||
using System; | |||
namespace Shadowsocks.WPF.Models | |||
{ | |||
[Serializable] | |||
public class ForwardProxyConfig | |||
{ | |||
public const int PROXY_SOCKS5 = 0; | |||
public const int PROXY_HTTP = 1; | |||
public const int MaxProxyTimeoutSec = 10; | |||
private const int DefaultProxyTimeoutSec = 3; | |||
public bool useProxy; | |||
public int proxyType; | |||
public string proxyServer; | |||
public int proxyPort; | |||
public int proxyTimeout; | |||
public bool useAuth; | |||
public string authUser; | |||
public string authPwd; | |||
public ForwardProxyConfig() | |||
{ | |||
useProxy = false; | |||
proxyType = PROXY_SOCKS5; | |||
proxyServer = ""; | |||
proxyPort = 0; | |||
proxyTimeout = DefaultProxyTimeoutSec; | |||
useAuth = false; | |||
authUser = ""; | |||
authPwd = ""; | |||
} | |||
public void CheckConfig() | |||
{ | |||
if (proxyType < PROXY_SOCKS5 || proxyType > PROXY_HTTP) | |||
{ | |||
proxyType = PROXY_SOCKS5; | |||
} | |||
} | |||
} | |||
} |
@@ -1,33 +0,0 @@ | |||
using System; | |||
namespace Shadowsocks.WPF.Models | |||
{ | |||
/* | |||
* Format: | |||
* <modifiers-combination>+<key> | |||
* | |||
*/ | |||
[Serializable] | |||
public class HotkeyConfig | |||
{ | |||
public string SwitchSystemProxy; | |||
public string SwitchSystemProxyMode; | |||
public string SwitchAllowLan; | |||
public string ShowLogs; | |||
public string ServerMoveUp; | |||
public string ServerMoveDown; | |||
public bool RegHotkeysAtStartup; | |||
public HotkeyConfig() | |||
{ | |||
SwitchSystemProxy = ""; | |||
SwitchSystemProxyMode = ""; | |||
SwitchAllowLan = ""; | |||
ShowLogs = ""; | |||
ServerMoveUp = ""; | |||
ServerMoveDown = ""; | |||
RegHotkeysAtStartup = false; | |||
} | |||
} | |||
} |
@@ -36,8 +36,8 @@ namespace Shadowsocks.WPF.Models | |||
const string LOGGER_FILE_NAME_ATTRIBUTE = "fileName"; | |||
XmlDocument doc = new XmlDocument(); | |||
XmlElement logFileNameElement; | |||
XmlElement logLevelElement; | |||
XmlElement? logFileNameElement; | |||
XmlElement? logLevelElement; | |||
/// <summary> | |||
/// Load the NLog config xml file content | |||
@@ -46,8 +46,8 @@ namespace Shadowsocks.WPF.Models | |||
{ | |||
NLogConfig config = new NLogConfig(); | |||
config.doc.Load(NLOG_CONFIG_FILE_NAME); | |||
config.logLevelElement = (XmlElement)SelectSingleNode(config.doc, "//nlog:logger[@name='*']"); | |||
config.logFileNameElement = (XmlElement)SelectSingleNode(config.doc, "//nlog:target[@name='file']"); | |||
config.logLevelElement = (XmlElement?)SelectSingleNode(config.doc, "//nlog:logger[@name='*']"); | |||
config.logFileNameElement = (XmlElement?)SelectSingleNode(config.doc, "//nlog:target[@name='file']"); | |||
return config; | |||
} | |||
@@ -105,7 +105,7 @@ namespace Shadowsocks.WPF.Models | |||
/// <param name="doc"></param> | |||
/// <param name="xpath"></param> | |||
/// <returns></returns> | |||
private static XmlNode SelectSingleNode(XmlDocument doc, string xpath) | |||
private static XmlNode? SelectSingleNode(XmlDocument doc, string xpath) | |||
{ | |||
XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable); | |||
manager.AddNamespace("nlog", "http://www.nlog-project.org/schemas/NLog.xsd"); | |||
@@ -121,7 +121,7 @@ namespace Shadowsocks.WPF.Models | |||
if (!File.Exists(NLOG_CONFIG_FILE_NAME)) | |||
{ | |||
File.WriteAllText(NLOG_CONFIG_FILE_NAME, Properties.Resources.NLog_config); | |||
File.WriteAllText(NLOG_CONFIG_FILE_NAME, Properties.Resources.NLog); | |||
LogManager.LoadConfiguration(NLOG_CONFIG_FILE_NAME); | |||
} | |||
} | |||
@@ -133,12 +133,15 @@ namespace Shadowsocks.WPF.Services | |||
var filename = asset.GetProperty("name").GetString(); | |||
var browser_download_url = asset.GetProperty("browser_download_url").GetString(); | |||
var response = await httpClient.GetAsync(browser_download_url); | |||
using (var downloadedFileStream = File.Create(Utils.Utilities.GetTempPath(filename))) | |||
await response.Content.CopyToAsync(downloadedFileStream); | |||
logger.Info($"Downloaded {filename}."); | |||
// store .zip filename | |||
if (filename.EndsWith(".zip")) | |||
NewReleaseZipFilename = filename; | |||
if (filename is string) | |||
{ | |||
using (var downloadedFileStream = File.Create(Utils.Utilities.GetTempPath(filename))) | |||
await response.Content.CopyToAsync(downloadedFileStream); | |||
logger.Info($"Downloaded {filename}."); | |||
// store .zip filename | |||
if (filename.EndsWith(".zip")) | |||
NewReleaseZipFilename = filename; | |||
} | |||
} | |||
logger.Info("Finished downloading."); | |||
// notify user | |||
@@ -1,17 +1,21 @@ | |||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
<PropertyGroup> | |||
<OutputType>Exe</OutputType> | |||
<TargetFramework>net5.0-windows</TargetFramework> | |||
<UseWPF>true</UseWPF> | |||
<Authors>clowwindy & community 2020</Authors> | |||
<PackageId>Shadowsocks.WPF</PackageId> | |||
<Product>Shadowsocks WPF GUI</Product> | |||
<AssemblyVersion>5.0.0.0</AssemblyVersion> | |||
<Version>1.0.0</Version> | |||
<ApplicationManifest>App.manifest</ApplicationManifest> | |||
<Product>Shadowsocks for Windows WPF GUI</Product> | |||
<Authors>Clowwindy & The Community</Authors> | |||
<Version>5.0.0</Version> | |||
<ApplicationIcon>Assets\shadowsocks.ico</ApplicationIcon> | |||
<NoWin32Manifest>true</NoWin32Manifest> | |||
<Nullable>enable</Nullable> | |||
<Copyright>© 2020 Clowwindy & The Community</Copyright> | |||
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile> | |||
<PackageProjectUrl>https://github.com/shadowsocks/shadowsocks-windows</PackageProjectUrl> | |||
<RepositoryUrl>https://github.com/shadowsocks/shadowsocks-windows</RepositoryUrl> | |||
<RepositoryType>Public</RepositoryType> | |||
<Description>If you want to keep a secret, you must also hide it from yourself.</Description> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
@@ -40,6 +44,10 @@ | |||
<None Remove="Resources\ss32Out.png" /> | |||
<None Remove="Resources\ss32Outline.png" /> | |||
<None Remove="Resources\ssw128.png" /> | |||
<None Include="..\LICENSE.txt"> | |||
<Pack>True</Pack> | |||
<PackagePath></PackagePath> | |||
</None> | |||
</ItemGroup> | |||
<ItemGroup> | |||
@@ -115,8 +123,4 @@ | |||
<Resource Include="Resources\ssw128.png" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Folder Include="Properties\PublishProfiles\" /> | |||
</ItemGroup> | |||
</Project> |
@@ -1,15 +1,20 @@ | |||
using Shadowsocks.Net.SystemProxy; | |||
using Shadowsocks.PAC; | |||
using Shadowsocks.WPF.Models; | |||
using Shadowsocks.WPF.Services.SystemProxy; | |||
using Splat; | |||
using System.Windows; | |||
namespace Shadowsocks.WPF.Utils | |||
{ | |||
public static class SystemProxy | |||
{ | |||
public static void Update(Configuration config, bool forceDisable, PACServer pacSrv, bool noRetry = false) | |||
public static void Update(bool forceDisable, bool enabled, bool global) | |||
{ | |||
bool global = config.global; | |||
bool enabled = config.enabled; | |||
var settings = Locator.Current.GetService<Settings>(); | |||
var appSettings = settings.App; | |||
var netSettings = settings.Net; | |||
var pacSettings = settings.PAC; | |||
if (forceDisable || !WinINet.operational) | |||
{ | |||
@@ -22,20 +27,12 @@ namespace Shadowsocks.WPF.Utils | |||
{ | |||
if (global) | |||
{ | |||
WinINet.ProxyGlobal("localhost:" + config.localPort.ToString(), "<local>"); | |||
WinINet.ProxyGlobal($"localhost:{netSettings.HttpListeningPort}", "<local>"); | |||
} | |||
else | |||
{ | |||
string pacUrl; | |||
if (config.useOnlinePac && !string.IsNullOrEmpty(config.pacUrl)) | |||
{ | |||
pacUrl = config.pacUrl; | |||
} | |||
else | |||
{ | |||
pacUrl = pacSrv.PacUrl; | |||
} | |||
var pacUrl = string.IsNullOrEmpty(pacSettings.CustomPACUrl) | |||
? Locator.Current.GetService<PACServer>().PacUrl : pacSettings.CustomPACUrl; | |||
WinINet.ProxyPAC(pacUrl); | |||
} | |||
} | |||
@@ -46,8 +43,8 @@ namespace Shadowsocks.WPF.Utils | |||
} | |||
catch (ProxyException ex) | |||
{ | |||
logger.LogUsefulException(ex); | |||
if (ex.Type != ProxyExceptionType.Unspecific && !noRetry) | |||
LogHost.Default.Error(ex, "An error occurred while updating system proxy."); | |||
/*if (ex.Type != ProxyExceptionType.Unspecific && !noRetry) | |||
{ | |||
var ret = MessageBox.Show(I18N.GetString("Error occured when process proxy setting, do you want reset current setting and retry?"), I18N.GetString("Shadowsocks"), MessageBoxButtons.YesNo, MessageBoxIcon.Warning); | |||
if (ret == DialogResult.Yes) | |||
@@ -59,7 +56,7 @@ namespace Shadowsocks.WPF.Utils | |||
else | |||
{ | |||
MessageBox.Show(I18N.GetString("Unrecoverable proxy setting error occured, see log for detail"), I18N.GetString("Shadowsocks"), MessageBoxButtons.OK, MessageBoxIcon.Error); | |||
} | |||
}*/ | |||
} | |||
} | |||
} |
@@ -2,7 +2,9 @@ using ReactiveUI; | |||
using ReactiveUI.Fody.Helpers; | |||
using ReactiveUI.Validation.Extensions; | |||
using ReactiveUI.Validation.Helpers; | |||
using Shadowsocks.Net.Settings; | |||
using Shadowsocks.WPF.Models; | |||
using Splat; | |||
using System.Linq; | |||
using System.Reactive; | |||
using System.Reactive.Linq; | |||
@@ -13,19 +15,18 @@ namespace Shadowsocks.WPF.ViewModels | |||
{ | |||
public ForwardProxyViewModel() | |||
{ | |||
if (!_config.proxy.useProxy) | |||
NoProxy = true; | |||
else if (_config.proxy.proxyType == 0) | |||
UseSocks5Proxy = true; | |||
else | |||
UseHttpProxy = true; | |||
_forwardProxySettings = Locator.Current.GetService<Settings>().Net.ForwardProxy; | |||
Address = _config.proxy.proxyServer; | |||
Port = _config.proxy.proxyPort; | |||
Timeout = _config.proxy.proxyTimeout; | |||
NoProxy = _forwardProxySettings.NoProxy; | |||
UseSocks5Proxy = _forwardProxySettings.UseSocks5Proxy; | |||
UseHttpProxy = _forwardProxySettings.UseHttpProxy; | |||
Username = _config.proxy.authUser; | |||
Password = _config.proxy.authPwd; | |||
Address = _forwardProxySettings.Address; | |||
Port = _forwardProxySettings.Port; | |||
Timeout = 5; | |||
Username = _forwardProxySettings.Username; | |||
Password = _forwardProxySettings.Password; | |||
this.WhenAnyValue(x => x.NoProxy, x => !x) | |||
.ToPropertyEx(this, x => x.CanModifyDetails); | |||
@@ -52,12 +53,13 @@ namespace Shadowsocks.WPF.ViewModels | |||
Save = ReactiveCommand.Create(() => | |||
{ | |||
_controller.SaveProxy(GetForwardProxyConfig()); | |||
_menuViewController.CloseForwardProxyWindow(); | |||
// TODO: save settings | |||
}, canSave); | |||
Cancel = ReactiveCommand.Create(_menuViewController.CloseForwardProxyWindow); | |||
//Cancel = ReactiveCommand.Create(_menuViewController.CloseForwardProxyWindow); | |||
} | |||
private ForwardProxySettings _forwardProxySettings; | |||
public ValidationHelper AddressRule { get; } | |||
public ValidationHelper PortRule { get; } | |||
public ValidationHelper TimeoutRule { get; } | |||
@@ -93,29 +95,16 @@ namespace Shadowsocks.WPF.ViewModels | |||
[Reactive] | |||
public string Password { get; set; } | |||
private ForwardProxyConfig GetForwardProxyConfig() | |||
{ | |||
var forwardProxyConfig = new ForwardProxyConfig() | |||
private ForwardProxySettings GetForwardProxySettings() | |||
=> new ForwardProxySettings() | |||
{ | |||
proxyServer = Address, | |||
proxyPort = Port, | |||
proxyTimeout = Timeout, | |||
authUser = Username, | |||
authPwd = Password | |||
NoProxy = NoProxy, | |||
UseSocks5Proxy = UseSocks5Proxy, | |||
UseHttpProxy = UseHttpProxy, | |||
Address = Address, | |||
Port = Port, | |||
Username = Username, | |||
Password = Password, | |||
}; | |||
if (NoProxy) | |||
forwardProxyConfig.useProxy = false; | |||
else if (UseSocks5Proxy) | |||
{ | |||
forwardProxyConfig.useProxy = true; | |||
forwardProxyConfig.proxyType = 0; | |||
} | |||
else | |||
{ | |||
forwardProxyConfig.useProxy = true; | |||
forwardProxyConfig.proxyType = 1; | |||
} | |||
return forwardProxyConfig; | |||
} | |||
} | |||
} |
@@ -18,7 +18,7 @@ namespace Shadowsocks.WPF.ViewModels | |||
{ | |||
public OnlineConfigViewModel() | |||
{ | |||
Sources = new ObservableCollection<string>(_config.onlineConfigSource); | |||
Sources = new ObservableCollection<string>(); | |||
SelectedSource = ""; | |||
Address = ""; | |||
@@ -39,8 +39,8 @@ namespace Shadowsocks.WPF.ViewModels | |||
address => Uri.IsWellFormedUriString(address, UriKind.Absolute) && | |||
(address.StartsWith("https://") || address.StartsWith("http://"))); | |||
Update = ReactiveCommand.CreateFromTask(() => _controller.UpdateOnlineConfig(SelectedSource), canUpdateCopyRemove); | |||
UpdateAll = ReactiveCommand.CreateFromTask(_controller.UpdateAllOnlineConfig, canUpdateAll); | |||
//Update = ReactiveCommand.CreateFromTask(() => _controller.UpdateOnlineConfig(SelectedSource), canUpdateCopyRemove); | |||
//UpdateAll = ReactiveCommand.CreateFromTask(_controller.UpdateAllOnlineConfig, canUpdateAll); | |||
CopyLink = ReactiveCommand.Create(() => Clipboard.SetText(SelectedSource), canUpdateCopyRemove); | |||
Remove = ReactiveCommand.Create(() => | |||
{ | |||
@@ -50,13 +50,13 @@ namespace Shadowsocks.WPF.ViewModels | |||
{ | |||
result = Sources.Remove(urlToRemove); | |||
} while (result); | |||
_controller.RemoveOnlineConfig(urlToRemove); | |||
//_controller.RemoveOnlineConfig(urlToRemove); | |||
}, canUpdateCopyRemove); | |||
Add = ReactiveCommand.Create(() => | |||
{ | |||
Sources.Add(Address); | |||
SelectedSource = Address; | |||
_controller.SaveOnlineConfigSource(Sources.ToList()); | |||
//_controller.SaveOnlineConfigSource(Sources.ToList()); | |||
Address = ""; | |||
}, canAdd); | |||