diff --git a/Shadowsocks.PAC/GeositeUpdater.cs b/Shadowsocks.PAC/GeositeUpdater.cs index 0a655adc..e1de829a 100644 --- a/Shadowsocks.PAC/GeositeUpdater.cs +++ b/Shadowsocks.PAC/GeositeUpdater.cs @@ -1,17 +1,13 @@ -using NLog; -using Shadowsocks.Properties; -using Shadowsocks.Util; +using Splat; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; -using Newtonsoft.Json; -using Shadowsocks.Model; -using System.Net; using System.Net.Http; using System.Threading.Tasks; using System.Security.Cryptography; +using System.Text.Json; namespace Shadowsocks.PAC { @@ -25,32 +21,31 @@ namespace Shadowsocks.PAC } } - public static class GeositeUpdater + public class GeositeUpdater : IEnableLogger { - private static Logger logger = LogManager.GetCurrentClassLogger(); + public event EventHandler UpdateCompleted; - public static event EventHandler UpdateCompleted; + public event ErrorEventHandler Error; - public static event ErrorEventHandler Error; + private readonly string DATABASE_PATH; - private static readonly string DATABASE_PATH = Utils.GetTempPath("dlc.dat"); + private readonly string GEOSITE_URL = "https://github.com/v2fly/domain-list-community/raw/release/dlc.dat"; + private readonly string GEOSITE_SHA256SUM_URL = "https://github.com/v2fly/domain-list-community/raw/release/dlc.dat.sha256sum"; + private byte[] geositeDB; - private static readonly string GEOSITE_URL = "https://github.com/v2fly/domain-list-community/raw/release/dlc.dat"; - private static readonly string GEOSITE_SHA256SUM_URL = "https://github.com/v2fly/domain-list-community/raw/release/dlc.dat.sha256sum"; - private static byte[] geositeDB; + public readonly Dictionary> Geosites = new Dictionary>(); - public static readonly Dictionary> Geosites = new Dictionary>(); - - static GeositeUpdater() + public GeositeUpdater(string dlcPath) { + DATABASE_PATH = dlcPath; if (File.Exists(DATABASE_PATH) && new FileInfo(DATABASE_PATH).Length > 0) { geositeDB = File.ReadAllBytes(DATABASE_PATH); } else { - geositeDB = Resources.dlc_dat; - File.WriteAllBytes(DATABASE_PATH, Resources.dlc_dat); + geositeDB = Properties.Resources.dlc; + File.WriteAllBytes(DATABASE_PATH, Properties.Resources.dlc); } LoadGeositeList(); } @@ -58,7 +53,7 @@ namespace Shadowsocks.PAC /// /// load new GeoSite data from geositeDB /// - static void LoadGeositeList() + private void LoadGeositeList() { var list = GeositeList.Parser.ParseFrom(geositeDB); foreach (var item in list.Entries) @@ -67,42 +62,41 @@ namespace Shadowsocks.PAC } } - public static void ResetEvent() + public void ResetEvent() { UpdateCompleted = null; Error = null; } - public static async Task UpdatePACFromGeosite() + public async Task UpdatePACFromGeosite(PACSettings pACSettings) { string geositeUrl = GEOSITE_URL; string geositeSha256sumUrl = GEOSITE_SHA256SUM_URL; SHA256 mySHA256 = SHA256.Create(); - var config = Program.MainController.GetCurrentConfiguration(); - bool blacklist = config.geositePreferDirect; - var httpClient = Program.MainController.GetHttpClient(); + bool blacklist = pACSettings.PACDefaultToDirect; + var httpClient = Locator.Current.GetService(); - if (!string.IsNullOrWhiteSpace(config.geositeUrl)) + if (!string.IsNullOrWhiteSpace(pACSettings.CustomGeositeUrl)) { - logger.Info("Found custom Geosite URL in config file"); - geositeUrl = config.geositeUrl; + this.Log().Info("Found custom Geosite URL in config file"); + geositeUrl = pACSettings.CustomGeositeUrl; } - logger.Info($"Checking Geosite from {geositeUrl}"); + this.Log().Info($"Checking Geosite from {geositeUrl}"); try { // download checksum first var geositeSha256sum = await httpClient.GetStringAsync(geositeSha256sumUrl); geositeSha256sum = geositeSha256sum.Substring(0, 64).ToUpper(); - logger.Info($"Got Sha256sum: {geositeSha256sum}"); + this.Log().Info($"Got Sha256sum: {geositeSha256sum}"); // compare downloaded checksum with local geositeDB byte[] localDBHashBytes = mySHA256.ComputeHash(geositeDB); string localDBHash = BitConverter.ToString(localDBHashBytes).Replace("-", String.Empty); - logger.Info($"Local Sha256sum: {localDBHash}"); + this.Log().Info($"Local Sha256sum: {localDBHash}"); // if already latest if (geositeSha256sum == localDBHash) { - logger.Info("Local GeoSite DB is up to date."); + this.Log().Info("Local GeoSite DB is up to date."); return; } @@ -112,15 +106,15 @@ namespace Shadowsocks.PAC // verify sha256sum byte[] downloadedDBHashBytes = mySHA256.ComputeHash(downloadedBytes); string downloadedDBHash = BitConverter.ToString(downloadedDBHashBytes).Replace("-", String.Empty); - logger.Info($"Actual Sha256sum: {downloadedDBHash}"); + this.Log().Info($"Actual Sha256sum: {downloadedDBHash}"); if (geositeSha256sum != downloadedDBHash) { - logger.Info("Sha256sum Verification: FAILED. Downloaded GeoSite DB is corrupted. Aborting the update."); + this.Log().Info("Sha256sum Verification: FAILED. Downloaded GeoSite DB is corrupted. Aborting the update."); throw new Exception("Sha256sum mismatch"); } else { - logger.Info("Sha256sum Verification: PASSED. Applying to local GeoSite DB."); + this.Log().Info("Sha256sum Verification: PASSED. Applying to local GeoSite DB."); } // write to geosite file @@ -130,7 +124,7 @@ namespace Shadowsocks.PAC // update stuff geositeDB = downloadedBytes; LoadGeositeList(); - bool pacFileChanged = MergeAndWritePACFile(config.geositeDirectGroups, config.geositeProxiedGroups, blacklist); + bool pacFileChanged = MergeAndWritePACFile(pACSettings.GeositeDirectGroups, pACSettings.GeositeProxiedGroups, blacklist); UpdateCompleted?.Invoke(null, new GeositeResultEventArgs(pacFileChanged)); } catch (Exception ex) @@ -147,12 +141,12 @@ namespace Shadowsocks.PAC /// A list of geosite groups configured for proxied connection. /// Whether to use blacklist mode. False for whitelist. /// - public static bool MergeAndWritePACFile(List directGroups, List proxiedGroups, bool blacklist) + public bool MergeAndWritePACFile(List directGroups, List proxiedGroups, bool blacklist) { string abpContent = MergePACFile(directGroups, proxiedGroups, blacklist); if (File.Exists(PACDaemon.PAC_FILE)) { - string original = FileManager.NonExclusiveReadAllText(PACDaemon.PAC_FILE, Encoding.UTF8); + string original = File.ReadAllText(PACDaemon.PAC_FILE); if (original == abpContent) { return false; @@ -167,7 +161,7 @@ namespace Shadowsocks.PAC /// /// The group name to check for. /// True if the group exists. False if the group doesn't exist. - public static bool CheckGeositeGroup(string group) => SeparateAttributeFromGroupName(group, out string groupName, out _) && Geosites.ContainsKey(groupName); + public bool CheckGeositeGroup(string group) => SeparateAttributeFromGroupName(group, out string groupName, out _) && Geosites.ContainsKey(groupName); /// /// Separates the attribute (e.g. @cn) from a group name. @@ -177,7 +171,7 @@ namespace Shadowsocks.PAC /// The group name with the attribute stripped. /// The attribute. /// True for success. False for more than one '@'. - private static bool SeparateAttributeFromGroupName(string group, out string groupName, out string attribute) + private bool SeparateAttributeFromGroupName(string group, out string groupName, out string attribute) { var splitGroupAttributeList = group.Split('@'); if (splitGroupAttributeList.Length == 1) // no attribute @@ -199,34 +193,39 @@ namespace Shadowsocks.PAC return true; } - private static string MergePACFile(List directGroups, List proxiedGroups, bool blacklist) + private string MergePACFile(List directGroups, List proxiedGroups, bool blacklist) { string abpContent; if (File.Exists(PACDaemon.USER_ABP_FILE)) { - abpContent = FileManager.NonExclusiveReadAllText(PACDaemon.USER_ABP_FILE, Encoding.UTF8); + abpContent = File.ReadAllText(PACDaemon.USER_ABP_FILE); } else { - abpContent = Resources.abp_js; + abpContent = Properties.Resources.abp; } List userruleLines = new List(); if (File.Exists(PACDaemon.USER_RULE_FILE)) { - string userrulesString = FileManager.NonExclusiveReadAllText(PACDaemon.USER_RULE_FILE, Encoding.UTF8); + string userrulesString = File.ReadAllText(PACDaemon.USER_RULE_FILE); userruleLines = ProcessUserRules(userrulesString); } List ruleLines = GenerateRules(directGroups, proxiedGroups, blacklist); + + var jsonSerializerOptions = new JsonSerializerOptions() + { + WriteIndented = true, + }; abpContent = -$@"var __USERRULES__ = {JsonConvert.SerializeObject(userruleLines, Formatting.Indented)}; -var __RULES__ = {JsonConvert.SerializeObject(ruleLines, Formatting.Indented)}; +$@"var __USERRULES__ = {JsonSerializer.Serialize(userruleLines, jsonSerializerOptions)}; +var __RULES__ = {JsonSerializer.Serialize(ruleLines, jsonSerializerOptions)}; {abpContent}"; return abpContent; } - private static List ProcessUserRules(string content) + private List ProcessUserRules(string content) { List valid_lines = new List(); using (var stringReader = new StringReader(content)) @@ -248,7 +247,7 @@ var __RULES__ = {JsonConvert.SerializeObject(ruleLines, Formatting.Indented)}; /// A list of geosite groups configured for proxied connection. /// Whether to use blacklist mode. False for whitelist. /// A list of rule lines. - private static List GenerateRules(List directGroups, List proxiedGroups, bool blacklist) + private List GenerateRules(List directGroups, List proxiedGroups, bool blacklist) { List ruleLines; if (blacklist) // blocking + exception rules @@ -272,7 +271,7 @@ var __RULES__ = {JsonConvert.SerializeObject(ruleLines, Formatting.Indented)}; /// /// A list of source groups. /// A list of rule lines. - private static List GenerateBlockingRules(List groups) + private List GenerateBlockingRules(List groups) { List ruleLines = new List(); foreach (var group in groups) @@ -337,7 +336,7 @@ var __RULES__ = {JsonConvert.SerializeObject(ruleLines, Formatting.Indented)}; /// /// A list of source groups. /// A list of rule lines. - private static List GenerateExceptionRules(List groups) + private List GenerateExceptionRules(List groups) => GenerateBlockingRules(groups) .Select(r => $"@@{r}") // convert blocking rules to exception rules .ToList(); diff --git a/Shadowsocks.PAC/PACDaemon.cs b/Shadowsocks.PAC/PACDaemon.cs index 1189e469..40a7b7dc 100644 --- a/Shadowsocks.PAC/PACDaemon.cs +++ b/Shadowsocks.PAC/PACDaemon.cs @@ -1,11 +1,6 @@ -using NLog; -using Shadowsocks.Model; -using Shadowsocks.Properties; -using Shadowsocks.Util; +using Splat; using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; using System.Threading.Tasks; @@ -15,14 +10,11 @@ namespace Shadowsocks.PAC /// /// Processing the PAC file content /// - public class PACDaemon + public class PACDaemon : IEnableLogger { - private static Logger logger = LogManager.GetCurrentClassLogger(); - public const string PAC_FILE = "pac.txt"; public const string USER_RULE_FILE = "user-rule.txt"; public const string USER_ABP_FILE = "abp.txt"; - private Configuration config; FileSystemWatcher PACFileWatcher; FileSystemWatcher UserRuleFileWatcher; @@ -30,14 +22,17 @@ namespace Shadowsocks.PAC public event EventHandler PACFileChanged; public event EventHandler UserRuleFileChanged; - public PACDaemon(Configuration config) + private PACSettings _PACSettings; + private GeositeUpdater _geositeUpdater; + + public PACDaemon(PACSettings pACSettings, string workingDirectory, string dlcPath) { - this.config = config; + _PACSettings = pACSettings; + _geositeUpdater = new GeositeUpdater(dlcPath); TouchPACFile(); TouchUserRuleFile(); - - this.WatchPacFile(); - this.WatchUserRuleFile(); + WatchPacFile(workingDirectory); + WatchUserRuleFile(workingDirectory); } @@ -45,7 +40,7 @@ namespace Shadowsocks.PAC { if (!File.Exists(PAC_FILE)) { - GeositeUpdater.MergeAndWritePACFile(config.geositeDirectGroups, config.geositeProxiedGroups, config.geositePreferDirect); + _geositeUpdater.MergeAndWritePACFile(_PACSettings.GeositeDirectGroups, _PACSettings.GeositeProxiedGroups, _PACSettings.PACDefaultToDirect); } return PAC_FILE; } @@ -54,7 +49,7 @@ namespace Shadowsocks.PAC { if (!File.Exists(USER_RULE_FILE)) { - File.WriteAllText(USER_RULE_FILE, Resources.user_rule); + File.WriteAllText(USER_RULE_FILE, Properties.Resources.user_rule); } return USER_RULE_FILE; } @@ -63,16 +58,16 @@ namespace Shadowsocks.PAC { if (!File.Exists(PAC_FILE)) { - GeositeUpdater.MergeAndWritePACFile(config.geositeDirectGroups, config.geositeProxiedGroups, config.geositePreferDirect); + _geositeUpdater.MergeAndWritePACFile(_PACSettings.GeositeDirectGroups, _PACSettings.GeositeProxiedGroups, _PACSettings.PACDefaultToDirect); } return File.ReadAllText(PAC_FILE, Encoding.UTF8); } - private void WatchPacFile() + private void WatchPacFile(string workingDirectory) { PACFileWatcher?.Dispose(); - PACFileWatcher = new FileSystemWatcher(Program.WorkingDirectory); + PACFileWatcher = new FileSystemWatcher(workingDirectory); PACFileWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; PACFileWatcher.Filter = PAC_FILE; PACFileWatcher.Changed += PACFileWatcher_Changed; @@ -82,10 +77,10 @@ namespace Shadowsocks.PAC PACFileWatcher.EnableRaisingEvents = true; } - private void WatchUserRuleFile() + private void WatchUserRuleFile(string workingDirectory) { UserRuleFileWatcher?.Dispose(); - UserRuleFileWatcher = new FileSystemWatcher(Program.WorkingDirectory); + UserRuleFileWatcher = new FileSystemWatcher(workingDirectory); UserRuleFileWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; UserRuleFileWatcher.Filter = USER_RULE_FILE; UserRuleFileWatcher.Changed += UserRuleFileWatcher_Changed; @@ -103,7 +98,7 @@ namespace Shadowsocks.PAC { if (PACFileChanged != null) { - logger.Info($"Detected: PAC file '{e.Name}' was {e.ChangeType.ToString().ToLower()}."); + this.Log().Info($"Detected: PAC file '{e.Name}' was {e.ChangeType.ToString().ToLower()}."); Task.Factory.StartNew(() => { ((FileSystemWatcher)sender).EnableRaisingEvents = false; @@ -118,7 +113,7 @@ namespace Shadowsocks.PAC { if (UserRuleFileChanged != null) { - logger.Info($"Detected: User Rule file '{e.Name}' was {e.ChangeType.ToString().ToLower()}."); + this.Log().Info($"Detected: User Rule file '{e.Name}' was {e.ChangeType.ToString().ToLower()}."); Task.Factory.StartNew(() => { ((FileSystemWatcher)sender).EnableRaisingEvents = false; diff --git a/Shadowsocks.PAC/PACServer.cs b/Shadowsocks.PAC/PACServer.cs index 4da05095..4e8696d4 100644 --- a/Shadowsocks.PAC/PACServer.cs +++ b/Shadowsocks.PAC/PACServer.cs @@ -1,18 +1,17 @@ +using Shadowsocks.Net; +using Shadowsocks.Utilities; +using Shadowsocks.Net.Crypto; +using Splat; using System; using System.Net; using System.Net.Sockets; using System.Text; -using NLog; -using Shadowsocks.Net; -using Shadowsocks.Utilities; -using Shadowsocks.Net.Crypto; +using System.Reflection; namespace Shadowsocks.PAC { - public class PACServer : StreamService + public class PACServer : StreamService, IEnableLogger { - private static Logger logger = LogManager.GetCurrentClassLogger(); - public const string RESOURCE_NAME = "pac"; private string PacSecret @@ -27,23 +26,23 @@ namespace Shadowsocks.PAC } } private string _cachedPacSecret = ""; + private bool _PACServerEnableSecret; public string PacUrl { get; private set; } = ""; - private Configuration _config; private PACDaemon _pacDaemon; - public PACServer(PACDaemon pacDaemon) + public PACServer(PACDaemon pacDaemon, bool PACServerEnableSecret) { _pacDaemon = pacDaemon; + _PACServerEnableSecret = PACServerEnableSecret; } - public void UpdatePACURL(Configuration config) + public void UpdatePACURL(EndPoint localEndPoint) { - _config = config; - string usedSecret = _config.secureLocalPac ? $"&secret={PacSecret}" : ""; + string usedSecret = _PACServerEnableSecret ? $"&secret={PacSecret}" : ""; string contentHash = GetHash(_pacDaemon.GetPACContent()); - PacUrl = $"http://{config.LocalHost}:{config.localPort}/{RESOURCE_NAME}?hash={contentHash}{usedSecret}"; - logger.Debug("Set PAC URL:" + PacUrl); + PacUrl = $"http://{localEndPoint}/{RESOURCE_NAME}?hash={contentHash}{usedSecret}"; + this.Log().Debug("Setting PAC URL: {PacUrl}"); } private static string GetHash(string content) @@ -81,7 +80,7 @@ namespace Shadowsocks.PAC string request = Encoding.UTF8.GetString(firstPacket, 0, length); string[] lines = request.Split('\r', '\n'); bool hostMatch = false, pathMatch = false, useSocks = false; - bool secretMatch = !_config.secureLocalPac; + bool secretMatch = !_PACServerEnableSecret; if (lines.Length < 2) // need at lease RequestLine + Host { @@ -172,7 +171,7 @@ namespace Shadowsocks.PAC string pacContent = $"var __PROXY__ = '{proxy}';\n" + _pacDaemon.GetPACContent(); string responseHead = $@"HTTP/1.1 200 OK -Server: ShadowsocksWindows/{UpdateChecker.Version} +Server: ShadowsocksPAC/{Assembly.GetExecutingAssembly().GetName().Version} Content-Type: application/x-ns-proxy-autoconfig Content-Length: { Encoding.UTF8.GetBytes(pacContent).Length} Connection: Close @@ -183,7 +182,7 @@ Connection: Close } catch (Exception e) { - logger.LogUsefulException(e); + this.Log().Error(e, ""); socket.Close(); } } @@ -199,11 +198,6 @@ Connection: Close { } } - private string GetPACAddress(IPEndPoint localEndPoint, bool useSocks) - { - return localEndPoint.AddressFamily == AddressFamily.InterNetworkV6 - ? $"{(useSocks ? "SOCKS5" : "PROXY")} [{localEndPoint.Address}]:{_config.localPort};" - : $"{(useSocks ? "SOCKS5" : "PROXY")} {localEndPoint.Address}:{_config.localPort};"; - } + private string GetPACAddress(IPEndPoint localEndPoint, bool useSocks) => $"{(useSocks ? "SOCKS5" : "PROXY")} {localEndPoint};"; } } diff --git a/Shadowsocks.PAC/PACSettings.cs b/Shadowsocks.PAC/PACSettings.cs new file mode 100644 index 00000000..dc974527 --- /dev/null +++ b/Shadowsocks.PAC/PACSettings.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Shadowsocks.PAC +{ + /// + /// Settings used for PAC. + /// + public class PACSettings + { + public PACSettings() + { + PACDefaultToDirect = false; + PACServerEnableSecret = true; + RegeneratePacOnVersionUpdate = true; + CustomPACUrl = ""; + CustomGeositeUrl = ""; + GeositeDirectGroups = new List() + { + "private", + "cn", + "geolocation-!cn@cn", + }; + GeositeProxiedGroups = new List() + { + "geolocation-!cn", + }; + } + + /// + /// Controls whether direct connection is used for + /// hostnames not matched by blocking rules + /// or matched by exception rules. + /// Defaults to false, or whitelist mode, + /// where hostnames matching the above conditions + /// are connected to via proxy. + /// Enable it to use blacklist mode. + /// + public bool PACDefaultToDirect { get; set; } + + /// + /// Controls whether the PAC server uses a secret + /// to protect access to the PAC URL. + /// Defaults to true. + /// + public bool PACServerEnableSecret { get; set; } + + /// + /// Controls whether `pac.txt` should be regenerated + /// when shadowsocks-windows is updated. + /// Defaults to true, so new changes can be applied. + /// Change it to false if you want to manage `pac.txt` + /// yourself. + /// + public bool RegeneratePacOnVersionUpdate { get; set; } + + /// + /// Specifies a custom PAC URL. + /// Leave empty to use local PAC. + /// + public string CustomPACUrl { get; set; } + + /// + /// Specifies a custom Geosite database URL. + /// Leave empty to use the default source. + /// + public string CustomGeositeUrl { get; set; } + + /// + /// A list of Geosite groups + /// that we use direct connection for. + /// + public List GeositeDirectGroups { get; set; } + + /// + /// A list of Geosite groups + /// that we always connect to via proxy. + /// + public List GeositeProxiedGroups { get; set; } + } +} diff --git a/Shadowsocks.PAC/Properties/Resources.Designer.cs b/Shadowsocks.PAC/Properties/Resources.Designer.cs new file mode 100644 index 00000000..bc66146a --- /dev/null +++ b/Shadowsocks.PAC/Properties/Resources.Designer.cs @@ -0,0 +1,112 @@ +//------------------------------------------------------------------------------ +// +// 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. +// +//------------------------------------------------------------------------------ + +namespace Shadowsocks.PAC.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // 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()] + internal 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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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.PAC.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 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 + ///var re = /^(@@)?\|\|.*?[^\^]$/; + ///for (var i = 0; i < __RULES__.length; i++) { + /// var s = __RULES__[i]; + /// if (s.match(re)) s += "^"; + /// rules.push(s); + ///} + /// + /// [rest of string was truncated]";. + /// + internal static string abp { + get { + return ResourceManager.GetString("abp", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] dlc { + get { + object obj = ResourceManager.GetObject("dlc", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized string similar to ! Put user rules line by line in this file. + ///! See https://adblockplus.org/en/filter-cheatsheet + ///. + /// + internal static string user_rule { + get { + return ResourceManager.GetString("user_rule", resourceCulture); + } + } + } +} diff --git a/Shadowsocks.PAC/Properties/Resources.resx b/Shadowsocks.PAC/Properties/Resources.resx new file mode 100644 index 00000000..4b519644 --- /dev/null +++ b/Shadowsocks.PAC/Properties/Resources.resx @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\abp.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + + + ..\Resources\dlc.dat;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\user-rule.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + \ No newline at end of file diff --git a/Shadowsocks.PAC/Shadowsocks.PAC.csproj b/Shadowsocks.PAC/Shadowsocks.PAC.csproj index 9b7805f6..9531d781 100644 --- a/Shadowsocks.PAC/Shadowsocks.PAC.csproj +++ b/Shadowsocks.PAC/Shadowsocks.PAC.csproj @@ -5,8 +5,36 @@ - + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs +