- Shadowsocks - Shadowsocks.Common - Shadowsocks.Crypto - Shadowsocks.WPFpull/2897/head
@@ -0,0 +1,100 @@ | |||
root = true | |||
# EditorConfig: http://EditorConfig.org | |||
# VS extension: https://marketplace.visualstudio.com/items?itemName = MadsKristensen.EditorConfig | |||
# 4 space indentation | |||
[*] | |||
charset = utf-8 | |||
indent_style = space | |||
indent_size = 4 | |||
# Microsoft .NET properties | |||
csharp_new_line_before_members_in_object_initializers = false | |||
csharp_preferred_modifier_order = public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion | |||
csharp_style_expression_bodied_methods = true:suggestion | |||
csharp_style_var_elsewhere = true:suggestion | |||
csharp_style_var_for_built_in_types = true:suggestion | |||
csharp_style_var_when_type_is_apparent = true:suggestion | |||
dotnet_naming_rule.private_constants_rule.severity = suggestion | |||
dotnet_naming_rule.private_constants_rule.style = all_upper_style | |||
dotnet_naming_rule.private_constants_rule.symbols = private_constants_symbols | |||
dotnet_naming_rule.private_static_readonly_rule.severity = suggestion | |||
dotnet_naming_rule.private_static_readonly_rule.style = lower_camel_case_style | |||
dotnet_naming_rule.private_static_readonly_rule.symbols = private_static_readonly_symbols | |||
dotnet_naming_style.all_upper_style.capitalization = all_upper | |||
dotnet_naming_style.all_upper_style.word_separator = _ | |||
dotnet_naming_style.lower_camel_case_style.capitalization = camel_case | |||
dotnet_naming_style.lower_camel_case_style.required_prefix = _ | |||
dotnet_naming_symbols.private_constants_symbols.applicable_accessibilities = private | |||
dotnet_naming_symbols.private_constants_symbols.applicable_kinds = field | |||
dotnet_naming_symbols.private_constants_symbols.required_modifiers = const | |||
dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private | |||
dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field | |||
dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static,readonly | |||
dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none | |||
dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:none | |||
dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none | |||
dotnet_style_qualification_for_event = false:warning | |||
dotnet_style_qualification_for_field = false:warning | |||
dotnet_style_qualification_for_method = false:warning | |||
dotnet_style_qualification_for_property = false:warning | |||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion | |||
# CSharp code style settings: | |||
[*.cs] | |||
# Prefer "var" everywhere | |||
csharp_style_var_for_built_in_types = true:suggestion | |||
csharp_style_var_when_type_is_apparent = true:suggestion | |||
csharp_style_var_elsewhere = true:suggestion | |||
# Prefer method-like constructs to have a block body | |||
csharp_style_expression_bodied_methods = true:suggestion | |||
csharp_style_expression_bodied_constructors = false:none | |||
csharp_style_expression_bodied_operators = true:suggestion | |||
# Prefer property-like constructs to have an expression-body | |||
csharp_style_expression_bodied_properties = true:suggestion | |||
csharp_style_expression_bodied_indexers = true:suggestion | |||
csharp_style_expression_bodied_accessors = true:none | |||
# Suggest more modern language features when available | |||
csharp_style_pattern_matching_over_is_with_cast_check = false:none | |||
csharp_style_pattern_matching_over_as_with_null_check = false:none | |||
csharp_style_inlined_variable_declaration = false:none | |||
csharp_style_throw_expression = false:none | |||
csharp_style_conditional_delegate_call = true:suggestion | |||
# Newline settings | |||
csharp_new_line_before_open_brace = all | |||
csharp_new_line_before_else = true | |||
csharp_new_line_before_catch = true | |||
csharp_new_line_before_finally = true | |||
csharp_new_line_before_members_in_object_initializers = false | |||
csharp_new_line_before_members_in_anonymous_types = false | |||
# Dotnet code style settings: | |||
[*.{cs,vb}] | |||
# Sort using and Import directives with System.* appearing first | |||
dotnet_sort_system_directives_first = false | |||
# Avoid "this." and "Me." if not necessary | |||
dotnet_style_qualification_for_field = false:warning | |||
dotnet_style_qualification_for_property = false:warning | |||
dotnet_style_qualification_for_method = false:warning | |||
dotnet_style_qualification_for_event = false:warning | |||
# Use language keywords instead of framework type names for type references | |||
dotnet_style_predefined_type_for_locals_parameters_members = true:silent | |||
dotnet_style_predefined_type_for_member_access = true:silent | |||
# Suggest more modern language features when available | |||
dotnet_style_object_initializer = true:silent | |||
dotnet_style_collection_initializer = true:silent | |||
dotnet_style_coalesce_expression = true:suggestion | |||
dotnet_style_null_propagation = true:suggestion | |||
dotnet_style_explicit_tuple_names = true:suggestion | |||
[*.{appxmanifest,asax,ascx,aspx,axml,build,config,cs,cshtml,csproj,css,dbml,discomap,dtd,htm,html,js,json,jsproj,jsx,lsproj,master,njsproj,nuspec,proj,props,proto,razor,resjson,resw,resx,skin,StyleCop,targets,tasks,ts,tsx,vb,vbproj,xaml,xamlx,xml,xoml,xsd}] | |||
indent_style = space | |||
indent_size = 4 | |||
tab_width = 4 |
@@ -0,0 +1,9 @@ | |||
using SimpleInjector; | |||
namespace Shadowsocks.Common.Model | |||
{ | |||
public static class IoCManager | |||
{ | |||
public static Container Container { get; } = new Container(); | |||
} | |||
} |
@@ -0,0 +1,17 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
<PropertyGroup> | |||
<TargetFramework>netstandard2.1</TargetFramework> | |||
<Authors>clowwindy & community 2020</Authors> | |||
<Company>clowwindy & community 2020</Company> | |||
<Product>Shadowsocks Common</Product> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<PackageReference Include="Google.Protobuf" Version="3.13.0" /> | |||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> | |||
<PackageReference Include="NLog" Version="4.7.5" /> | |||
<PackageReference Include="SimpleInjector" Version="5.0.4" /> | |||
</ItemGroup> | |||
</Project> |
@@ -1,11 +1,7 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Runtime.Serialization; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace Shadowsocks.Util.SystemProxy | |||
namespace Shadowsocks.Common.SystemProxy | |||
{ | |||
enum ProxyExceptionType | |||
{ |
@@ -1,151 +1,143 @@ | |||
using System; | |||
using System.ComponentModel; | |||
using System.IO; | |||
using System.Net.Sockets; | |||
using System.Net; | |||
using System.Diagnostics; | |||
using System.Text; | |||
using Shadowsocks.Util.SystemProxy; | |||
namespace NLog | |||
{ | |||
public static class LoggerExtension | |||
{ | |||
// for key, iv, etc... | |||
public static void Dump(this Logger logger, string tag, ReadOnlySpan<byte> arr) | |||
{ | |||
logger.Dump(tag, arr.ToArray(), arr.Length); | |||
} | |||
public static void Dump(this Logger logger, string tag, byte[] arr, int length = -1) | |||
{ | |||
if (arr == null) logger.Trace($@" | |||
{tag}: | |||
(null) | |||
"); | |||
if (length == -1) length = arr.Length; | |||
if (!logger.IsTraceEnabled) return; | |||
string hex = BitConverter.ToString(arr.AsSpan(0, Math.Min(arr.Length, length)).ToArray()).Replace("-", ""); | |||
string content = $@" | |||
{tag}: | |||
{hex} | |||
"; | |||
logger.Trace(content); | |||
} | |||
// for cipher and plain text, so we can use openssl to test | |||
public static void DumpBase64(this Logger logger, string tag, ReadOnlySpan<byte> arr) | |||
{ | |||
logger.DumpBase64(tag, arr.ToArray(), arr.Length); | |||
} | |||
public static void DumpBase64(this Logger logger, string tag, byte[] arr, int length = -1) | |||
{ | |||
if (arr == null) logger.Trace($@" | |||
{tag}: | |||
(null) | |||
"); | |||
if (length == -1) length = arr.Length; | |||
if (!logger.IsTraceEnabled) return; | |||
string hex = Convert.ToBase64String(arr.AsSpan(0, Math.Min(arr.Length, length)).ToArray()); | |||
string content = $@" | |||
{tag}: | |||
{hex} | |||
"; | |||
logger.Trace(content); | |||
} | |||
public static void Debug(this Logger logger, EndPoint local, EndPoint remote, int len, string header = null, string tailer = null) | |||
{ | |||
if (logger.IsDebugEnabled) | |||
{ | |||
if (header == null && tailer == null) | |||
logger.Debug($"{local} => {remote} (size={len})"); | |||
else if (header == null && tailer != null) | |||
logger.Debug($"{local} => {remote} (size={len}), {tailer}"); | |||
else if (header != null && tailer == null) | |||
logger.Debug($"{header}: {local} => {remote} (size={len})"); | |||
else | |||
logger.Debug($"{header}: {local} => {remote} (size={len}), {tailer}"); | |||
} | |||
} | |||
public static void Debug(this Logger logger, Socket sock, int len, string header = null, string tailer = null) | |||
{ | |||
if (logger.IsDebugEnabled) | |||
{ | |||
logger.Debug(sock.LocalEndPoint, sock.RemoteEndPoint, len, header, tailer); | |||
} | |||
} | |||
public static void LogUsefulException(this Logger logger, Exception e) | |||
{ | |||
// just log useful exceptions, not all of them | |||
if (e is SocketException) | |||
{ | |||
SocketException se = (SocketException)e; | |||
if (se.SocketErrorCode == SocketError.ConnectionAborted) | |||
{ | |||
// closed by browser when sending | |||
// normally happens when download is canceled or a tab is closed before page is loaded | |||
} | |||
else if (se.SocketErrorCode == SocketError.ConnectionReset) | |||
{ | |||
// received rst | |||
} | |||
else if (se.SocketErrorCode == SocketError.NotConnected) | |||
{ | |||
// The application tried to send or receive data, and the System.Net.Sockets.Socket is not connected. | |||
} | |||
else if (se.SocketErrorCode == SocketError.HostUnreachable) | |||
{ | |||
// There is no network route to the specified host. | |||
} | |||
else if (se.SocketErrorCode == SocketError.TimedOut) | |||
{ | |||
// The connection attempt timed out, or the connected host has failed to respond. | |||
} | |||
else | |||
{ | |||
logger.Warn(e); | |||
} | |||
} | |||
else if (e is ObjectDisposedException) | |||
{ | |||
} | |||
else if (e is Win32Exception) | |||
{ | |||
var ex = (Win32Exception)e; | |||
// Win32Exception (0x80004005): A 32 bit processes cannot access modules of a 64 bit process. | |||
if ((uint)ex.ErrorCode != 0x80004005) | |||
{ | |||
logger.Warn(e); | |||
} | |||
} | |||
else if (e is ProxyException) | |||
{ | |||
var ex = (ProxyException)e; | |||
switch (ex.Type) | |||
{ | |||
case ProxyExceptionType.FailToRun: | |||
case ProxyExceptionType.QueryReturnMalformed: | |||
case ProxyExceptionType.SysproxyExitError: | |||
logger.Error($"sysproxy - {ex.Type.ToString()}:{ex.Message}"); | |||
break; | |||
case ProxyExceptionType.QueryReturnEmpty: | |||
case ProxyExceptionType.Unspecific: | |||
logger.Error($"sysproxy - {ex.Type.ToString()}"); | |||
break; | |||
} | |||
} | |||
else | |||
{ | |||
logger.Warn(e); | |||
} | |||
} | |||
} | |||
} | |||
using Shadowsocks.Common.SystemProxy; | |||
using System; | |||
using System.ComponentModel; | |||
using System.Net; | |||
using System.Net.Sockets; | |||
namespace NLog | |||
{ | |||
public static class LoggerExtension | |||
{ | |||
// for key, iv, etc... | |||
public static void Dump(this Logger logger, string tag, ReadOnlySpan<byte> arr) | |||
{ | |||
logger.Dump(tag, arr.ToArray(), arr.Length); | |||
} | |||
public static void Dump(this Logger logger, string tag, byte[] arr, int length = -1) | |||
{ | |||
if (arr == null) logger.Trace($@" | |||
{tag}: | |||
(null) | |||
"); | |||
if (length == -1) length = arr.Length; | |||
if (!logger.IsTraceEnabled) return; | |||
string hex = BitConverter.ToString(arr.AsSpan(0, Math.Min(arr.Length, length)).ToArray()).Replace("-", ""); | |||
string content = $@" | |||
{tag}: | |||
{hex} | |||
"; | |||
logger.Trace(content); | |||
} | |||
// for cipher and plain text, so we can use openssl to test | |||
public static void DumpBase64(this Logger logger, string tag, ReadOnlySpan<byte> arr) | |||
{ | |||
logger.DumpBase64(tag, arr.ToArray(), arr.Length); | |||
} | |||
public static void DumpBase64(this Logger logger, string tag, byte[] arr, int length = -1) | |||
{ | |||
if (arr == null) logger.Trace($@" | |||
{tag}: | |||
(null) | |||
"); | |||
if (length == -1) length = arr.Length; | |||
if (!logger.IsTraceEnabled) return; | |||
string hex = Convert.ToBase64String(arr.AsSpan(0, Math.Min(arr.Length, length)).ToArray()); | |||
string content = $@" | |||
{tag}: | |||
{hex} | |||
"; | |||
logger.Trace(content); | |||
} | |||
public static void Debug(this Logger logger, EndPoint local, EndPoint remote, int len, string header = null, string tailer = null) | |||
{ | |||
if (logger.IsDebugEnabled) | |||
{ | |||
if (header == null && tailer == null) | |||
logger.Debug($"{local} => {remote} (size={len})"); | |||
else if (header == null && tailer != null) | |||
logger.Debug($"{local} => {remote} (size={len}), {tailer}"); | |||
else if (header != null && tailer == null) | |||
logger.Debug($"{header}: {local} => {remote} (size={len})"); | |||
else | |||
logger.Debug($"{header}: {local} => {remote} (size={len}), {tailer}"); | |||
} | |||
} | |||
public static void Debug(this Logger logger, Socket sock, int len, string header = null, string tailer = null) | |||
{ | |||
if (logger.IsDebugEnabled) | |||
logger.Debug(sock.LocalEndPoint, sock.RemoteEndPoint, len, header, tailer); | |||
} | |||
public static void LogUsefulException(this Logger logger, Exception e) | |||
{ | |||
// just log useful exceptions, not all of them | |||
if (e is SocketException se) | |||
{ | |||
if (se.SocketErrorCode == SocketError.ConnectionAborted) | |||
{ | |||
// closed by browser when sending | |||
// normally happens when download is canceled or a tab is closed before page is loaded | |||
} | |||
else if (se.SocketErrorCode == SocketError.ConnectionReset) | |||
{ | |||
// received rst | |||
} | |||
else if (se.SocketErrorCode == SocketError.NotConnected) | |||
{ | |||
// The application tried to send or receive data, and the System.Net.Sockets.Socket is not connected. | |||
} | |||
else if (se.SocketErrorCode == SocketError.HostUnreachable) | |||
{ | |||
// There is no network route to the specified host. | |||
} | |||
else if (se.SocketErrorCode == SocketError.TimedOut) | |||
{ | |||
// The connection attempt timed out, or the connected host has failed to respond. | |||
} | |||
else | |||
{ | |||
logger.Warn(e); | |||
} | |||
} | |||
else if (e is ObjectDisposedException) | |||
{ | |||
} | |||
else if (e is Win32Exception ex) | |||
{ | |||
// Win32Exception (0x80004005): A 32 bit processes cannot access modules of a 64 bit process. | |||
if ((uint)ex.ErrorCode != 0x80004005) | |||
logger.Warn(e); | |||
} | |||
else if (e is ProxyException pe) | |||
{ | |||
switch (pe.Type) | |||
{ | |||
case ProxyExceptionType.FailToRun: | |||
case ProxyExceptionType.QueryReturnMalformed: | |||
case ProxyExceptionType.SysproxyExitError: | |||
logger.Error($"sysproxy - {pe.Type}:{pe.Message}"); | |||
break; | |||
case ProxyExceptionType.QueryReturnEmpty: | |||
case ProxyExceptionType.Unspecific: | |||
logger.Error($"sysproxy - {pe.Type}"); | |||
break; | |||
} | |||
} | |||
else | |||
{ | |||
logger.Warn(e); | |||
} | |||
} | |||
} | |||
} |
@@ -1,12 +1,12 @@ | |||
using System; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Security.Cryptography; | |||
namespace Shadowsocks.Encryption.AEAD | |||
namespace Shadowsocks.Crypto.AEAD | |||
{ | |||
public class AEADAesGcmNativeEncryptor : AEADEncryptor | |||
public class AEADAesGcmNativeCrypto : AEADCrypto | |||
{ | |||
public AEADAesGcmNativeEncryptor(string method, string password) : base(method, password) | |||
public AEADAesGcmNativeCrypto(string method, string password) : base(method, password) | |||
{ | |||
} | |||
@@ -51,4 +51,4 @@ namespace Shadowsocks.Encryption.AEAD | |||
return clen; | |||
} | |||
} | |||
} | |||
} |
@@ -1,16 +1,17 @@ | |||
using System; | |||
using System; | |||
using System.Collections.Generic; | |||
using Org.BouncyCastle.Crypto.Engines; | |||
using Org.BouncyCastle.Crypto.Modes; | |||
using Org.BouncyCastle.Crypto.Parameters; | |||
namespace Shadowsocks.Encryption.AEAD | |||
namespace Shadowsocks.Crypto.AEAD | |||
{ | |||
public class AEADBouncyCastleEncryptor : AEADEncryptor | |||
public class AEADBouncyCastleCrypto : AEADCrypto | |||
{ | |||
IAeadCipher aead; | |||
bool enc; | |||
public AEADBouncyCastleEncryptor(string method, string password) : base(method, password) | |||
public AEADBouncyCastleCrypto(string method, string password) : base(method, password) | |||
{ | |||
aead = cipherFamily switch | |||
{ |
@@ -1,320 +1,322 @@ | |||
using NLog; | |||
using Shadowsocks.Controller; | |||
using Shadowsocks.Encryption.Exception; | |||
using Shadowsocks.Encryption.Stream; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Runtime.CompilerServices; | |||
using System.Text; | |||
namespace Shadowsocks.Encryption.AEAD | |||
{ | |||
public abstract class AEADEncryptor : EncryptorBase | |||
{ | |||
private static readonly Logger logger = LogManager.GetCurrentClassLogger(); | |||
// We are using the same saltLen and keyLen | |||
private const string Info = "ss-subkey"; | |||
private static readonly byte[] InfoBytes = Encoding.ASCII.GetBytes(Info); | |||
// every connection should create its own buffer | |||
private readonly byte[] buffer = new byte[65536]; | |||
private int bufPtr = 0; | |||
public const int ChunkLengthBytes = 2; | |||
public const uint ChunkLengthMask = 0x3FFFu; | |||
protected CipherFamily cipherFamily; | |||
protected CipherInfo CipherInfo; | |||
protected static byte[] masterKey = Array.Empty<byte>(); | |||
protected byte[] sessionKey = Array.Empty<byte>(); | |||
protected int keyLen; | |||
protected int saltLen; | |||
protected int tagLen; | |||
protected int nonceLen; | |||
protected byte[] salt; | |||
protected byte[] nonce; | |||
// Is first packet | |||
protected bool saltReady; | |||
// Is first chunk(tcp request) | |||
protected bool tcpRequestSent; | |||
public AEADEncryptor(string method, string password) | |||
: base(method, password) | |||
{ | |||
CipherInfo = GetCiphers()[method.ToLower()]; | |||
cipherFamily = CipherInfo.Type; | |||
AEADCipherParameter parameter = (AEADCipherParameter)CipherInfo.CipherParameter; | |||
keyLen = parameter.KeySize; | |||
saltLen = parameter.SaltSize; | |||
tagLen = parameter.TagSize; | |||
nonceLen = parameter.NonceSize; | |||
InitKey(password); | |||
salt = new byte[saltLen]; | |||
// Initialize all-zero nonce for each connection | |||
nonce = new byte[nonceLen]; | |||
logger.Dump($"masterkey {instanceId}", masterKey, keyLen); | |||
logger.Dump($"nonce {instanceId}", nonce, keyLen); | |||
} | |||
protected abstract Dictionary<string, CipherInfo> GetCiphers(); | |||
protected void InitKey(string password) | |||
{ | |||
byte[] passbuf = Encoding.UTF8.GetBytes(password); | |||
// init master key | |||
if (masterKey == null) | |||
{ | |||
masterKey = new byte[keyLen]; | |||
} | |||
if (masterKey.Length != keyLen) | |||
{ | |||
Array.Resize(ref masterKey, keyLen); | |||
} | |||
StreamEncryptor.LegacyDeriveKey(passbuf, masterKey, keyLen); | |||
// init session key | |||
sessionKey = new byte[keyLen]; | |||
} | |||
public virtual void InitCipher(byte[] salt, bool isEncrypt) | |||
{ | |||
this.salt = new byte[saltLen]; | |||
Array.Copy(salt, this.salt, saltLen); | |||
CryptoUtils.HKDF(keyLen, masterKey, salt, InfoBytes).CopyTo(sessionKey, 0); | |||
logger.Dump($"salt {instanceId}", salt, saltLen); | |||
logger.Dump($"sessionkey {instanceId}", sessionKey, keyLen); | |||
} | |||
public abstract int CipherEncrypt(ReadOnlySpan<byte> plain, Span<byte> cipher); | |||
public abstract int CipherDecrypt(Span<byte> plain, ReadOnlySpan<byte> cipher); | |||
#region TCP | |||
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)] | |||
public override int Encrypt(ReadOnlySpan<byte> plain, Span<byte> cipher) | |||
{ | |||
// push data | |||
Span<byte> tmp = buffer.AsSpan(0, plain.Length + bufPtr); | |||
plain.CopyTo(tmp.Slice(bufPtr)); | |||
int outlength = 0; | |||
if (!saltReady) | |||
{ | |||
saltReady = true; | |||
// Generate salt | |||
byte[] saltBytes = RNG.GetBytes(saltLen); | |||
InitCipher(saltBytes, true); | |||
saltBytes.CopyTo(cipher); | |||
outlength = saltLen; | |||
} | |||
if (!tcpRequestSent) | |||
{ | |||
tcpRequestSent = true; | |||
// read addr byte to encrypt | |||
int encAddrBufLength = ChunkEncrypt(tmp.Slice(0, AddressBufferLength), cipher.Slice(outlength)); | |||
tmp = tmp.Slice(AddressBufferLength); | |||
outlength += encAddrBufLength; | |||
} | |||
// handle other chunks | |||
while (true) | |||
{ | |||
// calculate next chunk size | |||
int bufSize = tmp.Length; | |||
if (bufSize <= 0) | |||
{ | |||
return outlength; | |||
} | |||
int chunklength = (int)Math.Min(bufSize, ChunkLengthMask); | |||
// read next chunk | |||
int encChunkLength = ChunkEncrypt(tmp.Slice(0, chunklength), cipher.Slice(outlength)); | |||
tmp = tmp.Slice(chunklength); | |||
outlength += encChunkLength; | |||
// check if we have enough space for outbuf | |||
// if not, keep buf for next run, at this condition, buffer is not empty | |||
if (outlength + TCPHandler.ChunkOverheadSize > TCPHandler.BufferSize) | |||
{ | |||
logger.Debug("enc outbuf almost full, giving up"); | |||
// write rest data to head of shared buffer | |||
tmp.CopyTo(buffer); | |||
bufPtr = tmp.Length; | |||
return outlength; | |||
} | |||
// check if buffer empty | |||
bufSize = tmp.Length; | |||
if (bufSize <= 0) | |||
{ | |||
logger.Debug("No more data to encrypt, leaving"); | |||
return outlength; | |||
} | |||
} | |||
} | |||
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)] | |||
public override int Decrypt(Span<byte> plain, ReadOnlySpan<byte> cipher) | |||
{ | |||
int outlength = 0; | |||
// drop all into buffer | |||
Span<byte> tmp = buffer.AsSpan(0, cipher.Length + bufPtr); | |||
cipher.CopyTo(tmp.Slice(bufPtr)); | |||
int bufSize = tmp.Length; | |||
logger.Debug($"{instanceId} decrypt tcp, read salt: {!saltReady}"); | |||
if (!saltReady) | |||
{ | |||
// check if we get the leading salt | |||
if (bufSize <= saltLen) | |||
{ | |||
// need more, write back cache | |||
tmp.CopyTo(buffer); | |||
bufPtr = tmp.Length; | |||
return outlength; | |||
} | |||
saltReady = true; | |||
byte[] salt = tmp.Slice(0, saltLen).ToArray(); | |||
tmp = tmp.Slice(saltLen); | |||
InitCipher(salt, false); | |||
} | |||
// handle chunks | |||
while (true) | |||
{ | |||
bufSize = tmp.Length; | |||
// check if we have any data | |||
if (bufSize <= 0) | |||
{ | |||
logger.Trace("No data in buffer"); | |||
return outlength; | |||
} | |||
// first get chunk length | |||
if (bufSize <= ChunkLengthBytes + tagLen) | |||
{ | |||
// so we only have chunk length and its tag? | |||
// wait more | |||
logger.Trace($"{instanceId} not enough data to decrypt chunk. write {tmp.Length} byte back to buffer."); | |||
tmp.CopyTo(buffer); | |||
bufPtr = tmp.Length; | |||
return outlength; | |||
} | |||
logger.Trace($"{instanceId} try decrypt to offset {outlength}"); | |||
int len = ChunkDecrypt(plain.Slice(outlength), tmp); | |||
if (len <= 0) | |||
{ | |||
logger.Trace($"{instanceId} no chunk decrypted, write {tmp.Length} byte back to buffer."); | |||
// no chunk decrypted | |||
tmp.CopyTo(buffer); | |||
bufPtr = tmp.Length; | |||
return outlength; | |||
} | |||
logger.Trace($"{instanceId} decrypted {len} to offset {outlength}"); | |||
// drop decrypted data | |||
tmp = tmp.Slice(ChunkLengthBytes + tagLen + len + tagLen); | |||
outlength += len; | |||
// logger.Debug("aead dec outlength " + outlength); | |||
if (outlength + 100 > TCPHandler.BufferSize) | |||
{ | |||
logger.Trace($"{instanceId} output almost full, write {tmp.Length} byte back to buffer."); | |||
tmp.CopyTo(buffer); | |||
bufPtr = tmp.Length; | |||
return outlength; | |||
} | |||
bufSize = tmp.Length; | |||
// check if we already done all of them | |||
if (bufSize <= 0) | |||
{ | |||
bufPtr = 0; | |||
logger.Debug($"{instanceId} no data in buffer, already all done"); | |||
return outlength; | |||
} | |||
} | |||
} | |||
#endregion | |||
#region UDP | |||
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)] | |||
public override int EncryptUDP(ReadOnlySpan<byte> plain, Span<byte> cipher) | |||
{ | |||
RNG.GetSpan(cipher.Slice(0, saltLen)); | |||
InitCipher(cipher.Slice(0, saltLen).ToArray(), true); | |||
return saltLen + CipherEncrypt(plain, cipher.Slice(saltLen)); | |||
} | |||
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)] | |||
public override int DecryptUDP(Span<byte> plain, ReadOnlySpan<byte> cipher) | |||
{ | |||
InitCipher(cipher.Slice(0, saltLen).ToArray(), false); | |||
return CipherDecrypt(plain, cipher.Slice(saltLen)); | |||
} | |||
#endregion | |||
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)] | |||
private int ChunkEncrypt(ReadOnlySpan<byte> plain, Span<byte> cipher) | |||
{ | |||
if (plain.Length > ChunkLengthMask) | |||
{ | |||
logger.Error("enc chunk too big"); | |||
throw new CryptoErrorException(); | |||
} | |||
byte[] lenbuf = BitConverter.GetBytes((ushort)IPAddress.HostToNetworkOrder((short)plain.Length)); | |||
int cipherLenSize = CipherEncrypt(lenbuf, cipher); | |||
CryptoUtils.SodiumIncrement(nonce); | |||
int cipherDataSize = CipherEncrypt(plain, cipher.Slice(cipherLenSize)); | |||
CryptoUtils.SodiumIncrement(nonce); | |||
return cipherLenSize + cipherDataSize; | |||
} | |||
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)] | |||
private int ChunkDecrypt(Span<byte> plain, ReadOnlySpan<byte> cipher) | |||
{ | |||
// try to dec chunk len | |||
byte[] chunkLengthByte = new byte[ChunkLengthBytes]; | |||
CipherDecrypt(chunkLengthByte, cipher.Slice(0, ChunkLengthBytes + tagLen)); | |||
ushort chunkLength = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(chunkLengthByte, 0)); | |||
if (chunkLength > ChunkLengthMask) | |||
{ | |||
// we get invalid chunk | |||
logger.Error($"{instanceId} Invalid chunk length: {chunkLength}"); | |||
throw new CryptoErrorException(); | |||
} | |||
// logger.Debug("Get the real chunk len:" + chunkLength); | |||
int bufSize = cipher.Length; | |||
if (bufSize < ChunkLengthBytes + tagLen /* we haven't remove them */+ chunkLength + tagLen) | |||
{ | |||
logger.Debug($"{instanceId} need {ChunkLengthBytes + tagLen + chunkLength + tagLen}, but have {cipher.Length}"); | |||
return 0; | |||
} | |||
CryptoUtils.SodiumIncrement(nonce); | |||
// we have enough data to decrypt one chunk | |||
// drop chunk len and its tag from buffer | |||
int len = CipherDecrypt(plain, cipher.Slice(ChunkLengthBytes + tagLen, chunkLength + tagLen)); | |||
CryptoUtils.SodiumIncrement(nonce); | |||
logger.Trace($"{instanceId} decrypted {len} byte chunk used {ChunkLengthBytes + tagLen + chunkLength + tagLen} from {cipher.Length}"); | |||
return len; | |||
} | |||
} | |||
} | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Runtime.CompilerServices; | |||
using System.Text; | |||
using NLog; | |||
using Shadowsocks.Crypto.Exception; | |||
using Shadowsocks.Crypto.Stream; | |||
namespace Shadowsocks.Crypto.AEAD | |||
{ | |||
public abstract class AEADCrypto : CryptoBase | |||
{ | |||
private static readonly Logger logger = LogManager.GetCurrentClassLogger(); | |||
// We are using the same saltLen and keyLen | |||
private const string Info = "ss-subkey"; | |||
private static readonly byte[] InfoBytes = Encoding.ASCII.GetBytes(Info); | |||
// every connection should create its own buffer | |||
private readonly byte[] buffer = new byte[65536]; | |||
private int bufPtr = 0; | |||
public const int ChunkLengthBytes = 2; | |||
public const uint ChunkLengthMask = 0x3FFFu; | |||
protected CipherFamily cipherFamily; | |||
protected CipherInfo CipherInfo; | |||
protected static byte[] masterKey = Array.Empty<byte>(); | |||
protected byte[] sessionKey = Array.Empty<byte>(); | |||
protected int keyLen; | |||
protected int saltLen; | |||
protected int tagLen; | |||
protected int nonceLen; | |||
protected byte[] salt; | |||
protected byte[] nonce; | |||
// Is first packet | |||
protected bool saltReady; | |||
// Is first chunk(tcp request) | |||
protected bool tcpRequestSent; | |||
public AEADCrypto(string method, string password) | |||
: base(method, password) | |||
{ | |||
CipherInfo = GetCiphers()[method.ToLower()]; | |||
cipherFamily = CipherInfo.Type; | |||
AEADCipherParameter parameter = (AEADCipherParameter)CipherInfo.CipherParameter; | |||
keyLen = parameter.KeySize; | |||
saltLen = parameter.SaltSize; | |||
tagLen = parameter.TagSize; | |||
nonceLen = parameter.NonceSize; | |||
InitKey(password); | |||
salt = new byte[saltLen]; | |||
// Initialize all-zero nonce for each connection | |||
nonce = new byte[nonceLen]; | |||
logger.Dump($"masterkey {instanceId}", masterKey, keyLen); | |||
logger.Dump($"nonce {instanceId}", nonce, keyLen); | |||
} | |||
protected abstract Dictionary<string, CipherInfo> GetCiphers(); | |||
protected void InitKey(string password) | |||
{ | |||
byte[] passbuf = Encoding.UTF8.GetBytes(password); | |||
// init master key | |||
if (masterKey == null) | |||
{ | |||
masterKey = new byte[keyLen]; | |||
} | |||
if (masterKey.Length != keyLen) | |||
{ | |||
Array.Resize(ref masterKey, keyLen); | |||
} | |||
StreamCrypto.LegacyDeriveKey(passbuf, masterKey, keyLen); | |||
// init session key | |||
sessionKey = new byte[keyLen]; | |||
} | |||
public virtual void InitCipher(byte[] salt, bool isEncrypt) | |||
{ | |||
this.salt = new byte[saltLen]; | |||
Array.Copy(salt, this.salt, saltLen); | |||
CryptoUtils.HKDF(keyLen, masterKey, salt, InfoBytes).CopyTo(sessionKey, 0); | |||
logger.Dump($"salt {instanceId}", salt, saltLen); | |||
logger.Dump($"sessionkey {instanceId}", sessionKey, keyLen); | |||
} | |||
public abstract int CipherEncrypt(ReadOnlySpan<byte> plain, Span<byte> cipher); | |||
public abstract int CipherDecrypt(Span<byte> plain, ReadOnlySpan<byte> cipher); | |||
#region TCP | |||
[MethodImpl(MethodImplOptions.Synchronized)] | |||
public override int Encrypt(ReadOnlySpan<byte> plain, Span<byte> cipher) | |||
{ | |||
// push data | |||
Span<byte> tmp = buffer.AsSpan(0, plain.Length + bufPtr); | |||
plain.CopyTo(tmp.Slice(bufPtr)); | |||
int outlength = 0; | |||
if (!saltReady) | |||
{ | |||
saltReady = true; | |||
// Generate salt | |||
byte[] saltBytes = RNG.GetBytes(saltLen); | |||
InitCipher(saltBytes, true); | |||
saltBytes.CopyTo(cipher); | |||
outlength = saltLen; | |||
} | |||
if (!tcpRequestSent) | |||
{ | |||
tcpRequestSent = true; | |||
// read addr byte to encrypt | |||
int encAddrBufLength = ChunkEncrypt(tmp.Slice(0, AddressBufferLength), cipher.Slice(outlength)); | |||
tmp = tmp.Slice(AddressBufferLength); | |||
outlength += encAddrBufLength; | |||
} | |||
// handle other chunks | |||
while (true) | |||
{ | |||
// calculate next chunk size | |||
int bufSize = tmp.Length; | |||
if (bufSize <= 0) | |||
{ | |||
return outlength; | |||
} | |||
int chunklength = (int)Math.Min(bufSize, ChunkLengthMask); | |||
// read next chunk | |||
int encChunkLength = ChunkEncrypt(tmp.Slice(0, chunklength), cipher.Slice(outlength)); | |||
tmp = tmp.Slice(chunklength); | |||
outlength += encChunkLength; | |||
// check if we have enough space for outbuf | |||
// if not, keep buf for next run, at this condition, buffer is not empty | |||
if (outlength + TCPParameter.ChunkOverheadSize > TCPParameter.BufferSize) | |||
{ | |||
logger.Debug("enc outbuf almost full, giving up"); | |||
// write rest data to head of shared buffer | |||
tmp.CopyTo(buffer); | |||
bufPtr = tmp.Length; | |||
return outlength; | |||
} | |||
// check if buffer empty | |||
bufSize = tmp.Length; | |||
if (bufSize <= 0) | |||
{ | |||
logger.Debug("No more data to encrypt, leaving"); | |||
return outlength; | |||
} | |||
} | |||
} | |||
[MethodImpl(MethodImplOptions.Synchronized)] | |||
public override int Decrypt(Span<byte> plain, ReadOnlySpan<byte> cipher) | |||
{ | |||
int outlength = 0; | |||
// drop all into buffer | |||
Span<byte> tmp = buffer.AsSpan(0, cipher.Length + bufPtr); | |||
cipher.CopyTo(tmp.Slice(bufPtr)); | |||
int bufSize = tmp.Length; | |||
logger.Debug($"{instanceId} decrypt tcp, read salt: {!saltReady}"); | |||
if (!saltReady) | |||
{ | |||
// check if we get the leading salt | |||
if (bufSize <= saltLen) | |||
{ | |||
// need more, write back cache | |||
tmp.CopyTo(buffer); | |||
bufPtr = tmp.Length; | |||
return outlength; | |||
} | |||
saltReady = true; | |||
byte[] salt = tmp.Slice(0, saltLen).ToArray(); | |||
tmp = tmp.Slice(saltLen); | |||
InitCipher(salt, false); | |||
} | |||
// handle chunks | |||
while (true) | |||
{ | |||
bufSize = tmp.Length; | |||
// check if we have any data | |||
if (bufSize <= 0) | |||
{ | |||
logger.Trace("No data in buffer"); | |||
return outlength; | |||
} | |||
// first get chunk length | |||
if (bufSize <= ChunkLengthBytes + tagLen) | |||
{ | |||
// so we only have chunk length and its tag? | |||
// wait more | |||
logger.Trace($"{instanceId} not enough data to decrypt chunk. write {tmp.Length} byte back to buffer."); | |||
tmp.CopyTo(buffer); | |||
bufPtr = tmp.Length; | |||
return outlength; | |||
} | |||
logger.Trace($"{instanceId} try decrypt to offset {outlength}"); | |||
int len = ChunkDecrypt(plain.Slice(outlength), tmp); | |||
if (len <= 0) | |||
{ | |||
logger.Trace($"{instanceId} no chunk decrypted, write {tmp.Length} byte back to buffer."); | |||
// no chunk decrypted | |||
tmp.CopyTo(buffer); | |||
bufPtr = tmp.Length; | |||
return outlength; | |||
} | |||
logger.Trace($"{instanceId} decrypted {len} to offset {outlength}"); | |||
// drop decrypted data | |||
tmp = tmp.Slice(ChunkLengthBytes + tagLen + len + tagLen); | |||
outlength += len; | |||
// logger.Debug("aead dec outlength " + outlength); | |||
if (outlength + 100 > TCPParameter.BufferSize) | |||
{ | |||
logger.Trace($"{instanceId} output almost full, write {tmp.Length} byte back to buffer."); | |||
tmp.CopyTo(buffer); | |||
bufPtr = tmp.Length; | |||
return outlength; | |||
} | |||
bufSize = tmp.Length; | |||
// check if we already done all of them | |||
if (bufSize <= 0) | |||
{ | |||
bufPtr = 0; | |||
logger.Debug($"{instanceId} no data in buffer, already all done"); | |||
return outlength; | |||
} | |||
} | |||
} | |||
#endregion | |||
#region UDP | |||
[MethodImpl(MethodImplOptions.Synchronized)] | |||
public override int EncryptUDP(ReadOnlySpan<byte> plain, Span<byte> cipher) | |||
{ | |||
RNG.GetSpan(cipher.Slice(0, saltLen)); | |||
InitCipher(cipher.Slice(0, saltLen).ToArray(), true); | |||
return saltLen + CipherEncrypt(plain, cipher.Slice(saltLen)); | |||
} | |||
[MethodImpl(MethodImplOptions.Synchronized)] | |||
public override int DecryptUDP(Span<byte> plain, ReadOnlySpan<byte> cipher) | |||
{ | |||
InitCipher(cipher.Slice(0, saltLen).ToArray(), false); | |||
return CipherDecrypt(plain, cipher.Slice(saltLen)); | |||
} | |||
#endregion | |||
[MethodImpl(MethodImplOptions.Synchronized)] | |||
private int ChunkEncrypt(ReadOnlySpan<byte> plain, Span<byte> cipher) | |||
{ | |||
if (plain.Length > ChunkLengthMask) | |||
{ | |||
logger.Error("enc chunk too big"); | |||
throw new CryptoErrorException(); | |||
} | |||
byte[] lenbuf = BitConverter.GetBytes((ushort)IPAddress.HostToNetworkOrder((short)plain.Length)); | |||
int cipherLenSize = CipherEncrypt(lenbuf, cipher); | |||
CryptoUtils.SodiumIncrement(nonce); | |||
int cipherDataSize = CipherEncrypt(plain, cipher.Slice(cipherLenSize)); | |||
CryptoUtils.SodiumIncrement(nonce); | |||
return cipherLenSize + cipherDataSize; | |||
} | |||
[MethodImpl(MethodImplOptions.Synchronized)] | |||
private int ChunkDecrypt(Span<byte> plain, ReadOnlySpan<byte> cipher) | |||
{ | |||
// try to dec chunk len | |||
byte[] chunkLengthByte = new byte[ChunkLengthBytes]; | |||
CipherDecrypt(chunkLengthByte, cipher.Slice(0, ChunkLengthBytes + tagLen)); | |||
ushort chunkLength = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(chunkLengthByte, 0)); | |||
if (chunkLength > ChunkLengthMask) | |||
{ | |||
// we get invalid chunk | |||
logger.Error($"{instanceId} Invalid chunk length: {chunkLength}"); | |||
throw new CryptoErrorException(); | |||
} | |||
// logger.Debug("Get the real chunk len:" + chunkLength); | |||
int bufSize = cipher.Length; | |||
if (bufSize < ChunkLengthBytes + tagLen /* we haven't remove them */+ chunkLength + tagLen) | |||
{ | |||
logger.Debug($"{instanceId} need {ChunkLengthBytes + tagLen + chunkLength + tagLen}, but have {cipher.Length}"); | |||
return 0; | |||
} | |||
CryptoUtils.SodiumIncrement(nonce); | |||
// we have enough data to decrypt one chunk | |||
// drop chunk len and its tag from buffer | |||
int len = CipherDecrypt(plain, cipher.Slice(ChunkLengthBytes + tagLen, chunkLength + tagLen)); | |||
CryptoUtils.SodiumIncrement(nonce); | |||
logger.Trace($"{instanceId} decrypted {len} byte chunk used {ChunkLengthBytes + tagLen + chunkLength + tagLen} from {cipher.Length}"); | |||
return len; | |||
} | |||
} | |||
} |
@@ -1,15 +1,16 @@ | |||
using NaCl.Core; | |||
using NaCl.Core.Base; | |||
using System; | |||
using System.Collections.Generic; | |||
namespace Shadowsocks.Encryption.AEAD | |||
using NaCl.Core; | |||
using NaCl.Core.Base; | |||
namespace Shadowsocks.Crypto.AEAD | |||
{ | |||
public class AEADNaClEncryptor : AEADEncryptor | |||
public class AEADNaClCrypto : AEADCrypto | |||
{ | |||
SnufflePoly1305 enc; | |||
public AEADNaClEncryptor(string method, string password) : base(method, password) | |||
public AEADNaClCrypto(string method, string password) : base(method, password) | |||
{ | |||
} | |||
@@ -43,16 +44,19 @@ namespace Shadowsocks.Encryption.AEAD | |||
public override int CipherEncrypt(ReadOnlySpan<byte> plain, Span<byte> cipher) | |||
{ | |||
byte[] ct = enc.Encrypt(plain, null, nonce); | |||
ct.CopyTo(cipher); | |||
return ct.Length; | |||
//byte[] ct = enc.Encrypt(plain, null, nonce); | |||
//ct.CopyTo(cipher); | |||
//return ct.Length; | |||
throw new NotImplementedException(); | |||
} | |||
public override int CipherDecrypt(Span<byte> plain, ReadOnlySpan<byte> cipher) | |||
{ | |||
byte[] pt = enc.Decrypt(cipher, null, nonce); | |||
pt.CopyTo(plain); | |||
return pt.Length; | |||
//byte[] pt = enc.Decrypt(cipher, null, nonce); | |||
//pt.CopyTo(plain); | |||
//return pt.Length; | |||
throw new NotImplementedException(); | |||
} | |||
} | |||
} |
@@ -1,6 +1,4 @@ | |||
using Shadowsocks.Controller; | |||
namespace Shadowsocks.Encryption | |||
namespace Shadowsocks.Crypto | |||
{ | |||
public enum CipherFamily | |||
{ | |||
@@ -96,7 +94,9 @@ namespace Shadowsocks.Encryption | |||
public override string ToString() | |||
{ | |||
return StandardState == CipherStandardState.InUse ? Name : $"{Name} ({I18N.GetString(StandardState.ToString().ToLower())})"; | |||
// TODO: | |||
// return StandardState == CipherStandardState.InUse ? Name : $"{Name} ({I18N.GetString(StandardState.ToString().ToLower())})"; | |||
return ""; | |||
} | |||
public string ToString(bool verbose) | |||
{ | |||
@@ -108,4 +108,4 @@ namespace Shadowsocks.Encryption | |||
return $"{Name} {StandardState} {CipherParameter}"; | |||
} | |||
} | |||
} | |||
} |
@@ -1,49 +1,48 @@ | |||
using System; | |||
using System.Runtime.CompilerServices; | |||
namespace Shadowsocks.Encryption | |||
{ | |||
public abstract class EncryptorBase : IEncryptor | |||
{ | |||
private static int _currentId = 0; | |||
public const int MaxInputSize = 32768; | |||
public const int MAX_DOMAIN_LEN = 255; | |||
public const int ADDR_PORT_LEN = 2; | |||
public const int ADDR_ATYP_LEN = 1; | |||
public const int ATYP_IPv4 = 0x01; | |||
public const int ATYP_DOMAIN = 0x03; | |||
public const int ATYP_IPv6 = 0x04; | |||
public const int MD5Length = 16; | |||
// for debugging only, give it a number to trace data stream | |||
public readonly int instanceId; | |||
protected EncryptorBase(string method, string password) | |||
{ | |||
instanceId = _currentId; | |||
_currentId++; | |||
Method = method; | |||
Password = password; | |||
} | |||
protected string Method; | |||
protected string Password; | |||
public override string ToString() | |||
{ | |||
return $"{instanceId}({Method},{Password})"; | |||
} | |||
public abstract int Encrypt(ReadOnlySpan<byte> plain, Span<byte> cipher); | |||
public abstract int Decrypt(Span<byte> plain, ReadOnlySpan<byte> cipher); | |||
public abstract int EncryptUDP(ReadOnlySpan<byte> plain, Span<byte> cipher); | |||
public abstract int DecryptUDP(Span<byte> plain, ReadOnlySpan<byte> cipher); | |||
public int AddressBufferLength { get; set; } = -1; | |||
} | |||
} | |||
using System; | |||
namespace Shadowsocks.Crypto | |||
{ | |||
public abstract class CryptoBase : ICrypto | |||
{ | |||
private static int _currentId = 0; | |||
public const int MaxInputSize = 32768; | |||
public const int MAX_DOMAIN_LEN = 255; | |||
public const int ADDR_PORT_LEN = 2; | |||
public const int ADDR_ATYP_LEN = 1; | |||
public const int ATYP_IPv4 = 0x01; | |||
public const int ATYP_DOMAIN = 0x03; | |||
public const int ATYP_IPv6 = 0x04; | |||
public const int MD5Length = 16; | |||
// for debugging only, give it a number to trace data stream | |||
public readonly int instanceId; | |||
protected CryptoBase(string method, string password) | |||
{ | |||
instanceId = _currentId; | |||
_currentId++; | |||
Method = method; | |||
Password = password; | |||
} | |||
protected string Method; | |||
protected string Password; | |||
public override string ToString() | |||
{ | |||
return $"{instanceId}({Method},{Password})"; | |||
} | |||
public abstract int Encrypt(ReadOnlySpan<byte> plain, Span<byte> cipher); | |||
public abstract int Decrypt(Span<byte> plain, ReadOnlySpan<byte> cipher); | |||
public abstract int EncryptUDP(ReadOnlySpan<byte> plain, Span<byte> cipher); | |||
public abstract int DecryptUDP(Span<byte> plain, ReadOnlySpan<byte> cipher); | |||
public int AddressBufferLength { get; set; } = -1; | |||
} | |||
} |
@@ -1,119 +1,123 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Reflection; | |||
using System.Text; | |||
using Shadowsocks.Encryption.AEAD; | |||
using Shadowsocks.Encryption.Stream; | |||
namespace Shadowsocks.Encryption | |||
{ | |||
public static class EncryptorFactory | |||
{ | |||
public static string DefaultCipher = "chacha20-ietf-poly1305"; | |||
private static readonly Dictionary<string, Type> _registeredEncryptors = new Dictionary<string, Type>(); | |||
private static readonly Dictionary<string, CipherInfo> ciphers = new Dictionary<string, CipherInfo>(); | |||
private static readonly Type[] ConstructorTypes = { typeof(string), typeof(string) }; | |||
static EncryptorFactory() | |||
{ | |||
foreach (var method in StreamPlainNativeEncryptor.SupportedCiphers()) | |||
{ | |||
if (!_registeredEncryptors.ContainsKey(method.Key)) | |||
{ | |||
ciphers.Add(method.Key, method.Value); | |||
_registeredEncryptors.Add(method.Key, typeof(StreamPlainNativeEncryptor)); | |||
} | |||
} | |||
foreach (var method in StreamRc4NativeEncryptor.SupportedCiphers()) | |||
{ | |||
if (!_registeredEncryptors.ContainsKey(method.Key)) | |||
{ | |||
ciphers.Add(method.Key, method.Value); | |||
_registeredEncryptors.Add(method.Key, typeof(StreamRc4NativeEncryptor)); | |||
} | |||
} | |||
foreach (var method in StreamAesCfbBouncyCastleEncryptor.SupportedCiphers()) | |||
{ | |||
if (!_registeredEncryptors.ContainsKey(method.Key)) | |||
{ | |||
ciphers.Add(method.Key, method.Value); | |||
_registeredEncryptors.Add(method.Key, typeof(StreamAesCfbBouncyCastleEncryptor)); | |||
} | |||
} | |||
foreach (var method in StreamChachaNaClEncryptor.SupportedCiphers()) | |||
{ | |||
if (!_registeredEncryptors.ContainsKey(method.Key)) | |||
{ | |||
ciphers.Add(method.Key, method.Value); | |||
_registeredEncryptors.Add(method.Key, typeof(StreamChachaNaClEncryptor)); | |||
} | |||
} | |||
foreach (var method in AEADAesGcmNativeEncryptor.SupportedCiphers()) | |||
{ | |||
if (!_registeredEncryptors.ContainsKey(method.Key)) | |||
{ | |||
ciphers.Add(method.Key, method.Value); | |||
_registeredEncryptors.Add(method.Key, typeof(AEADAesGcmNativeEncryptor)); | |||
} | |||
} | |||
foreach (var method in AEADNaClEncryptor.SupportedCiphers()) | |||
{ | |||
if (!_registeredEncryptors.ContainsKey(method.Key)) | |||
{ | |||
ciphers.Add(method.Key, method.Value); | |||
_registeredEncryptors.Add(method.Key, typeof(AEADNaClEncryptor)); | |||
} | |||
} | |||
} | |||
public static IEncryptor GetEncryptor(string method, string password) | |||
{ | |||
if (string.IsNullOrEmpty(method)) | |||
{ | |||
method = Model.Server.DefaultMethod; | |||
} | |||
method = method.ToLowerInvariant(); | |||
bool ok = _registeredEncryptors.TryGetValue(method, out Type t); | |||
if (!ok) | |||
{ | |||
t = _registeredEncryptors[DefaultCipher]; | |||
} | |||
ConstructorInfo c = t?.GetConstructor(ConstructorTypes) ?? | |||
throw new TypeLoadException("can't load constructor"); | |||
if (c == null) throw new System.Exception("Invalid ctor"); | |||
IEncryptor result = (IEncryptor)c.Invoke(new object[] { method, password }); | |||
return result; | |||
} | |||
public static string DumpRegisteredEncryptor() | |||
{ | |||
var sb = new StringBuilder(); | |||
sb.Append(Environment.NewLine); | |||
sb.AppendLine("-------------------------"); | |||
sb.AppendLine("Registered Encryptor Info"); | |||
foreach (var encryptor in _registeredEncryptors) | |||
{ | |||
sb.AppendLine($"{ciphers[encryptor.Key].ToString(true)} => {encryptor.Value.Name}"); | |||
} | |||
// use ----- instead of =======, so when user paste it to Github, it won't became title | |||
sb.AppendLine("-------------------------"); | |||
return sb.ToString(); | |||
} | |||
public static CipherInfo GetCipherInfo(string name) | |||
{ | |||
// TODO: Replace cipher when required not exist | |||
return ciphers[name]; | |||
} | |||
public static IEnumerable<CipherInfo> ListAvaliableCiphers() | |||
{ | |||
return ciphers.Values; | |||
} | |||
} | |||
} | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Reflection; | |||
using System.Text; | |||
using Shadowsocks.Common.Crypto; | |||
using Shadowsocks.Common.Model; | |||
using Shadowsocks.Crypto.AEAD; | |||
using Shadowsocks.Crypto.Stream; | |||
namespace Shadowsocks.Crypto | |||
{ | |||
public static class CryptoFactory | |||
{ | |||
public static string DefaultCipher = "chacha20-ietf-poly1305"; | |||
private static readonly Dictionary<string, Type> _registeredEncryptors = new Dictionary<string, Type>(); | |||
private static readonly Dictionary<string, CipherInfo> ciphers = new Dictionary<string, CipherInfo>(); | |||
private static readonly Type[] ConstructorTypes = { typeof(string), typeof(string) }; | |||
static CryptoFactory() | |||
{ | |||
foreach (var method in StreamPlainNativeCrypto.SupportedCiphers()) | |||
{ | |||
if (!_registeredEncryptors.ContainsKey(method.Key)) | |||
{ | |||
ciphers.Add(method.Key, method.Value); | |||
_registeredEncryptors.Add(method.Key, typeof(StreamPlainNativeCrypto)); | |||
} | |||
} | |||
foreach (var method in StreamRc4NativeCrypto.SupportedCiphers()) | |||
{ | |||
if (!_registeredEncryptors.ContainsKey(method.Key)) | |||
{ | |||
ciphers.Add(method.Key, method.Value); | |||
_registeredEncryptors.Add(method.Key, typeof(StreamRc4NativeCrypto)); | |||
} | |||
} | |||
foreach (var method in StreamAesCfbBouncyCastleCrypto.SupportedCiphers()) | |||
{ | |||
if (!_registeredEncryptors.ContainsKey(method.Key)) | |||
{ | |||
ciphers.Add(method.Key, method.Value); | |||
_registeredEncryptors.Add(method.Key, typeof(StreamAesCfbBouncyCastleCrypto)); | |||
} | |||
} | |||
foreach (var method in StreamChachaNaClCrypto.SupportedCiphers()) | |||
{ | |||
if (!_registeredEncryptors.ContainsKey(method.Key)) | |||
{ | |||
ciphers.Add(method.Key, method.Value); | |||
_registeredEncryptors.Add(method.Key, typeof(StreamChachaNaClCrypto)); | |||
} | |||
} | |||
foreach (var method in AEADAesGcmNativeCrypto.SupportedCiphers()) | |||
{ | |||
if (!_registeredEncryptors.ContainsKey(method.Key)) | |||
{ | |||
ciphers.Add(method.Key, method.Value); | |||
_registeredEncryptors.Add(method.Key, typeof(AEADAesGcmNativeCrypto)); | |||
} | |||
} | |||
foreach (var method in AEADNaClCrypto.SupportedCiphers()) | |||
{ | |||
if (!_registeredEncryptors.ContainsKey(method.Key)) | |||
{ | |||
ciphers.Add(method.Key, method.Value); | |||
_registeredEncryptors.Add(method.Key, typeof(AEADNaClCrypto)); | |||
} | |||
} | |||
} | |||
public static ICrypto GetEncryptor(string method, string password) | |||
{ | |||
if (string.IsNullOrEmpty(method)) | |||
{ | |||
// todo | |||
//method = IoCManager.Container.Resolve<IDefaultCrypto>().GetDefaultMethod(); | |||
} | |||
method = method.ToLowerInvariant(); | |||
bool ok = _registeredEncryptors.TryGetValue(method, out Type t); | |||
if (!ok) | |||
{ | |||
t = _registeredEncryptors[DefaultCipher]; | |||
} | |||
ConstructorInfo c = t?.GetConstructor(ConstructorTypes) ?? | |||
throw new TypeLoadException("can't load constructor"); | |||
if (c == null) throw new System.Exception("Invalid ctor"); | |||
ICrypto result = (ICrypto)c.Invoke(new object[] { method, password }); | |||
return result; | |||
} | |||
public static string DumpRegisteredEncryptor() | |||
{ | |||
var sb = new StringBuilder(); | |||
sb.Append(Environment.NewLine); | |||
sb.AppendLine("-------------------------"); | |||
sb.AppendLine("Registered Encryptor Info"); | |||
foreach (var encryptor in _registeredEncryptors) | |||
{ | |||
sb.AppendLine($"{ciphers[encryptor.Key].ToString(true)} => {encryptor.Value.Name}"); | |||
} | |||
// use ----- instead of =======, so when user paste it to Github, it won't became title | |||
sb.AppendLine("-------------------------"); | |||
return sb.ToString(); | |||
} | |||
public static CipherInfo GetCipherInfo(string name) | |||
{ | |||
// TODO: Replace cipher when required not exist | |||
return ciphers[name]; | |||
} | |||
public static IEnumerable<CipherInfo> ListAvaliableCiphers() | |||
{ | |||
return ciphers.Values; | |||
} | |||
} | |||
} |
@@ -1,17 +1,17 @@ | |||
namespace Shadowsocks.Encryption.Exception | |||
{ | |||
public class CryptoErrorException : System.Exception | |||
{ | |||
public CryptoErrorException() | |||
{ | |||
} | |||
public CryptoErrorException(string msg) : base(msg) | |||
{ | |||
} | |||
public CryptoErrorException(string message, System.Exception innerException) : base(message, innerException) | |||
{ | |||
} | |||
} | |||
} | |||
namespace Shadowsocks.Crypto.Exception | |||
{ | |||
public class CryptoErrorException : System.Exception | |||
{ | |||
public CryptoErrorException() | |||
{ | |||
} | |||
public CryptoErrorException(string msg) : base(msg) | |||
{ | |||
} | |||
public CryptoErrorException(string message, System.Exception innerException) : base(message, innerException) | |||
{ | |||
} | |||
} | |||
} |
@@ -1,14 +1,14 @@ | |||
using System; | |||
namespace Shadowsocks.Encryption | |||
{ | |||
public interface IEncryptor | |||
{ | |||
/* length == -1 means not used */ | |||
int AddressBufferLength { set; get; } | |||
int Encrypt(ReadOnlySpan<byte> plain, Span<byte> cipher); | |||
int Decrypt(Span<byte> plain, ReadOnlySpan<byte> cipher); | |||
int EncryptUDP(ReadOnlySpan<byte> plain, Span<byte> cipher); | |||
int DecryptUDP(Span<byte> plain, ReadOnlySpan<byte> cipher); | |||
} | |||
} | |||
using System; | |||
namespace Shadowsocks.Crypto | |||
{ | |||
public interface ICrypto | |||
{ | |||
/* length == -1 means not used */ | |||
int AddressBufferLength { set; get; } | |||
int Encrypt(ReadOnlySpan<byte> plain, Span<byte> cipher); | |||
int Decrypt(Span<byte> plain, ReadOnlySpan<byte> cipher); | |||
int EncryptUDP(ReadOnlySpan<byte> plain, Span<byte> cipher); | |||
int DecryptUDP(Span<byte> plain, ReadOnlySpan<byte> cipher); | |||
} | |||
} |
@@ -1,50 +1,50 @@ | |||
using System; | |||
using System.Security.Cryptography; | |||
namespace Shadowsocks.Encryption | |||
{ | |||
public static class RNG | |||
{ | |||
private static RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider(); | |||
public static void Reload() | |||
{ | |||
_rng.Dispose(); | |||
_rng = new RNGCryptoServiceProvider(); | |||
} | |||
public static void GetSpan(Span<byte> span) | |||
{ | |||
_rng.GetBytes(span); | |||
} | |||
public static Span<byte> GetSpan(int length) | |||
{ | |||
Span<byte> span = new byte[length]; | |||
_rng.GetBytes(span); | |||
return span; | |||
} | |||
public static byte[] GetBytes(int length) | |||
{ | |||
byte[] buf = new byte[length]; | |||
_rng.GetBytes(buf); | |||
return buf; | |||
} | |||
public static void GetBytes(byte[] buf, int len) | |||
{ | |||
try | |||
{ | |||
_rng.GetBytes(buf, 0, len); | |||
} | |||
catch | |||
{ | |||
// the backup way | |||
byte[] tmp = new byte[len]; | |||
_rng.GetBytes(tmp); | |||
Buffer.BlockCopy(tmp, 0, buf, 0, len); | |||
} | |||
} | |||
} | |||
} | |||
using System; | |||
using System.Security.Cryptography; | |||
namespace Shadowsocks.Crypto | |||
{ | |||
public static class RNG | |||
{ | |||
private static RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider(); | |||
public static void Reload() | |||
{ | |||
_rng.Dispose(); | |||
_rng = new RNGCryptoServiceProvider(); | |||
} | |||
public static void GetSpan(Span<byte> span) | |||
{ | |||
_rng.GetBytes(span); | |||
} | |||
public static Span<byte> GetSpan(int length) | |||
{ | |||
Span<byte> span = new byte[length]; | |||
_rng.GetBytes(span); | |||
return span; | |||
} | |||
public static byte[] GetBytes(int length) | |||
{ | |||
byte[] buf = new byte[length]; | |||
_rng.GetBytes(buf); | |||
return buf; | |||
} | |||
public static void GetBytes(byte[] buf, int len) | |||
{ | |||
try | |||
{ | |||
_rng.GetBytes(buf, 0, len); | |||
} | |||
catch | |||
{ | |||
// the backup way | |||
byte[] tmp = new byte[len]; | |||
_rng.GetBytes(tmp); | |||
Buffer.BlockCopy(tmp, 0, buf, 0, len); | |||
} | |||
} | |||
} | |||
} |
@@ -1,19 +1,19 @@ | |||
using Org.BouncyCastle.Crypto.Engines; | |||
using Org.BouncyCastle.Crypto.Engines; | |||
using Org.BouncyCastle.Crypto.Modes; | |||
using Org.BouncyCastle.Crypto.Parameters; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Runtime.CompilerServices; | |||
namespace Shadowsocks.Encryption.Stream | |||
namespace Shadowsocks.Crypto.Stream | |||
{ | |||
public class StreamAesCfbBouncyCastleEncryptor : StreamEncryptor | |||
public class StreamAesCfbBouncyCastleCrypto : StreamCrypto | |||
{ | |||
readonly byte[] cfbBuf = new byte[MaxInputSize + 128]; | |||
int ptr = 0; | |||
readonly ExtendedCfbBlockCipher b; | |||
public StreamAesCfbBouncyCastleEncryptor(string method, string password) : base(method, password) | |||
public StreamAesCfbBouncyCastleCrypto(string method, string password) : base(method, password) | |||
{ | |||
b = new ExtendedCfbBlockCipher(new AesEngine(), 128); | |||
} | |||
@@ -36,7 +36,7 @@ namespace Shadowsocks.Encryption.Stream | |||
return cipher.Length; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)] | |||
[MethodImpl( MethodImplOptions.AggressiveInlining)] | |||
private void CipherUpdate(ReadOnlySpan<byte> i, Span<byte> o) | |||
{ | |||
Span<byte> ob = new byte[o.Length + 128]; |
@@ -1,11 +1,11 @@ | |||
using System; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Runtime.CompilerServices; | |||
using NaCl.Core; | |||
namespace Shadowsocks.Encryption.Stream | |||
namespace Shadowsocks.Crypto.Stream | |||
{ | |||
public class StreamChachaNaClEncryptor : StreamEncryptor | |||
public class StreamChachaNaClCrypto : StreamCrypto | |||
{ | |||
const int BlockSize = 64; | |||
@@ -22,7 +22,7 @@ namespace Shadowsocks.Encryption.Stream | |||
int remain = 0; | |||
// increase counter manually... | |||
int ic = 0; | |||
public StreamChachaNaClEncryptor(string method, string password) : base(method, password) | |||
public StreamChachaNaClCrypto(string method, string password) : base(method, password) | |||
{ | |||
} | |||
@@ -36,7 +36,7 @@ namespace Shadowsocks.Encryption.Stream | |||
return CipherUpdate(plain, cipher, true); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)] | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
private int CipherUpdate(ReadOnlySpan<byte> i, Span<byte> o, bool enc) | |||
{ | |||
// about performance problem: |
@@ -1,179 +1,181 @@ | |||
using NLog; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Runtime.CompilerServices; | |||
using System.Text; | |||
namespace Shadowsocks.Encryption.Stream | |||
{ | |||
public abstract class StreamEncryptor : EncryptorBase | |||
{ | |||
private static readonly Logger logger = LogManager.GetCurrentClassLogger(); | |||
// shared by TCP decrypt UDP encrypt and decrypt | |||
protected static byte[] sharedBuffer = new byte[65536]; | |||
// Is first packet | |||
protected bool ivReady; | |||
protected CipherFamily cipherFamily; | |||
protected CipherInfo CipherInfo; | |||
// long-time master key | |||
protected static byte[] key = Array.Empty<byte>(); | |||
protected byte[] iv = Array.Empty<byte>(); | |||
protected int keyLen; | |||
protected int ivLen; | |||
public StreamEncryptor(string method, string password) | |||
: base(method, password) | |||
{ | |||
CipherInfo = GetCiphers()[method.ToLower()]; | |||
cipherFamily = CipherInfo.Type; | |||
StreamCipherParameter parameter = (StreamCipherParameter)CipherInfo.CipherParameter; | |||
keyLen = parameter.KeySize; | |||
ivLen = parameter.IvSize; | |||
InitKey(password); | |||
logger.Dump($"key {instanceId}", key, keyLen); | |||
} | |||
protected abstract Dictionary<string, CipherInfo> GetCiphers(); | |||
private void InitKey(string password) | |||
{ | |||
byte[] passbuf = Encoding.UTF8.GetBytes(password); | |||
key ??= new byte[keyLen]; | |||
if (key.Length != keyLen) | |||
{ | |||
Array.Resize(ref key, keyLen); | |||
} | |||
LegacyDeriveKey(passbuf, key, keyLen); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void LegacyDeriveKey(byte[] password, byte[] key, int keylen) | |||
{ | |||
byte[] result = new byte[password.Length + MD5Length]; | |||
int i = 0; | |||
byte[] md5sum = Array.Empty<byte>(); | |||
while (i < keylen) | |||
{ | |||
if (i == 0) | |||
{ | |||
md5sum = CryptoUtils.MD5(password); | |||
} | |||
else | |||
{ | |||
Array.Copy(md5sum, 0, result, 0, MD5Length); | |||
Array.Copy(password, 0, result, MD5Length, password.Length); | |||
md5sum = CryptoUtils.MD5(result); | |||
} | |||
Array.Copy(md5sum, 0, key, i, Math.Min(MD5Length, keylen - i)); | |||
i += MD5Length; | |||
} | |||
} | |||
protected virtual void InitCipher(byte[] iv, bool isEncrypt) | |||
{ | |||
if (ivLen == 0) | |||
{ | |||
return; | |||
} | |||
this.iv = new byte[ivLen]; | |||
Array.Copy(iv, this.iv, ivLen); | |||
} | |||
protected abstract int CipherEncrypt(ReadOnlySpan<byte> plain, Span<byte> cipher); | |||
protected abstract int CipherDecrypt(Span<byte> plain, ReadOnlySpan<byte> cipher); | |||
#region TCP | |||
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)] | |||
public override int Encrypt(ReadOnlySpan<byte> plain, Span<byte> cipher) | |||
{ | |||
int cipherOffset = 0; | |||
logger.Trace($"{instanceId} encrypt TCP, generate iv: {!ivReady}"); | |||
if (!ivReady) | |||
{ | |||
// Generate IV | |||
byte[] ivBytes = RNG.GetBytes(ivLen); | |||
InitCipher(ivBytes, true); | |||
ivBytes.CopyTo(cipher); | |||
cipherOffset = ivLen; | |||
cipher = cipher.Slice(cipherOffset); | |||
ivReady = true; | |||
} | |||
int clen = CipherEncrypt(plain, cipher); | |||
logger.DumpBase64($"plain {instanceId}", plain); | |||
logger.DumpBase64($"cipher {instanceId}", cipher.Slice(0, clen)); | |||
logger.Dump($"iv {instanceId}", iv, ivLen); | |||
return clen + cipherOffset; | |||
} | |||
private int recieveCtr = 0; | |||
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)] | |||
public override int Decrypt(Span<byte> plain, ReadOnlySpan<byte> cipher) | |||
{ | |||
logger.Trace($"{instanceId} decrypt TCP, read iv: {!ivReady}"); | |||
int cipherOffset = 0; | |||
// is first packet, need read iv | |||
if (!ivReady) | |||
{ | |||
// push to buffer in case of not enough data | |||
cipher.CopyTo(sharedBuffer.AsSpan(recieveCtr)); | |||
recieveCtr += cipher.Length; | |||
// not enough data for read iv, return 0 byte data | |||
if (recieveCtr <= ivLen) | |||
{ | |||
return 0; | |||
} | |||
// start decryption | |||
ivReady = true; | |||
if (ivLen > 0) | |||
{ | |||
// read iv | |||
byte[] iv = sharedBuffer.AsSpan(0, ivLen).ToArray(); | |||
InitCipher(iv, false); | |||
} | |||
else | |||
{ | |||
InitCipher(Array.Empty<byte>(), false); | |||
} | |||
cipherOffset += ivLen; | |||
} | |||
// read all data from buffer | |||
int len = CipherDecrypt(plain, cipher.Slice(cipherOffset)); | |||
logger.DumpBase64($"cipher {instanceId}", cipher.Slice(cipherOffset)); | |||
logger.DumpBase64($"plain {instanceId}", plain.Slice(0, len)); | |||
logger.Dump($"iv {instanceId}", iv, ivLen); | |||
return len; | |||
} | |||
#endregion | |||
#region UDP | |||
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)] | |||
public override int EncryptUDP(ReadOnlySpan<byte> plain, Span<byte> cipher) | |||
{ | |||
byte[] iv = RNG.GetBytes(ivLen); | |||
iv.CopyTo(cipher); | |||
InitCipher(iv, true); | |||
return ivLen + CipherEncrypt(plain, cipher.Slice(ivLen)); | |||
} | |||
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)] | |||
public override int DecryptUDP(Span<byte> plain, ReadOnlySpan<byte> cipher) | |||
{ | |||
InitCipher(cipher.Slice(0, ivLen).ToArray(), false); | |||
return CipherDecrypt(plain, cipher.Slice(ivLen)); | |||
} | |||
#endregion | |||
} | |||
} | |||
using NLog; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Runtime.CompilerServices; | |||
using System.Text; | |||
namespace Shadowsocks.Crypto.Stream | |||
{ | |||
public abstract class StreamCrypto : CryptoBase | |||
{ | |||
private static readonly Logger logger = LogManager.GetCurrentClassLogger(); | |||
// shared by TCP decrypt UDP encrypt and decrypt | |||
protected static byte[] sharedBuffer = new byte[65536]; | |||
// Is first packet | |||
protected bool ivReady; | |||
protected CipherFamily cipherFamily; | |||
protected CipherInfo CipherInfo; | |||
// long-time master key | |||
protected static byte[] key = Array.Empty<byte>(); | |||
protected byte[] iv = Array.Empty<byte>(); | |||
protected int keyLen; | |||
protected int ivLen; | |||
public StreamCrypto(string method, string password) | |||
: base(method, password) | |||
{ | |||
CipherInfo = GetCiphers()[method.ToLower()]; | |||
cipherFamily = CipherInfo.Type; | |||
StreamCipherParameter parameter = (StreamCipherParameter)CipherInfo.CipherParameter; | |||
keyLen = parameter.KeySize; | |||
ivLen = parameter.IvSize; | |||
InitKey(password); | |||
logger.Dump($"key {instanceId}", key, keyLen); | |||
} | |||
protected abstract Dictionary<string, CipherInfo> GetCiphers(); | |||
private void InitKey(string password) | |||
{ | |||
byte[] passbuf = Encoding.UTF8.GetBytes(password); | |||
key ??= new byte[keyLen]; | |||
if (key.Length != keyLen) | |||
{ | |||
Array.Resize(ref key, keyLen); | |||
} | |||
LegacyDeriveKey(passbuf, key, keyLen); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void LegacyDeriveKey(byte[] password, byte[] key, int keylen) | |||
{ | |||
byte[] result = new byte[password.Length + MD5Length]; | |||
int i = 0; | |||
byte[] md5sum = Array.Empty<byte>(); | |||
while (i < keylen) | |||
{ | |||
if (i == 0) | |||
{ | |||
md5sum = CryptoUtils.MD5(password); | |||
} | |||
else | |||
{ | |||
Array.Copy(md5sum, 0, result, 0, MD5Length); | |||
Array.Copy(password, 0, result, MD5Length, password.Length); | |||
md5sum = CryptoUtils.MD5(result); | |||
} | |||
Array.Copy(md5sum, 0, key, i, Math.Min(MD5Length, keylen - i)); | |||
i += MD5Length; | |||
} | |||
} | |||
protected virtual void InitCipher(byte[] iv, bool isEncrypt) | |||
{ | |||
if (ivLen == 0) | |||
{ | |||
return; | |||
} | |||
this.iv = new byte[ivLen]; | |||
Array.Copy(iv, this.iv, ivLen); | |||
} | |||
protected abstract int CipherEncrypt(ReadOnlySpan<byte> plain, Span<byte> cipher); | |||
protected abstract int CipherDecrypt(Span<byte> plain, ReadOnlySpan<byte> cipher); | |||
#region TCP | |||
[MethodImpl(MethodImplOptions.Synchronized)] | |||
public override int Encrypt(ReadOnlySpan<byte> plain, Span<byte> cipher) | |||
{ | |||
int cipherOffset = 0; | |||
logger.Trace($"{instanceId} encrypt TCP, generate iv: {!ivReady}"); | |||
if (!ivReady) | |||
{ | |||
// Generate IV | |||
byte[] ivBytes = RNG.GetBytes(ivLen); | |||
InitCipher(ivBytes, true); | |||
ivBytes.CopyTo(cipher); | |||
cipherOffset = ivLen; | |||
cipher = cipher.Slice(cipherOffset); | |||
ivReady = true; | |||
} | |||
int clen = CipherEncrypt(plain, cipher); | |||
logger.DumpBase64($"plain {instanceId}", plain); | |||
logger.DumpBase64($"cipher {instanceId}", cipher.Slice(0, clen)); | |||
logger.Dump($"iv {instanceId}", iv, ivLen); | |||
return clen + cipherOffset; | |||
} | |||
private int recieveCtr = 0; | |||
[MethodImpl(MethodImplOptions.Synchronized)] | |||
public override int Decrypt(Span<byte> plain, ReadOnlySpan<byte> cipher) | |||
{ | |||
logger.Trace($"{instanceId} decrypt TCP, read iv: {!ivReady}"); | |||
int cipherOffset = 0; | |||
// is first packet, need read iv | |||
if (!ivReady) | |||
{ | |||
// push to buffer in case of not enough data | |||
cipher.CopyTo(sharedBuffer.AsSpan(recieveCtr)); | |||
recieveCtr += cipher.Length; | |||
// not enough data for read iv, return 0 byte data | |||
if (recieveCtr <= ivLen) | |||
{ | |||
return 0; | |||
} | |||
// start decryption | |||
ivReady = true; | |||
if (ivLen > 0) | |||
{ | |||
// read iv | |||
byte[] iv = sharedBuffer.AsSpan(0, ivLen).ToArray(); | |||
InitCipher(iv, false); | |||
} | |||
else | |||
{ | |||
InitCipher(Array.Empty<byte>(), false); | |||
} | |||
cipherOffset += ivLen; | |||
} | |||
// read all data from buffer | |||
int len = CipherDecrypt(plain, cipher.Slice(cipherOffset)); | |||
logger.DumpBase64($"cipher {instanceId}", cipher.Slice(cipherOffset)); | |||
logger.DumpBase64($"plain {instanceId}", plain.Slice(0, len)); | |||
logger.Dump($"iv {instanceId}", iv, ivLen); | |||
return len; | |||
} | |||
#endregion | |||
#region UDP | |||
[MethodImpl(MethodImplOptions.Synchronized)] | |||
public override int EncryptUDP(ReadOnlySpan<byte> plain, Span<byte> cipher) | |||
{ | |||
byte[] iv = RNG.GetBytes(ivLen); | |||
iv.CopyTo(cipher); | |||
InitCipher(iv, true); | |||
return ivLen + CipherEncrypt(plain, cipher.Slice(ivLen)); | |||
} | |||
[MethodImpl(MethodImplOptions.Synchronized)] | |||
public override int DecryptUDP(Span<byte> plain, ReadOnlySpan<byte> cipher) | |||
{ | |||
InitCipher(cipher.Slice(0, ivLen).ToArray(), false); | |||
return CipherDecrypt(plain, cipher.Slice(ivLen)); | |||
} | |||
#endregion | |||
} | |||
} |
@@ -1,12 +1,12 @@ | |||
using System; | |||
using System; | |||
using System.Collections.Generic; | |||
namespace Shadowsocks.Encryption.Stream | |||
namespace Shadowsocks.Crypto.Stream | |||
{ | |||
public class StreamPlainNativeEncryptor : StreamEncryptor | |||
public class StreamPlainNativeCrypto : StreamCrypto | |||
{ | |||
public StreamPlainNativeEncryptor(string method, string password) : base(method, password) | |||
public StreamPlainNativeCrypto(string method, string password) : base(method, password) | |||
{ | |||
} | |||
@@ -1,14 +1,14 @@ | |||
using System; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Runtime.CompilerServices; | |||
namespace Shadowsocks.Encryption.Stream | |||
namespace Shadowsocks.Crypto.Stream | |||
{ | |||
public class StreamRc4NativeEncryptor : StreamEncryptor | |||
public class StreamRc4NativeCrypto : StreamCrypto | |||
{ | |||
byte[] realkey = new byte[256]; | |||
byte[] sbox = new byte[256]; | |||
public StreamRc4NativeEncryptor(string method, string password) : base(method, password) | |||
public StreamRc4NativeCrypto(string method, string password) : base(method, password) | |||
{ | |||
} | |||
@@ -94,7 +94,6 @@ namespace Shadowsocks.Encryption.Stream | |||
return s; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveOptimization)] | |||
private void RC4(Span<byte> s, Span<byte> data, int length) | |||
{ | |||
for (int n = 0; n < length; n++) |
@@ -0,0 +1,20 @@ | |||
using Shadowsocks.Crypto.AEAD; | |||
namespace Shadowsocks.Crypto | |||
{ | |||
public static class TCPParameter | |||
{ | |||
// each recv size. | |||
public const int RecvSize = 2048; | |||
// overhead of one chunk, reserved for AEAD ciphers | |||
// /* two tags */ | |||
public const int ChunkOverheadSize = 16 * 2 + AEADCrypto.ChunkLengthBytes; | |||
// max chunk size | |||
public const uint MaxChunkSize = AEADCrypto.ChunkLengthMask + AEADCrypto.ChunkLengthBytes + 16 * 2; | |||
// In general, the ciphertext length, we should take overhead into account | |||
public const int BufferSize = RecvSize + (int)MaxChunkSize + 32 /* max salt len */; | |||
} | |||
} |
@@ -0,0 +1,18 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
<PropertyGroup> | |||
<TargetFramework>netstandard2.1</TargetFramework> | |||
<Authors>clowwindy & community 2020</Authors> | |||
<Product>Shadowsocks Crypto</Product> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<PackageReference Include="BouncyCastle.NetCore" Version="1.8.6" /> | |||
<PackageReference Include="NaCl.Core" Version="2.0.0" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\Shadowsocks.Common\Shadowsocks.Common.csproj" /> | |||
</ItemGroup> | |||
</Project> |
@@ -1,4 +1,4 @@ | |||
using Org.BouncyCastle.Crypto; | |||
using Org.BouncyCastle.Crypto; | |||
using Org.BouncyCastle.Crypto.Digests; | |||
using Org.BouncyCastle.Crypto.Generators; | |||
using Org.BouncyCastle.Crypto.Parameters; | |||
@@ -6,7 +6,7 @@ using System; | |||
using System.Security.Cryptography; | |||
using System.Threading; | |||
namespace Shadowsocks.Encryption | |||
namespace Shadowsocks.Crypto | |||
{ | |||
public static class CryptoUtils | |||
{ | |||
@@ -14,14 +14,14 @@ namespace Shadowsocks.Encryption | |||
public static byte[] MD5(byte[] b) | |||
{ | |||
var hash = new byte[EncryptorBase.MD5Length]; | |||
var hash = new byte[CryptoBase.MD5Length]; | |||
Md5Hasher.Value.TryComputeHash(b, hash, out _); | |||
return hash; | |||
} | |||
// currently useless, just keep api same | |||
public static Span<byte> MD5(Span<byte> span) | |||
{ | |||
Span<byte> hash = new byte[EncryptorBase.MD5Length]; | |||
Span<byte> hash = new byte[CryptoBase.MD5Length]; | |||
Md5Hasher.Value.TryComputeHash(span, hash, out _); | |||
return hash; | |||
} |
@@ -0,0 +1,15 @@ | |||
<Application x:Class="Shadowsocks.WPF.App" | |||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |||
xmlns:local="clr-namespace:Shadowsocks.WPF" | |||
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes" | |||
StartupUri="Views/MainWindow.xaml"> | |||
<Application.Resources> | |||
<ResourceDictionary> | |||
<ResourceDictionary.MergedDictionaries> | |||
<md:BundledTheme BaseTheme="Light" PrimaryColor="DeepPurple" SecondaryColor="Lime" /> | |||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" /> | |||
</ResourceDictionary.MergedDictionaries> | |||
</ResourceDictionary> | |||
</Application.Resources> | |||
</Application> |
@@ -0,0 +1,20 @@ | |||
using ReactiveUI; | |||
using Splat; | |||
using System.Reflection; | |||
using System.Windows; | |||
namespace Shadowsocks.WPF | |||
{ | |||
/// <summary> | |||
/// Interaction logic for App.xaml | |||
/// </summary> | |||
public partial class App : Application | |||
{ | |||
public App() | |||
{ | |||
Locator.CurrentMutable.RegisterViewsForViewModels(Assembly.GetCallingAssembly()); | |||
} | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
using System.Windows; | |||
[assembly: ThemeInfo( | |||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located | |||
//(used if a resource is not found in the page, | |||
// or application resource dictionaries) | |||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located | |||
//(used if a resource is not found in the page, | |||
// app, or any theme specific resource dictionaries) | |||
)] |
@@ -0,0 +1,3 @@ | |||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> | |||
<ReactiveUI /> | |||
</Weavers> |
@@ -0,0 +1,26 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> | |||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> | |||
<xs:element name="Weavers"> | |||
<xs:complexType> | |||
<xs:all> | |||
<xs:element name="ReactiveUI" minOccurs="0" maxOccurs="1" type="xs:anyType" /> | |||
</xs:all> | |||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> | |||
<xs:annotation> | |||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> | |||
</xs:annotation> | |||
</xs:attribute> | |||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> | |||
<xs:annotation> | |||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> | |||
</xs:annotation> | |||
</xs:attribute> | |||
<xs:attribute name="GenerateXsd" type="xs:boolean"> | |||
<xs:annotation> | |||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> | |||
</xs:annotation> | |||
</xs:attribute> | |||
</xs:complexType> | |||
</xs:element> | |||
</xs:schema> |
@@ -0,0 +1,15 @@ | |||
using Shadowsocks.Common.Model; | |||
using System.Reflection; | |||
using WPFLocalizeExtension.Extensions; | |||
namespace Shadowsocks.WPF.Localization | |||
{ | |||
public class LocalizationProvider : ILocalizationProvider | |||
{ | |||
private static readonly string CallingAssemblyName = Assembly.GetCallingAssembly().GetName().Name; | |||
public T GetLocalizedValue<T>(string key) => LocExtension.GetLocalizedValue<T>($"{CallingAssemblyName}:Strings:{key}"); | |||
} | |||
} |
@@ -8,7 +8,7 @@ | |||
// </auto-generated> | |||
//------------------------------------------------------------------------------ | |||
namespace Shadowsocks.Localization { | |||
namespace Shadowsocks.WPF.Localization { | |||
using System; | |||
@@ -1,189 +1,189 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<root> | |||
<!-- | |||
Microsoft ResX Schema | |||
Version 2.0 | |||
The primary goals of this format is to allow a simple XML format | |||
that is mostly human readable. The generation and parsing of the | |||
various data types are done through the TypeConverter classes | |||
associated with the data types. | |||
Example: | |||
... ado.net/XML headers & schema ... | |||
<resheader name="resmimetype">text/microsoft-resx</resheader> | |||
<resheader name="version">2.0</resheader> | |||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | |||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | |||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> | |||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | |||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | |||
<value>[base64 mime encoded serialized .NET Framework object]</value> | |||
</data> | |||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | |||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> | |||
<comment>This is a comment</comment> | |||
</data> | |||
There are any number of "resheader" rows that contain simple | |||
name/value pairs. | |||
Each data row contains a name, and value. The row also contains a | |||
type or mimetype. Type corresponds to a .NET class that support | |||
text/value conversion through the TypeConverter architecture. | |||
Classes that don't support this are serialized and stored with the | |||
mimetype set. | |||
The mimetype is used for serialized objects, and tells the | |||
ResXResourceReader how to depersist the object. This is currently not | |||
extensible. For a given mimetype the value must be set accordingly: | |||
Note - application/x-microsoft.net.object.binary.base64 is the format | |||
that the ResXResourceWriter will generate, however the reader can | |||
read any of the formats listed below. | |||
mimetype: application/x-microsoft.net.object.binary.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.soap.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.bytearray.base64 | |||
value : The object must be serialized into a byte array | |||
: using a System.ComponentModel.TypeConverter | |||
: and then encoded with base64 encoding. | |||
--> | |||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | |||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> | |||
<xsd:element name="root" msdata:IsDataSet="true"> | |||
<xsd:complexType> | |||
<xsd:choice maxOccurs="unbounded"> | |||
<xsd:element name="metadata"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" use="required" type="xsd:string" /> | |||
<xsd:attribute name="type" type="xsd:string" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="assembly"> | |||
<xsd:complexType> | |||
<xsd:attribute name="alias" type="xsd:string" /> | |||
<xsd:attribute name="name" type="xsd:string" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="data"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> | |||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="resheader"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:choice> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:schema> | |||
<resheader name="resmimetype"> | |||
<value>text/microsoft-resx</value> | |||
</resheader> | |||
<resheader name="version"> | |||
<value>2.0</value> | |||
</resheader> | |||
<resheader name="reader"> | |||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<resheader name="writer"> | |||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<data name="Password" xml:space="preserve"> | |||
<value>密碼</value> | |||
</data> | |||
<data name="Port" xml:space="preserve"> | |||
<value>Port</value> | |||
</data> | |||
<data name="Type" xml:space="preserve"> | |||
<value>類型</value> | |||
</data> | |||
<data name="Address" xml:space="preserve"> | |||
<value>位址</value> | |||
</data> | |||
<data name="Timeout" xml:space="preserve"> | |||
<value>逾時 (秒)</value> | |||
</data> | |||
<data name="cancelButton_Content" xml:space="preserve"> | |||
<value>取消</value> | |||
</data> | |||
<data name="okButton_Content" xml:space="preserve"> | |||
<value>確定</value> | |||
</data> | |||
<data name="ToggleSystemProxy" xml:space="preserve"> | |||
<value>切換系統 Proxy 狀態</value> | |||
</data> | |||
<data name="ToggleProxyMode" xml:space="preserve"> | |||
<value>切換系統 Proxy 模式</value> | |||
</data> | |||
<data name="AllowClientsFromLAN" xml:space="preserve"> | |||
<value>切換區域網路共用</value> | |||
</data> | |||
<data name="OpenLogsWindow" xml:space="preserve"> | |||
<value>顯示記錄檔</value> | |||
</data> | |||
<data name="SwitchToPreviousServer" xml:space="preserve"> | |||
<value>切換上一個伺服器</value> | |||
</data> | |||
<data name="SwitchToNextServer" xml:space="preserve"> | |||
<value>切換下一個伺服器</value> | |||
</data> | |||
<data name="RegisterHotkeysAtStartup" xml:space="preserve"> | |||
<value>註冊所有快速鍵</value> | |||
</data> | |||
<data name="registerAllButton_Content" xml:space="preserve"> | |||
<value>啟動時註冊快速鍵</value> | |||
</data> | |||
<data name="updateButton_Content" xml:space="preserve"> | |||
<value>更新</value> | |||
</data> | |||
<data name="updateAllButton_Content" xml:space="preserve"> | |||
<value>全部更新</value> | |||
</data> | |||
<data name="addButton_Content" xml:space="preserve"> | |||
<value>新增</value> | |||
</data> | |||
<data name="skipVersionButton_Content" xml:space="preserve"> | |||
<value>跳過版本</value> | |||
</data> | |||
<data name="notNowButton_Content" xml:space="preserve"> | |||
<value>暫不更新</value> | |||
</data> | |||
<data name="updatePromptTitle" xml:space="preserve"> | |||
<value>發現可用更新</value> | |||
</data> | |||
<data name="copyLinkButton_Content" xml:space="preserve"> | |||
<value>複製鏈接</value> | |||
</data> | |||
<data name="Copy" xml:space="preserve"> | |||
<value>複製</value> | |||
</data> | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<root> | |||
<!-- | |||
Microsoft ResX Schema | |||
Version 2.0 | |||
The primary goals of this format is to allow a simple XML format | |||
that is mostly human readable. The generation and parsing of the | |||
various data types are done through the TypeConverter classes | |||
associated with the data types. | |||
Example: | |||
... ado.net/XML headers & schema ... | |||
<resheader name="resmimetype">text/microsoft-resx</resheader> | |||
<resheader name="version">2.0</resheader> | |||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | |||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | |||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> | |||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | |||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | |||
<value>[base64 mime encoded serialized .NET Framework object]</value> | |||
</data> | |||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | |||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> | |||
<comment>This is a comment</comment> | |||
</data> | |||
There are any number of "resheader" rows that contain simple | |||
name/value pairs. | |||
Each data row contains a name, and value. The row also contains a | |||
type or mimetype. Type corresponds to a .NET class that support | |||
text/value conversion through the TypeConverter architecture. | |||
Classes that don't support this are serialized and stored with the | |||
mimetype set. | |||
The mimetype is used for serialized objects, and tells the | |||
ResXResourceReader how to depersist the object. This is currently not | |||
extensible. For a given mimetype the value must be set accordingly: | |||
Note - application/x-microsoft.net.object.binary.base64 is the format | |||
that the ResXResourceWriter will generate, however the reader can | |||
read any of the formats listed below. | |||
mimetype: application/x-microsoft.net.object.binary.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.soap.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.bytearray.base64 | |||
value : The object must be serialized into a byte array | |||
: using a System.ComponentModel.TypeConverter | |||
: and then encoded with base64 encoding. | |||
--> | |||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | |||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> | |||
<xsd:element name="root" msdata:IsDataSet="true"> | |||
<xsd:complexType> | |||
<xsd:choice maxOccurs="unbounded"> | |||
<xsd:element name="metadata"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" use="required" type="xsd:string" /> | |||
<xsd:attribute name="type" type="xsd:string" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="assembly"> | |||
<xsd:complexType> | |||
<xsd:attribute name="alias" type="xsd:string" /> | |||
<xsd:attribute name="name" type="xsd:string" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="data"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> | |||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="resheader"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:choice> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:schema> | |||
<resheader name="resmimetype"> | |||
<value>text/microsoft-resx</value> | |||
</resheader> | |||
<resheader name="version"> | |||
<value>2.0</value> | |||
</resheader> | |||
<resheader name="reader"> | |||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<resheader name="writer"> | |||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<data name="Password" xml:space="preserve"> | |||
<value>密碼</value> | |||
</data> | |||
<data name="Port" xml:space="preserve"> | |||
<value>Port</value> | |||
</data> | |||
<data name="Type" xml:space="preserve"> | |||
<value>類型</value> | |||
</data> | |||
<data name="Address" xml:space="preserve"> | |||
<value>位址</value> | |||
</data> | |||
<data name="Timeout" xml:space="preserve"> | |||
<value>逾時 (秒)</value> | |||
</data> | |||
<data name="cancelButton_Content" xml:space="preserve"> | |||
<value>取消</value> | |||
</data> | |||
<data name="okButton_Content" xml:space="preserve"> | |||
<value>確定</value> | |||
</data> | |||
<data name="ToggleSystemProxy" xml:space="preserve"> | |||
<value>切換系統 Proxy 狀態</value> | |||
</data> | |||
<data name="ToggleProxyMode" xml:space="preserve"> | |||
<value>切換系統 Proxy 模式</value> | |||
</data> | |||
<data name="AllowClientsFromLAN" xml:space="preserve"> | |||
<value>切換區域網路共用</value> | |||
</data> | |||
<data name="OpenLogsWindow" xml:space="preserve"> | |||
<value>顯示記錄檔</value> | |||
</data> | |||
<data name="SwitchToPreviousServer" xml:space="preserve"> | |||
<value>切換上一個伺服器</value> | |||
</data> | |||
<data name="SwitchToNextServer" xml:space="preserve"> | |||
<value>切換下一個伺服器</value> | |||
</data> | |||
<data name="RegisterHotkeysAtStartup" xml:space="preserve"> | |||
<value>註冊所有快速鍵</value> | |||
</data> | |||
<data name="registerAllButton_Content" xml:space="preserve"> | |||
<value>啟動時註冊快速鍵</value> | |||
</data> | |||
<data name="updateButton_Content" xml:space="preserve"> | |||
<value>更新</value> | |||
</data> | |||
<data name="updateAllButton_Content" xml:space="preserve"> | |||
<value>全部更新</value> | |||
</data> | |||
<data name="addButton_Content" xml:space="preserve"> | |||
<value>新增</value> | |||
</data> | |||
<data name="skipVersionButton_Content" xml:space="preserve"> | |||
<value>跳過版本</value> | |||
</data> | |||
<data name="notNowButton_Content" xml:space="preserve"> | |||
<value>暫不更新</value> | |||
</data> | |||
<data name="updatePromptTitle" xml:space="preserve"> | |||
<value>發現可用更新</value> | |||
</data> | |||
<data name="copyLinkButton_Content" xml:space="preserve"> | |||
<value>複製鏈接</value> | |||
</data> | |||
<data name="Copy" xml:space="preserve"> | |||
<value>複製</value> | |||
</data> | |||
</root> |
@@ -1,12 +1,14 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<!-- | |||
https://go.microsoft.com/fwlink/?LinkID=208121. | |||
--> | |||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
<PropertyGroup> | |||
<Configuration>Release</Configuration> | |||
<Platform>Any CPU</Platform> | |||
<PublishDir>bin\Release\netcoreapp3.1\publish\</PublishDir> | |||
<PublishProtocol>FileSystem</PublishProtocol> | |||
</PropertyGroup> | |||
--> | |||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
<PropertyGroup> | |||
<Configuration>Debug</Configuration> | |||
<Platform>Any CPU</Platform> | |||
<PublishDir>bin\Release\netcoreapp3.1\publish\</PublishDir> | |||
<PublishProtocol>FileSystem</PublishProtocol> | |||
<TargetFramework>netcoreapp3.1</TargetFramework> | |||
<SelfContained>false</SelfContained> | |||
</PropertyGroup> | |||
</Project> |
@@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. | |||
<PropertyGroup> | |||
<Configuration>Release</Configuration> | |||
<Platform>Any CPU</Platform> | |||
<PublishDir>bin\Release\netcoreapp3.1\win-x64\publish\</PublishDir> | |||
<PublishDir>bin\Release\netcoreapp3.1\publish\</PublishDir> | |||
<PublishProtocol>FileSystem</PublishProtocol> | |||
<TargetFramework>netcoreapp3.1</TargetFramework> | |||
<RuntimeIdentifier>win-x64</RuntimeIdentifier> |
@@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. | |||
<PropertyGroup> | |||
<Configuration>Release</Configuration> | |||
<Platform>Any CPU</Platform> | |||
<PublishDir>bin\Release\netcoreapp3.1\win-x86\publish\</PublishDir> | |||
<PublishDir>bin\Release\netcoreapp3.1\publish\</PublishDir> | |||
<PublishProtocol>FileSystem</PublishProtocol> | |||
<TargetFramework>netcoreapp3.1</TargetFramework> | |||
<RuntimeIdentifier>win-x86</RuntimeIdentifier> |
@@ -1,6 +1,6 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<!-- | |||
https://go.microsoft.com/fwlink/?LinkID=208121. | |||
--> | |||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
</Project> | |||
--> | |||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
</Project> |
@@ -0,0 +1,133 @@ | |||
//------------------------------------------------------------------------------ | |||
// <auto-generated> | |||
// 此代码由工具生成。 | |||
// 运行时版本:4.0.30319.42000 | |||
// | |||
// 对此文件的更改可能会导致不正确的行为,并且如果 | |||
// 重新生成代码,这些更改将会丢失。 | |||
// </auto-generated> | |||
//------------------------------------------------------------------------------ | |||
namespace Shadowsocks.WPF { | |||
using System; | |||
/// <summary> | |||
/// 一个强类型的资源类,用于查找本地化的字符串等。 | |||
/// </summary> | |||
// 此类是由 StronglyTypedResourceBuilder | |||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 | |||
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen | |||
// (以 /str 作为命令选项),或重新生成 VS 项目。 | |||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] | |||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] | |||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] | |||
internal class Resource { | |||
private static global::System.Resources.ResourceManager resourceMan; | |||
private static global::System.Globalization.CultureInfo resourceCulture; | |||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] | |||
internal Resource() { | |||
} | |||
/// <summary> | |||
/// 返回此类使用的缓存的 ResourceManager 实例。 | |||
/// </summary> | |||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] | |||
internal static global::System.Resources.ResourceManager ResourceManager { | |||
get { | |||
if (object.ReferenceEquals(resourceMan, null)) { | |||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Shadowsocks.WPF.Resource", typeof(Resource).Assembly); | |||
resourceMan = temp; | |||
} | |||
return resourceMan; | |||
} | |||
} | |||
/// <summary> | |||
/// 重写当前线程的 CurrentUICulture 属性 | |||
/// 重写当前线程的 CurrentUICulture 属性。 | |||
/// </summary> | |||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] | |||
internal static global::System.Globalization.CultureInfo Culture { | |||
get { | |||
return resourceCulture; | |||
} | |||
set { | |||
resourceCulture = value; | |||
} | |||
} | |||
/// <summary> | |||
/// 查找 System.Byte[] 类型的本地化资源。 | |||
/// </summary> | |||
internal static byte[] ss128 { | |||
get { | |||
object obj = ResourceManager.GetObject("ss128", resourceCulture); | |||
return ((byte[])(obj)); | |||
} | |||
} | |||
/// <summary> | |||
/// 查找 System.Byte[] 类型的本地化资源。 | |||
/// </summary> | |||
internal static byte[] ss32 { | |||
get { | |||
object obj = ResourceManager.GetObject("ss32", resourceCulture); | |||
return ((byte[])(obj)); | |||
} | |||
} | |||
/// <summary> | |||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。 | |||
/// </summary> | |||
internal static System.Drawing.Bitmap ss32Fill { | |||
get { | |||
object obj = ResourceManager.GetObject("ss32Fill", resourceCulture); | |||
return ((System.Drawing.Bitmap)(obj)); | |||
} | |||
} | |||
/// <summary> | |||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。 | |||
/// </summary> | |||
internal static System.Drawing.Bitmap ss32In { | |||
get { | |||
object obj = ResourceManager.GetObject("ss32In", resourceCulture); | |||
return ((System.Drawing.Bitmap)(obj)); | |||
} | |||
} | |||
/// <summary> | |||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。 | |||
/// </summary> | |||
internal static System.Drawing.Bitmap ss32Out { | |||
get { | |||
object obj = ResourceManager.GetObject("ss32Out", resourceCulture); | |||
return ((System.Drawing.Bitmap)(obj)); | |||
} | |||
} | |||
/// <summary> | |||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。 | |||
/// </summary> | |||
internal static System.Drawing.Bitmap ss32Outline { | |||
get { | |||
object obj = ResourceManager.GetObject("ss32Outline", resourceCulture); | |||
return ((System.Drawing.Bitmap)(obj)); | |||
} | |||
} | |||
/// <summary> | |||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。 | |||
/// </summary> | |||
internal static System.Drawing.Bitmap ssw128 { | |||
get { | |||
object obj = ResourceManager.GetObject("ssw128", resourceCulture); | |||
return ((System.Drawing.Bitmap)(obj)); | |||
} | |||
} | |||
} | |||
} |
@@ -1,157 +1,142 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<root> | |||
<!-- | |||
Microsoft ResX Schema | |||
Version 2.0 | |||
The primary goals of this format is to allow a simple XML format | |||
that is mostly human readable. The generation and parsing of the | |||
various data types are done through the TypeConverter classes | |||
associated with the data types. | |||
Example: | |||
... ado.net/XML headers & schema ... | |||
<resheader name="resmimetype">text/microsoft-resx</resheader> | |||
<resheader name="version">2.0</resheader> | |||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | |||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | |||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> | |||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | |||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | |||
<value>[base64 mime encoded serialized .NET Framework object]</value> | |||
</data> | |||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | |||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> | |||
<comment>This is a comment</comment> | |||
</data> | |||
There are any number of "resheader" rows that contain simple | |||
name/value pairs. | |||
Each data row contains a name, and value. The row also contains a | |||
type or mimetype. Type corresponds to a .NET class that support | |||
text/value conversion through the TypeConverter architecture. | |||
Classes that don't support this are serialized and stored with the | |||
mimetype set. | |||
The mimetype is used for serialized objects, and tells the | |||
ResXResourceReader how to depersist the object. This is currently not | |||
extensible. For a given mimetype the value must be set accordingly: | |||
Note - application/x-microsoft.net.object.binary.base64 is the format | |||
that the ResXResourceWriter will generate, however the reader can | |||
read any of the formats listed below. | |||
mimetype: application/x-microsoft.net.object.binary.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.soap.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.bytearray.base64 | |||
value : The object must be serialized into a byte array | |||
: using a System.ComponentModel.TypeConverter | |||
: and then encoded with base64 encoding. | |||
--> | |||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | |||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> | |||
<xsd:element name="root" msdata:IsDataSet="true"> | |||
<xsd:complexType> | |||
<xsd:choice maxOccurs="unbounded"> | |||
<xsd:element name="metadata"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" use="required" type="xsd:string" /> | |||
<xsd:attribute name="type" type="xsd:string" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="assembly"> | |||
<xsd:complexType> | |||
<xsd:attribute name="alias" type="xsd:string" /> | |||
<xsd:attribute name="name" type="xsd:string" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="data"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> | |||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="resheader"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:choice> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:schema> | |||
<resheader name="resmimetype"> | |||
<value>text/microsoft-resx</value> | |||
</resheader> | |||
<resheader name="version"> | |||
<value>2.0</value> | |||
</resheader> | |||
<resheader name="reader"> | |||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<resheader name="writer"> | |||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> | |||
<data name="abp_js" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>..\Data\abp.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;gb2312</value> | |||
</data> | |||
<data name="dlc_dat" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>..\data\dlc.dat;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</data> | |||
<data name="i18n_csv" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>..\Data\i18n.csv;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value> | |||
</data> | |||
<data name="NLog_config" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>..\data\nlog.config;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value> | |||
</data> | |||
<data name="privoxy_conf" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>..\data\privoxy_conf.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value> | |||
</data> | |||
<data name="privoxy_exe" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>..\data\privoxy.exe.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</data> | |||
<data name="ss32Fill" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>..\Resources\ss32Fill.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | |||
</data> | |||
<data name="ss32In" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>..\Resources\ss32In.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | |||
</data> | |||
<data name="ss32Out" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>..\Resources\ss32Out.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | |||
</data> | |||
<data name="ss32Outline" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>..\Resources\ss32Outline.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | |||
</data> | |||
<data name="ssw128" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>..\Resources\ssw128.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | |||
</data> | |||
<data name="user_rule" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>..\data\user-rule.txt;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value> | |||
</data> | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<root> | |||
<!-- | |||
Microsoft ResX Schema | |||
Version 2.0 | |||
The primary goals of this format is to allow a simple XML format | |||
that is mostly human readable. The generation and parsing of the | |||
various data types are done through the TypeConverter classes | |||
associated with the data types. | |||
Example: | |||
... ado.net/XML headers & schema ... | |||
<resheader name="resmimetype">text/microsoft-resx</resheader> | |||
<resheader name="version">2.0</resheader> | |||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | |||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | |||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> | |||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | |||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | |||
<value>[base64 mime encoded serialized .NET Framework object]</value> | |||
</data> | |||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | |||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> | |||
<comment>This is a comment</comment> | |||
</data> | |||
There are any number of "resheader" rows that contain simple | |||
name/value pairs. | |||
Each data row contains a name, and value. The row also contains a | |||
type or mimetype. Type corresponds to a .NET class that support | |||
text/value conversion through the TypeConverter architecture. | |||
Classes that don't support this are serialized and stored with the | |||
mimetype set. | |||
The mimetype is used for serialized objects, and tells the | |||
ResXResourceReader how to depersist the object. This is currently not | |||
extensible. For a given mimetype the value must be set accordingly: | |||
Note - application/x-microsoft.net.object.binary.base64 is the format | |||
that the ResXResourceWriter will generate, however the reader can | |||
read any of the formats listed below. | |||
mimetype: application/x-microsoft.net.object.binary.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.soap.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.bytearray.base64 | |||
value : The object must be serialized into a byte array | |||
: using a System.ComponentModel.TypeConverter | |||
: and then encoded with base64 encoding. | |||
--> | |||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | |||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> | |||
<xsd:element name="root" msdata:IsDataSet="true"> | |||
<xsd:complexType> | |||
<xsd:choice maxOccurs="unbounded"> | |||
<xsd:element name="metadata"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" use="required" type="xsd:string" /> | |||
<xsd:attribute name="type" type="xsd:string" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="assembly"> | |||
<xsd:complexType> | |||
<xsd:attribute name="alias" type="xsd:string" /> | |||
<xsd:attribute name="name" type="xsd:string" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="data"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> | |||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="resheader"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:choice> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:schema> | |||
<resheader name="resmimetype"> | |||
<value>text/microsoft-resx</value> | |||
</resheader> | |||
<resheader name="version"> | |||
<value>2.0</value> | |||
</resheader> | |||
<resheader name="reader"> | |||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<resheader name="writer"> | |||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> | |||
<data name="ss128" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>assets\ss128.pdn;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</data> | |||
<data name="ss32" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>assets\ss32.pdn;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</data> | |||
<data name="ss32Fill" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>assets\ss32fill.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | |||
</data> | |||
<data name="ss32In" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>assets\ss32in.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | |||
</data> | |||
<data name="ss32Out" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>assets\ss32out.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | |||
</data> | |||
<data name="ss32Outline" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>assets\ss32outline.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | |||
</data> | |||
<data name="ssw128" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>assets\ssw128.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | |||
</data> | |||
</root> |
@@ -0,0 +1,70 @@ | |||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> | |||
<PropertyGroup> | |||
<OutputType>Exe</OutputType> | |||
<TargetFramework>netcoreapp3.1</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> | |||
<ApplicationIcon>Assets\shadowsocks.ico</ApplicationIcon> | |||
<NoWin32Manifest>true</NoWin32Manifest> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<PackageReference Include="MaterialDesignThemes" Version="3.2.0" /> | |||
<PackageReference Include="OxyPlot.Wpf" Version="2.0.0" /> | |||
<PackageReference Include="ReactiveUI.Events.WPF" Version="12.1.1" /> | |||
<PackageReference Include="ReactiveUI.Fody" Version="12.1.1" /> | |||
<PackageReference Include="ReactiveUI.Validation" Version="1.8.6" /> | |||
<PackageReference Include="ReactiveUI.WPF" Version="12.1.1" /> | |||
<PackageReference Include="WPFLocalizeExtension" Version="3.8.0" /> | |||
<PackageReference Include="ZXing.Net" Version="0.16.6" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\Shadowsocks\Shadowsocks.csproj" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Resource Include="Assets\ss128.pdn" /> | |||
<Resource Include="Assets\ss32.pdn" /> | |||
<Resource Include="Assets\ss32Fill.png" /> | |||
<Resource Include="Assets\ss32In.png" /> | |||
<Resource Include="Assets\ss32Out.png" /> | |||
<Resource Include="Assets\ss32Outline.png" /> | |||
<Resource Include="Assets\ssw128.png" /> | |||
<Resource Include="Assets\shadowsocks.ico" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Compile Update="Localization\Strings.Designer.cs"> | |||
<DesignTime>True</DesignTime> | |||
<AutoGen>True</AutoGen> | |||
<DependentUpon>Strings.resx</DependentUpon> | |||
</Compile> | |||
<Compile Update="Resource.Designer.cs"> | |||
<DesignTime>True</DesignTime> | |||
<AutoGen>True</AutoGen> | |||
<DependentUpon>Resource.resx</DependentUpon> | |||
</Compile> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<EmbeddedResource Update="Localization\Strings.resx"> | |||
<Generator>ResXFileCodeGenerator</Generator> | |||
<LastGenOutput>Strings.Designer.cs</LastGenOutput> | |||
</EmbeddedResource> | |||
<EmbeddedResource Update="Resource.resx"> | |||
<Generator>ResXFileCodeGenerator</Generator> | |||
<LastGenOutput>Resource.Designer.cs</LastGenOutput> | |||
</EmbeddedResource> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Folder Include="Resources\" /> | |||
</ItemGroup> | |||
</Project> |
@@ -0,0 +1,21 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
<PropertyGroup> | |||
<_LastSelectedProfileId>D:\workspaces\repos\shadowsocks-windows\Shadowsocks.WPF\Properties\PublishProfiles\win-x64.pubxml</_LastSelectedProfileId> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<ApplicationDefinition Update="App.xaml"> | |||
<SubType>Designer</SubType> | |||
</ApplicationDefinition> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Compile Update="Views\MainWindow.xaml.cs"> | |||
<SubType>Code</SubType> | |||
</Compile> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Page Update="Views\MainWindow.xaml"> | |||
<SubType>Designer</SubType> | |||
</Page> | |||
</ItemGroup> | |||
</Project> |
@@ -9,7 +9,7 @@ using System.Linq; | |||
using System.Reactive; | |||
using System.Reactive.Linq; | |||
namespace Shadowsocks.ViewModels | |||
namespace Shadowsocks.WPF.ViewModels | |||
{ | |||
public class ForwardProxyViewModel : ReactiveValidationObject | |||
{ |
@@ -7,7 +7,7 @@ using System.Reactive; | |||
using System.Text; | |||
using System.Windows.Input; | |||
namespace Shadowsocks.ViewModels | |||
namespace Shadowsocks.WPF.ViewModels | |||
{ | |||
public class HotkeysViewModel : ReactiveObject | |||
{ |
@@ -0,0 +1,14 @@ | |||
using ReactiveUI; | |||
using Shadowsocks.Controller.Service; | |||
using System; | |||
namespace Shadowsocks.WPF.ViewModels | |||
{ | |||
public class MainWindowViewModel : ReactiveObject | |||
{ | |||
public MainWindowViewModel() | |||
{ | |||
} | |||
} | |||
} |
@@ -15,7 +15,7 @@ using System.Reactive.Linq; | |||
using System.Text; | |||
using System.Windows; | |||
namespace Shadowsocks.ViewModels | |||
namespace Shadowsocks.WPF.ViewModels | |||
{ | |||
public class OnlineConfigViewModel : ReactiveValidationObject | |||
{ |
@@ -10,7 +10,7 @@ using System.Reactive; | |||
using System.Windows; | |||
using System.Windows.Media.Imaging; | |||
namespace Shadowsocks.ViewModels | |||
namespace Shadowsocks.WPF.ViewModels | |||
{ | |||
public class ServerSharingViewModel : ReactiveObject | |||
{ |
@@ -3,7 +3,7 @@ using ReactiveUI; | |||
using Shadowsocks.Controller; | |||
using System.Reactive; | |||
namespace Shadowsocks.ViewModels | |||
namespace Shadowsocks.WPF.ViewModels | |||
{ | |||
public class VersionUpdatePromptViewModel : ReactiveObject | |||
{ |
@@ -1,12 +1,12 @@ | |||
<reactiveui:ReactiveUserControl | |||
x:Class="Shadowsocks.Views.ForwardProxyView" | |||
x:Class="Shadowsocks.WPF.Views.ForwardProxyView" | |||
x:TypeArguments="vms:ForwardProxyViewModel" | |||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | |||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | |||
xmlns:local="clr-namespace:Shadowsocks.Views" | |||
xmlns:vms="clr-namespace:Shadowsocks.ViewModels" | |||
xmlns:local="clr-namespace:Shadowsocks.WPF.Views" | |||
xmlns:vms="clr-namespace:Shadowsocks.WPF.ViewModels" | |||
xmlns:reactiveui="http://reactiveui.net" | |||
xmlns:lex="http://wpflocalizeextension.codeplex.com" | |||
lex:LocalizeDictionary.DesignCulture="en" |
@@ -1,8 +1,8 @@ | |||
using ReactiveUI; | |||
using Shadowsocks.ViewModels; | |||
using Shadowsocks.WPF.ViewModels; | |||
using System.Reactive.Disposables; | |||
namespace Shadowsocks.Views | |||
namespace Shadowsocks.WPF.Views | |||
{ | |||
/// <summary> | |||
/// Interaction logic for ForwardProxyView.xaml |
@@ -1,12 +1,12 @@ | |||
<reactiveui:ReactiveUserControl | |||
x:Class="Shadowsocks.Views.HotkeysView" | |||
x:Class="Shadowsocks.WPF.Views.HotkeysView" | |||
x:TypeArguments="vms:HotkeysViewModel" | |||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | |||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | |||
xmlns:local="clr-namespace:Shadowsocks.Views" | |||
xmlns:vms="clr-namespace:Shadowsocks.ViewModels" | |||
xmlns:local="clr-namespace:Shadowsocks.WPF.Views" | |||
xmlns:vms="clr-namespace:Shadowsocks.WPF.ViewModels" | |||
xmlns:reactiveui="http://reactiveui.net" | |||
xmlns:lex="http://wpflocalizeextension.codeplex.com" | |||
lex:LocalizeDictionary.DesignCulture="en" |
@@ -1,5 +1,5 @@ | |||
using ReactiveUI; | |||
using Shadowsocks.ViewModels; | |||
using Shadowsocks.WPF.ViewModels; | |||
using System; | |||
using System.Reactive.Disposables; | |||
using System.Windows; | |||
@@ -11,7 +11,7 @@ using System.Windows.Media; | |||
using System.Windows.Media.Imaging; | |||
using System.Windows.Navigation; | |||
namespace Shadowsocks.Views | |||
namespace Shadowsocks.WPF.Views | |||
{ | |||
/// <summary> | |||
/// Interaction logic for HotkeysView.xaml |
@@ -0,0 +1,21 @@ | |||
<reactiveui:ReactiveWindow x:Class="Shadowsocks.WPF.Views.MainWindow" | |||
xmlns:reactiveui="http://reactiveui.net" | |||
xmlns:vm="clr-namespace:Shadowsocks.WPF.ViewModels" | |||
x:TypeArguments="vm:MainWindowViewModel" | |||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | |||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | |||
xmlns:local="clr-namespace:Shadowsocks.WPF" | |||
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes" | |||
mc:Ignorable="d" | |||
Title="Shadowsocks" Width="800" Height="600" | |||
TextElement.Foreground="{DynamicResource MaterialDesignBody}" | |||
TextElement.FontWeight="Regular" | |||
TextElement.FontSize="13" | |||
TextOptions.TextFormattingMode="Ideal" | |||
TextOptions.TextRenderingMode="Auto" | |||
Background="{DynamicResource MaterialDesignPaper}" | |||
FontFamily="{DynamicResource MaterialDesignFont}"> | |||
</reactiveui:ReactiveWindow> |
@@ -0,0 +1,17 @@ | |||
using ReactiveUI; | |||
using Shadowsocks.WPF.ViewModels; | |||
namespace Shadowsocks.WPF.Views | |||
{ | |||
/// <summary> | |||
/// Interaction logic for MainWindow.xaml | |||
/// </summary> | |||
public partial class MainWindow : ReactiveWindow<MainWindowViewModel> | |||
{ | |||
public MainWindow() | |||
{ | |||
InitializeComponent(); | |||
} | |||
} | |||
} |
@@ -1,12 +1,12 @@ | |||
<reactiveui:ReactiveUserControl | |||
x:Class="Shadowsocks.Views.OnlineConfigView" | |||
x:Class="Shadowsocks.WPF.Views.OnlineConfigView" | |||
x:TypeArguments="vms:OnlineConfigViewModel" | |||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | |||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | |||
xmlns:local="clr-namespace:Shadowsocks.Views" | |||
xmlns:vms="clr-namespace:Shadowsocks.ViewModels" | |||
xmlns:local="clr-namespace:Shadowsocks.WPF.Views" | |||
xmlns:vms="clr-namespace:Shadowsocks.WPF.ViewModels" | |||
xmlns:reactiveui="http://reactiveui.net" | |||
xmlns:lex="http://wpflocalizeextension.codeplex.com" | |||
lex:LocalizeDictionary.DesignCulture="en" |
@@ -1,8 +1,8 @@ | |||
using ReactiveUI; | |||
using Shadowsocks.ViewModels; | |||
using Shadowsocks.WPF.ViewModels; | |||
using System.Reactive.Disposables; | |||
namespace Shadowsocks.Views | |||
namespace Shadowsocks.WPF.Views | |||
{ | |||
/// <summary> | |||
/// Interaction logic for OnlineConfigView.xaml |
@@ -1,12 +1,12 @@ | |||
<reactiveui:ReactiveUserControl | |||
x:Class="Shadowsocks.Views.ServerSharingView" | |||
x:Class="Shadowsocks.WPF.Views.ServerSharingView" | |||
x:TypeArguments="vms:ServerSharingViewModel" | |||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | |||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | |||
xmlns:local="clr-namespace:Shadowsocks.Views" | |||
xmlns:vms="clr-namespace:Shadowsocks.ViewModels" | |||
xmlns:local="clr-namespace:Shadowsocks.WPF.Views" | |||
xmlns:vms="clr-namespace:Shadowsocks.WPF.ViewModels" | |||
xmlns:reactiveui="http://reactiveui.net" | |||
xmlns:lex="http://wpflocalizeextension.codeplex.com" | |||
lex:LocalizeDictionary.DesignCulture="en" |
@@ -1,9 +1,9 @@ | |||
using ReactiveUI; | |||
using Shadowsocks.ViewModels; | |||
using Shadowsocks.WPF.ViewModels; | |||
using System.Reactive.Disposables; | |||
using System.Windows.Input; | |||
namespace Shadowsocks.Views | |||
namespace Shadowsocks.WPF.Views | |||
{ | |||
/// <summary> | |||
/// Interaction logic for ServerSharingView.xaml |
@@ -1,12 +1,12 @@ | |||
<reactiveui:ReactiveUserControl | |||
x:Class="Shadowsocks.Views.VersionUpdatePromptView" | |||
x:Class="Shadowsocks.WPF.Views.VersionUpdatePromptView" | |||
x:TypeArguments="vms:VersionUpdatePromptViewModel" | |||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | |||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | |||
xmlns:local="clr-namespace:Shadowsocks.Views" | |||
xmlns:vms="clr-namespace:Shadowsocks.ViewModels" | |||
xmlns:local="clr-namespace:Shadowsocks.WPF.Views" | |||
xmlns:vms="clr-namespace:Shadowsocks.WPF.ViewModels" | |||
xmlns:reactiveui="http://reactiveui.net" | |||
xmlns:mdxam="clr-namespace:MdXaml;assembly=MdXaml" | |||
xmlns:lex="http://wpflocalizeextension.codeplex.com" |
@@ -1,9 +1,9 @@ | |||
using Newtonsoft.Json.Linq; | |||
using ReactiveUI; | |||
using Shadowsocks.ViewModels; | |||
using Shadowsocks.WPF.ViewModels; | |||
using System.Reactive.Disposables; | |||
namespace Shadowsocks.Views | |||
namespace Shadowsocks.WPF.Views | |||
{ | |||
/// <summary> | |||
/// Interaction logic for VersionUpdatePromptView.xaml |
@@ -0,0 +1,13 @@ | |||
<?xml version="1.0" encoding="utf-8" ?> | |||
<!-- Warning: Configuration may reset after shadowsocks upgrade. --> | |||
<!-- If you messed it up, delete this file and Shadowsocks will create a new one. --> | |||
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | |||
<targets> | |||
<!-- This line is managed by Shadowsocks. Do not modify it unless you know what you are doing.--> | |||
<target name="file" xsi:type="File" fileName="ss_win_temp\shadowsocks.log" writeBom="false" encoding="utf-8"/> | |||
</targets> | |||
<rules> | |||
<!-- This line is managed by Shadowsocks. Do not modify it unless you know what you are doing. --> | |||
<logger name="*" minlevel="Info" writeTo="file"/> | |||
</rules> | |||
</nlog> |
@@ -1,8 +1,8 @@ | |||
listen-address __PRIVOXY_BIND_IP__:__PRIVOXY_BIND_PORT__ | |||
toggle 0 | |||
logfile ss_privoxy.log | |||
show-on-task-bar 0 | |||
activity-animation 0 | |||
forward-socks5 / __SOCKS_HOST__:__SOCKS_PORT__ . | |||
max-client-connections 2048 | |||
hide-console | |||
listen-address __PRIVOXY_BIND_IP__:__PRIVOXY_BIND_PORT__ | |||
toggle 0 | |||
logfile ss_privoxy.log | |||
show-on-task-bar 0 | |||
activity-animation 0 | |||
forward-socks5 / __SOCKS_HOST__:__SOCKS_PORT__ . | |||
max-client-connections 2048 | |||
hide-console |
@@ -1,2 +1,2 @@ | |||
! Put user rules line by line in this file. | |||
! See https://adblockplus.org/en/filter-cheatsheet | |||
! Put user rules line by line in this file. | |||
! See https://adblockplus.org/en/filter-cheatsheet |
@@ -0,0 +1,153 @@ | |||
//------------------------------------------------------------------------------ | |||
// <auto-generated> | |||
// 此代码由工具生成。 | |||
// 运行时版本:4.0.30319.42000 | |||
// | |||
// 对此文件的更改可能会导致不正确的行为,并且如果 | |||
// 重新生成代码,这些更改将会丢失。 | |||
// </auto-generated> | |||
//------------------------------------------------------------------------------ | |||
namespace Shadowsocks { | |||
using System; | |||
/// <summary> | |||
/// 一个强类型的资源类,用于查找本地化的字符串等。 | |||
/// </summary> | |||
// 此类是由 StronglyTypedResourceBuilder | |||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 | |||
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen | |||
// (以 /str 作为命令选项),或重新生成 VS 项目。 | |||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] | |||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] | |||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] | |||
internal class Resource { | |||
private static global::System.Resources.ResourceManager resourceMan; | |||
private static global::System.Globalization.CultureInfo resourceCulture; | |||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] | |||
internal Resource() { | |||
} | |||
/// <summary> | |||
/// 返回此类使用的缓存的 ResourceManager 实例。 | |||
/// </summary> | |||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] | |||
internal static global::System.Resources.ResourceManager ResourceManager { | |||
get { | |||
if (object.ReferenceEquals(resourceMan, null)) { | |||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Shadowsocks.Resource", typeof(Resource).Assembly); | |||
resourceMan = temp; | |||
} | |||
return resourceMan; | |||
} | |||
} | |||
/// <summary> | |||
/// 重写当前线程的 CurrentUICulture 属性 | |||
/// 重写当前线程的 CurrentUICulture 属性。 | |||
/// </summary> | |||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] | |||
internal static global::System.Globalization.CultureInfo Culture { | |||
get { | |||
return resourceCulture; | |||
} | |||
set { | |||
resourceCulture = value; | |||
} | |||
} | |||
/// <summary> | |||
/// 查找类似 /* eslint-disable */ | |||
///// Was generated by gfwlist2pac in precise mode | |||
///// https://github.com/clowwindy/gfwlist2pac | |||
/// | |||
///// 2019-10-06: More 'javascript' way to interaction with main program | |||
///// 2019-02-08: Updated to support shadowsocks-windows user rules. | |||
/// | |||
///var proxy = __PROXY__; | |||
///var userrules = []; | |||
///var rules = []; | |||
/// | |||
///// convert to abp grammar | |||
///for (var i = 0; i < __RULES__.length; i++) { | |||
/// var s = __RULES__[i]; | |||
/// if (s.substring(0, 2) == "||") s += "^"; | |||
/// rules.push(s); | |||
///} | |||
/// | |||
///for (var i = 0; i < [字符串的其余部分被截断]"; 的本地化字符串。 | |||
/// </summary> | |||
internal static string ABP_JS { | |||
get { | |||
return ResourceManager.GetString("ABP_JS", resourceCulture); | |||
} | |||
} | |||
/// <summary> | |||
/// 查找 System.Byte[] 类型的本地化资源。 | |||
/// </summary> | |||
internal static byte[] DLC_DAT { | |||
get { | |||
object obj = ResourceManager.GetObject("DLC_DAT", resourceCulture); | |||
return ((byte[])(obj)); | |||
} | |||
} | |||
/// <summary> | |||
/// 查找类似 <?xml version="1.0" encoding="utf-8" ?> | |||
///<!-- Warning: Configuration may reset after shadowsocks upgrade. --> | |||
///<!-- If you messed it up, delete this file and Shadowsocks will create a new one. --> | |||
///<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | |||
/// <targets> | |||
/// <!-- This line is managed by Shadowsocks. Do not modify it unless you know what you are doing.--> | |||
/// <target name="file" xsi:type="File" fileName="ss_win_temp\shadowsocks [字符串的其余部分被截断]"; 的本地化字符串。 | |||
/// </summary> | |||
internal static string NLOG_CONFIG { | |||
get { | |||
return ResourceManager.GetString("NLOG_CONFIG", resourceCulture); | |||
} | |||
} | |||
/// <summary> | |||
/// 查找类似 listen-address __PRIVOXY_BIND_IP__:__PRIVOXY_BIND_PORT__ | |||
///toggle 0 | |||
///logfile ss_privoxy.log | |||
///show-on-task-bar 0 | |||
///activity-animation 0 | |||
///forward-socks5 / __SOCKS_HOST__:__SOCKS_PORT__ . | |||
///max-client-connections 2048 | |||
///hide-console | |||
/// 的本地化字符串。 | |||
/// </summary> | |||
internal static string PRIVOXY_CONF { | |||
get { | |||
return ResourceManager.GetString("PRIVOXY_CONF", resourceCulture); | |||
} | |||
} | |||
/// <summary> | |||
/// 查找 System.Byte[] 类型的本地化资源。 | |||
/// </summary> | |||
internal static byte[] PRIVOXY_EXE { | |||
get { | |||
object obj = ResourceManager.GetObject("PRIVOXY_EXE", resourceCulture); | |||
return ((byte[])(obj)); | |||
} | |||
} | |||
/// <summary> | |||
/// 查找类似 ! Put user rules line by line in this file. | |||
///! See https://adblockplus.org/en/filter-cheatsheet | |||
/// 的本地化字符串。 | |||
/// </summary> | |||
internal static string USER_RULE { | |||
get { | |||
return ResourceManager.GetString("USER_RULE", resourceCulture); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,139 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<root> | |||
<!-- | |||
Microsoft ResX Schema | |||
Version 2.0 | |||
The primary goals of this format is to allow a simple XML format | |||
that is mostly human readable. The generation and parsing of the | |||
various data types are done through the TypeConverter classes | |||
associated with the data types. | |||
Example: | |||
... ado.net/XML headers & schema ... | |||
<resheader name="resmimetype">text/microsoft-resx</resheader> | |||
<resheader name="version">2.0</resheader> | |||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | |||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | |||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> | |||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | |||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | |||
<value>[base64 mime encoded serialized .NET Framework object]</value> | |||
</data> | |||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | |||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> | |||
<comment>This is a comment</comment> | |||
</data> | |||
There are any number of "resheader" rows that contain simple | |||
name/value pairs. | |||
Each data row contains a name, and value. The row also contains a | |||
type or mimetype. Type corresponds to a .NET class that support | |||
text/value conversion through the TypeConverter architecture. | |||
Classes that don't support this are serialized and stored with the | |||
mimetype set. | |||
The mimetype is used for serialized objects, and tells the | |||
ResXResourceReader how to depersist the object. This is currently not | |||
extensible. For a given mimetype the value must be set accordingly: | |||
Note - application/x-microsoft.net.object.binary.base64 is the format | |||
that the ResXResourceWriter will generate, however the reader can | |||
read any of the formats listed below. | |||
mimetype: application/x-microsoft.net.object.binary.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.soap.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.bytearray.base64 | |||
value : The object must be serialized into a byte array | |||
: using a System.ComponentModel.TypeConverter | |||
: and then encoded with base64 encoding. | |||
--> | |||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | |||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> | |||
<xsd:element name="root" msdata:IsDataSet="true"> | |||
<xsd:complexType> | |||
<xsd:choice maxOccurs="unbounded"> | |||
<xsd:element name="metadata"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" use="required" type="xsd:string" /> | |||
<xsd:attribute name="type" type="xsd:string" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="assembly"> | |||
<xsd:complexType> | |||
<xsd:attribute name="alias" type="xsd:string" /> | |||
<xsd:attribute name="name" type="xsd:string" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="data"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> | |||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="resheader"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:choice> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:schema> | |||
<resheader name="resmimetype"> | |||
<value>text/microsoft-resx</value> | |||
</resheader> | |||
<resheader name="version"> | |||
<value>2.0</value> | |||
</resheader> | |||
<resheader name="reader"> | |||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<resheader name="writer"> | |||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> | |||
<data name="ABP_JS" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>assets\abp.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;gb2312</value> | |||
</data> | |||
<data name="DLC_DAT" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>assets\dlc.dat;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</data> | |||
<data name="NLOG_CONFIG" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>assets\nlog.config;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;gb2312</value> | |||
</data> | |||
<data name="PRIVOXY_CONF" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>assets\privoxy_conf.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;gb2312</value> | |||
</data> | |||
<data name="PRIVOXY_EXE" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>assets\privoxy.exe.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</data> | |||
<data name="USER_RULE" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>assets\user-rule.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value> | |||
</data> | |||
</root> |
@@ -0,0 +1,31 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
<PropertyGroup> | |||
<TargetFramework>netstandard2.1</TargetFramework> | |||
<Authors>clowwindy & community 2020</Authors> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<PackageReference Include="CommandLineParser" Version="2.8.0" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\Shadowsocks.Crypto\Shadowsocks.Crypto.csproj" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Compile Update="Resource.Designer.cs"> | |||
<DesignTime>True</DesignTime> | |||
<AutoGen>True</AutoGen> | |||
<DependentUpon>Resource.resx</DependentUpon> | |||
</Compile> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<EmbeddedResource Update="Resource.resx"> | |||
<Generator>ResXFileCodeGenerator</Generator> | |||
<LastGenOutput>Resource.Designer.cs</LastGenOutput> | |||
</EmbeddedResource> | |||
</ItemGroup> | |||
</Project> |
@@ -1,13 +0,0 @@ | |||
<?xml version="1.0" encoding="utf-8" ?> | |||
<!-- Warning: Configuration may reset after shadowsocks upgrade. --> | |||
<!-- If you messed it up, delete this file and Shadowsocks will create a new one. --> | |||
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | |||
<targets> | |||
<!-- This line is managed by Shadowsocks. Do not modify it unless you know what you are doing.--> | |||
<target name="file" xsi:type="File" fileName="ss_win_temp\shadowsocks.log" writeBom="false" encoding="utf-8"/> | |||
</targets> | |||
<rules> | |||
<!-- This line is managed by Shadowsocks. Do not modify it unless you know what you are doing. --> | |||
<logger name="*" minlevel="Info" writeTo="file"/> | |||
</rules> | |||
</nlog> |
@@ -1,6 +0,0 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> | |||
<Caseless StringComparison="Ordinal" /> | |||
<Costura /> | |||
<ReactiveUI /> | |||
</Weavers> |
@@ -1,113 +0,0 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> | |||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> | |||
<xs:element name="Weavers"> | |||
<xs:complexType> | |||
<xs:all> | |||
<xs:element name="ReactiveUI" minOccurs="0" maxOccurs="1" type="xs:anyType" /> | |||
<xs:element name="Costura" minOccurs="0" maxOccurs="1"> | |||
<xs:complexType> | |||
<xs:all> | |||
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeAssemblies" type="xs:string"> | |||
<xs:annotation> | |||
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation> | |||
</xs:annotation> | |||
</xs:element> | |||
<xs:element minOccurs="0" maxOccurs="1" name="IncludeAssemblies" type="xs:string"> | |||
<xs:annotation> | |||
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation> | |||
</xs:annotation> | |||
</xs:element> | |||
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged32Assemblies" type="xs:string"> | |||
<xs:annotation> | |||
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with line breaks.</xs:documentation> | |||
</xs:annotation> | |||
</xs:element> | |||
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged64Assemblies" type="xs:string"> | |||
<xs:annotation> | |||
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with line breaks.</xs:documentation> | |||
</xs:annotation> | |||
</xs:element> | |||
<xs:element minOccurs="0" maxOccurs="1" name="PreloadOrder" type="xs:string"> | |||
<xs:annotation> | |||
<xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation> | |||
</xs:annotation> | |||
</xs:element> | |||
</xs:all> | |||
<xs:attribute name="CreateTemporaryAssemblies" type="xs:boolean"> | |||
<xs:annotation> | |||
<xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation> | |||
</xs:annotation> | |||
</xs:attribute> | |||
<xs:attribute name="IncludeDebugSymbols" type="xs:boolean"> | |||
<xs:annotation> | |||
<xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation> | |||
</xs:annotation> | |||
</xs:attribute> | |||
<xs:attribute name="DisableCompression" type="xs:boolean"> | |||
<xs:annotation> | |||
<xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation> | |||
</xs:annotation> | |||
</xs:attribute> | |||
<xs:attribute name="DisableCleanup" type="xs:boolean"> | |||
<xs:annotation> | |||
<xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation> | |||
</xs:annotation> | |||
</xs:attribute> | |||
<xs:attribute name="LoadAtModuleInit" type="xs:boolean"> | |||
<xs:annotation> | |||
<xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation> | |||
</xs:annotation> | |||
</xs:attribute> | |||
<xs:attribute name="IgnoreSatelliteAssemblies" type="xs:boolean"> | |||
<xs:annotation> | |||
<xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation> | |||
</xs:annotation> | |||
</xs:attribute> | |||
<xs:attribute name="ExcludeAssemblies" type="xs:string"> | |||
<xs:annotation> | |||
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation> | |||
</xs:annotation> | |||
</xs:attribute> | |||
<xs:attribute name="IncludeAssemblies" type="xs:string"> | |||
<xs:annotation> | |||
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation> | |||
</xs:annotation> | |||
</xs:attribute> | |||
<xs:attribute name="Unmanaged32Assemblies" type="xs:string"> | |||
<xs:annotation> | |||
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with |.</xs:documentation> | |||
</xs:annotation> | |||
</xs:attribute> | |||
<xs:attribute name="Unmanaged64Assemblies" type="xs:string"> | |||
<xs:annotation> | |||
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with |.</xs:documentation> | |||
</xs:annotation> | |||
</xs:attribute> | |||
<xs:attribute name="PreloadOrder" type="xs:string"> | |||
<xs:annotation> | |||
<xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation> | |||
</xs:annotation> | |||
</xs:attribute> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:element name="Caseless" minOccurs="0" maxOccurs="1" type="xs:anyType" /> | |||
</xs:all> | |||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> | |||
<xs:annotation> | |||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> | |||
</xs:annotation> | |||
</xs:attribute> | |||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> | |||
<xs:annotation> | |||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> | |||
</xs:annotation> | |||
</xs:attribute> | |||
<xs:attribute name="GenerateXsd" type="xs:boolean"> | |||
<xs:annotation> | |||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> | |||
</xs:annotation> | |||
</xs:attribute> | |||
</xs:complexType> | |||
</xs:element> | |||
</xs:schema> |
@@ -1,13 +0,0 @@ | |||
using System.Reflection; | |||
using WPFLocalizeExtension.Extensions; | |||
namespace Shadowsocks.Localization | |||
{ | |||
public static class LocalizationProvider | |||
{ | |||
public static T GetLocalizedValue<T>(string key) | |||
{ | |||
return LocExtension.GetLocalizedValue<T>(Assembly.GetCallingAssembly().GetName().Name + ":Strings:" + key); | |||
} | |||
} | |||
} |
@@ -1,244 +0,0 @@ | |||
//------------------------------------------------------------------------------ | |||
// <auto-generated> | |||
// This code was generated by a tool. | |||
// Runtime Version:4.0.30319.42000 | |||
// | |||
// Changes to this file may cause incorrect behavior and will be lost if | |||
// the code is regenerated. | |||
// </auto-generated> | |||
//------------------------------------------------------------------------------ | |||
namespace Shadowsocks.Properties { | |||
using System; | |||
/// <summary> | |||
/// A strongly-typed resource class, for looking up localized strings, etc. | |||
/// </summary> | |||
// This class was auto-generated by the StronglyTypedResourceBuilder | |||
// class via a tool like ResGen or Visual Studio. | |||
// To add or remove a member, edit your .ResX file then rerun ResGen | |||
// with the /str option, or rebuild your VS project. | |||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] | |||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] | |||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] | |||
public class Resources { | |||
private static global::System.Resources.ResourceManager resourceMan; | |||
private static global::System.Globalization.CultureInfo resourceCulture; | |||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] | |||
internal Resources() { | |||
} | |||
/// <summary> | |||
/// Returns the cached ResourceManager instance used by this class. | |||
/// </summary> | |||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] | |||
public static global::System.Resources.ResourceManager ResourceManager { | |||
get { | |||
if (object.ReferenceEquals(resourceMan, null)) { | |||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Shadowsocks.Properties.Resources", typeof(Resources).Assembly); | |||
resourceMan = temp; | |||
} | |||
return resourceMan; | |||
} | |||
} | |||
/// <summary> | |||
/// Overrides the current thread's CurrentUICulture property for all | |||
/// resource lookups using this strongly typed resource class. | |||
/// </summary> | |||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] | |||
public static global::System.Globalization.CultureInfo Culture { | |||
get { | |||
return resourceCulture; | |||
} | |||
set { | |||
resourceCulture = value; | |||
} | |||
} | |||
/// <summary> | |||
/// Looks up a localized string similar to /* eslint-disable */ | |||
///// Was generated by gfwlist2pac in precise mode | |||
///// https://github.com/clowwindy/gfwlist2pac | |||
/// | |||
///// 2019-10-06: More 'javascript' way to interaction with main program | |||
///// 2019-02-08: Updated to support shadowsocks-windows user rules. | |||
/// | |||
///var proxy = __PROXY__; | |||
///var userrules = []; | |||
///var rules = []; | |||
/// | |||
///// convert to abp grammar | |||
///for (var i = 0; i < __RULES__.length; i++) { | |||
/// var s = __RULES__[i]; | |||
/// if (s.substring(0, 2) == "||") s += "^"; | |||
/// rules.push(s); | |||
///} | |||
/// | |||
///for (var i = 0; i < [rest of string was truncated]";. | |||
/// </summary> | |||
public static string abp_js { | |||
get { | |||
return ResourceManager.GetString("abp_js", resourceCulture); | |||
} | |||
} | |||
/// <summary> | |||
/// Looks up a localized resource of type System.Byte[]. | |||
/// </summary> | |||
public static byte[] dlc_dat { | |||
get { | |||
object obj = ResourceManager.GetObject("dlc_dat", resourceCulture); | |||
return ((byte[])(obj)); | |||
} | |||
} | |||
/// <summary> | |||
/// Looks up a localized string similar to en,ru-RU,zh-CN,zh-TW,ja,ko,fr | |||
///#Restart program to apply translation,,,,,, | |||
///#This is comment line,,,,,, | |||
///#Always keep language name at head of file,,,,,, | |||
///#Language name is output in log,,,,,, | |||
///"#You can find it by search ""Current language is:""",,,,,, | |||
///#Please use UTF-8 with BOM encoding so we can edit it in Excel,,,,,, | |||
///,,,,,, | |||
///Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks | |||
///,,,,,, | |||
///#Menu,,,,,, | |||
///,,,,,, | |||
///System Proxy,Системный прокси-сервер,系统代理,系統代理,システムプロキシ,시스템 프록시,P [rest of string was truncated]";. | |||
/// </summary> | |||
public static string i18n_csv { | |||
get { | |||
return ResourceManager.GetString("i18n_csv", resourceCulture); | |||
} | |||
} | |||
/// <summary> | |||
/// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> | |||
///<!-- Warning: Configuration may reset after shadowsocks upgrade. --> | |||
///<!-- If you messed it up, delete this file and Shadowsocks will create a new one. --> | |||
///<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | |||
/// <targets> | |||
/// <!-- This line is managed by Shadowsocks. Do not modify it unless you know what you are doing.--> | |||
/// <target name="file" xsi:type="File" fileName="ss_win_temp\shadowsocks.log" writ [rest of string was truncated]";. | |||
/// </summary> | |||
public static string NLog_config { | |||
get { | |||
return ResourceManager.GetString("NLog_config", resourceCulture); | |||
} | |||
} | |||
/// <summary> | |||
/// Looks up a localized string similar to listen-address __PRIVOXY_BIND_IP__:__PRIVOXY_BIND_PORT__ | |||
///toggle 0 | |||
///logfile ss_privoxy.log | |||
///show-on-task-bar 0 | |||
///activity-animation 0 | |||
///forward-socks5 / __SOCKS_HOST__:__SOCKS_PORT__ . | |||
///max-client-connections 2048 | |||
///hide-console | |||
///. | |||
/// </summary> | |||
public static string privoxy_conf { | |||
get { | |||
return ResourceManager.GetString("privoxy_conf", resourceCulture); | |||
} | |||
} | |||
/// <summary> | |||
/// Looks up a localized resource of type System.Byte[]. | |||
/// </summary> | |||
public static byte[] privoxy_exe { | |||
get { | |||
object obj = ResourceManager.GetObject("privoxy_exe", resourceCulture); | |||
return ((byte[])(obj)); | |||
} | |||
} | |||
/// <summary> | |||
/// Looks up a localized resource of type System.Drawing.Bitmap. | |||
/// </summary> | |||
public static System.Drawing.Bitmap ss32Fill { | |||
get { | |||
object obj = ResourceManager.GetObject("ss32Fill", resourceCulture); | |||
return ((System.Drawing.Bitmap)(obj)); | |||
} | |||
} | |||
/// <summary> | |||
/// Looks up a localized resource of type System.Drawing.Bitmap. | |||
/// </summary> | |||
public static System.Drawing.Bitmap ss32In { | |||
get { | |||
object obj = ResourceManager.GetObject("ss32In", resourceCulture); | |||
return ((System.Drawing.Bitmap)(obj)); | |||
} | |||
} | |||
/// <summary> | |||
/// Looks up a localized resource of type System.Drawing.Bitmap. | |||
/// </summary> | |||
public static System.Drawing.Bitmap ss32Out { | |||
get { | |||
object obj = ResourceManager.GetObject("ss32Out", resourceCulture); | |||
return ((System.Drawing.Bitmap)(obj)); | |||
} | |||
} | |||
/// <summary> | |||
/// Looks up a localized resource of type System.Drawing.Bitmap. | |||
/// </summary> | |||
public static System.Drawing.Bitmap ss32Outline { | |||
get { | |||
object obj = ResourceManager.GetObject("ss32Outline", resourceCulture); | |||
return ((System.Drawing.Bitmap)(obj)); | |||
} | |||
} | |||
/// <summary> | |||
/// Looks up a localized resource of type System.Drawing.Bitmap. | |||
/// </summary> | |||
public static System.Drawing.Bitmap ssw128 { | |||
get { | |||
object obj = ResourceManager.GetObject("ssw128", resourceCulture); | |||
return ((System.Drawing.Bitmap)(obj)); | |||
} | |||
} | |||
/// <summary> | |||
/// Looks up a localized resource of type System.Byte[]. | |||
/// </summary> | |||
public static byte[] sysproxy_exe { | |||
get { | |||
object obj = ResourceManager.GetObject("sysproxy_exe", resourceCulture); | |||
return ((byte[])(obj)); | |||
} | |||
} | |||
/// <summary> | |||
/// Looks up a localized resource of type System.Byte[]. | |||
/// </summary> | |||
public static byte[] sysproxy64_exe { | |||
get { | |||
object obj = ResourceManager.GetObject("sysproxy64_exe", resourceCulture); | |||
return ((byte[])(obj)); | |||
} | |||
} | |||
/// <summary> | |||
/// Looks up a localized string similar to ! Put user rules line by line in this file. | |||
///! See https://adblockplus.org/en/filter-cheatsheet | |||
///. | |||
/// </summary> | |||
public static string user_rule { | |||
get { | |||
return ResourceManager.GetString("user_rule", resourceCulture); | |||
} | |||
} | |||
} | |||
} |
@@ -1,86 +0,0 @@ | |||
//------------------------------------------------------------------------------ | |||
// <auto-generated> | |||
// 此代码由工具生成。 | |||
// 运行时版本:4.0.30319.42000 | |||
// | |||
// 对此文件的更改可能会导致不正确的行为,并且如果 | |||
// 重新生成代码,这些更改将会丢失。 | |||
// </auto-generated> | |||
//------------------------------------------------------------------------------ | |||
namespace Shadowsocks.Properties { | |||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] | |||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.4.0.0")] | |||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { | |||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); | |||
public static Settings Default { | |||
get { | |||
return defaultInstance; | |||
} | |||
} | |||
[global::System.Configuration.UserScopedSettingAttribute()] | |||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] | |||
[global::System.Configuration.DefaultSettingValueAttribute("600")] | |||
public int LogViewerWidth { | |||
get { | |||
return ((int)(this["LogViewerWidth"])); | |||
} | |||
set { | |||
this["LogViewerWidth"] = value; | |||
} | |||
} | |||
[global::System.Configuration.UserScopedSettingAttribute()] | |||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] | |||
[global::System.Configuration.DefaultSettingValueAttribute("400")] | |||
public int LogViewerHeight { | |||
get { | |||
return ((int)(this["LogViewerHeight"])); | |||
} | |||
set { | |||
this["LogViewerHeight"] = value; | |||
} | |||
} | |||
[global::System.Configuration.UserScopedSettingAttribute()] | |||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] | |||
[global::System.Configuration.DefaultSettingValueAttribute("True")] | |||
public bool LogViewerMaximized { | |||
get { | |||
return ((bool)(this["LogViewerMaximized"])); | |||
} | |||
set { | |||
this["LogViewerMaximized"] = value; | |||
} | |||
} | |||
[global::System.Configuration.UserScopedSettingAttribute()] | |||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] | |||
[global::System.Configuration.DefaultSettingValueAttribute("0")] | |||
public int LogViewerTop { | |||
get { | |||
return ((int)(this["LogViewerTop"])); | |||
} | |||
set { | |||
this["LogViewerTop"] = value; | |||
} | |||
} | |||
[global::System.Configuration.UserScopedSettingAttribute()] | |||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] | |||
[global::System.Configuration.DefaultSettingValueAttribute("0")] | |||
public int LogViewerLeft { | |||
get { | |||
return ((int)(this["LogViewerLeft"])); | |||
} | |||
set { | |||
this["LogViewerLeft"] = value; | |||
} | |||
} | |||
} | |||
} |
@@ -1,21 +0,0 @@ | |||
<?xml version='1.0' encoding='utf-8'?> | |||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="Shadowsocks.Properties" GeneratedClassName="Settings"> | |||
<Profiles /> | |||
<Settings> | |||
<Setting Name="LogViewerWidth" Type="System.Int32" Scope="User"> | |||
<Value Profile="(Default)">600</Value> | |||
</Setting> | |||
<Setting Name="LogViewerHeight" Type="System.Int32" Scope="User"> | |||
<Value Profile="(Default)">400</Value> | |||
</Setting> | |||
<Setting Name="LogViewerMaximized" Type="System.Boolean" Scope="User"> | |||
<Value Profile="(Default)">True</Value> | |||
</Setting> | |||
<Setting Name="LogViewerTop" Type="System.Int32" Scope="User"> | |||
<Value Profile="(Default)">0</Value> | |||
</Setting> | |||
<Setting Name="LogViewerLeft" Type="System.Int32" Scope="User"> | |||
<Value Profile="(Default)">0</Value> | |||
</Setting> | |||
</Settings> | |||
</SettingsFile> |
@@ -12,6 +12,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ShadowsocksTest", "test\Sha | |||
EndProject | |||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7BD54B24-BBD7-4DD8-99EF-DAEE6684B673}" | |||
ProjectSection(SolutionItems) = preProject | |||
.editorconfig = .editorconfig | |||
.gitignore = .gitignore | |||
appveyor.yml = appveyor.yml | |||
appveyor.yml.obsolete = appveyor.yml.obsolete | |||
@@ -23,6 +24,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution | |||
README.md = README.md | |||
EndProjectSection | |||
EndProject | |||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shadowsocks.Common", "Shadowsocks.Common\Shadowsocks.Common.csproj", "{61AF0616-8E90-46C4-908A-E182A5001AB5}" | |||
EndProject | |||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shadowsocks.Crypto", "Shadowsocks.Crypto\Shadowsocks.Crypto.csproj", "{AD8974F4-EFDC-4EC5-A147-54CD4934D295}" | |||
EndProject | |||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shadowsocks", "Shadowsocks\Shadowsocks.csproj", "{85C2FC93-91F0-454F-AF0A-522FCD20827A}" | |||
EndProject | |||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shadowsocks.WPF", "Shadowsocks.WPF\Shadowsocks.WPF.csproj", "{EA1FB2D4-B5A7-47A6-B097-2F4D29E23010}" | |||
EndProject | |||
Global | |||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||
Debug|Any CPU = Debug|Any CPU | |||
@@ -37,6 +46,22 @@ Global | |||
{45913187-0685-4903-B250-DCEF0479CD86}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{45913187-0685-4903-B250-DCEF0479CD86}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{45913187-0685-4903-B250-DCEF0479CD86}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{61AF0616-8E90-46C4-908A-E182A5001AB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{61AF0616-8E90-46C4-908A-E182A5001AB5}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{61AF0616-8E90-46C4-908A-E182A5001AB5}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{61AF0616-8E90-46C4-908A-E182A5001AB5}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{AD8974F4-EFDC-4EC5-A147-54CD4934D295}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{AD8974F4-EFDC-4EC5-A147-54CD4934D295}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{AD8974F4-EFDC-4EC5-A147-54CD4934D295}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{AD8974F4-EFDC-4EC5-A147-54CD4934D295}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{85C2FC93-91F0-454F-AF0A-522FCD20827A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{85C2FC93-91F0-454F-AF0A-522FCD20827A}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{85C2FC93-91F0-454F-AF0A-522FCD20827A}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{85C2FC93-91F0-454F-AF0A-522FCD20827A}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{EA1FB2D4-B5A7-47A6-B097-2F4D29E23010}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{EA1FB2D4-B5A7-47A6-B097-2F4D29E23010}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{EA1FB2D4-B5A7-47A6-B097-2F4D29E23010}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{EA1FB2D4-B5A7-47A6-B097-2F4D29E23010}.Release|Any CPU.Build.0 = Release|Any CPU | |||
EndGlobalSection | |||
GlobalSection(SolutionProperties) = preSolution | |||
HideSolutionNode = FALSE | |||