Repository: hiddify/HiddifyN Branch: master Commit: cb0909f13ad6 Files: 179 Total size: 1.5 MB Directory structure: gitextract_b47e1nds/ ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── 01_bug_report.yml │ │ └── 02_feature_request.yml │ └── workflows/ │ ├── ci.yml │ └── release.yml ├── .gitignore ├── LICENSE ├── README.md └── v2rayN/ ├── .gitattributes ├── .gitignore ├── HiddifyRestartN/ │ ├── HiddifyRestartN.csproj │ ├── Program.cs │ └── Properties/ │ └── launchSettings.json ├── HiddifyUpgradeN/ │ ├── HiddifyUpgradeN.csproj │ ├── MainForm.Designer.cs │ ├── MainForm.cs │ ├── MainForm.resx │ ├── Program.cs │ ├── Properties/ │ │ ├── Resources.Designer.cs │ │ ├── Resources.resx │ │ ├── Settings.Designer.cs │ │ └── Settings.settings │ └── app.manifest ├── PacLib/ │ ├── PacHandler.cs │ ├── PacLib.csproj │ ├── Resources/ │ │ └── pac.txt │ ├── Resources.Designer.cs │ └── Resources.resx ├── ProtosLib/ │ ├── ProtosLib.csproj │ ├── Statistics.proto │ └── Tests.cs ├── v2rayN/ │ ├── App.xaml │ ├── App.xaml.cs │ ├── AssemblyInfo.cs │ ├── Base/ │ │ ├── DownloaderHelper.cs │ │ ├── HttpClientHelper.cs │ │ ├── MyDGTextColumn.cs │ │ ├── SqliteHelper.cs │ │ └── StringEx.cs │ ├── Converters/ │ │ ├── DelayColorConverter.cs │ │ ├── LocalizeConverter.cs │ │ ├── MaterialDesignFonts.cs │ │ └── SizeConverter.cs │ ├── FodyWeavers.xml │ ├── Global.cs │ ├── Handler/ │ │ ├── ConfigHandler.cs │ │ ├── CoreConfigHandler.cs │ │ ├── CoreConfigSingbox.cs │ │ ├── CoreConfigV2ray.cs │ │ ├── CoreHandler.cs │ │ ├── DownloadHandle.cs │ │ ├── HotkeyHandler.cs │ │ ├── LazyConfig.cs │ │ ├── MainFormHandler.cs │ │ ├── NoticeHandler.cs │ │ ├── ProfileExHandler.cs │ │ ├── ProxySetting.cs │ │ ├── QRCodeHelper.cs │ │ ├── ShareHandler.cs │ │ ├── SpeedtestHandler.cs │ │ ├── StatisticsHandler.cs │ │ ├── SysProxyHandle.cs │ │ ├── TunHandler.cs │ │ └── UpdateHandle.cs │ ├── Mode/ │ │ ├── BalancerItem.cs │ │ ├── ComboItem.cs │ │ ├── Config.cs │ │ ├── ConfigItems.cs │ │ ├── ConfigOld.cs │ │ ├── CoreInfo.cs │ │ ├── DNSItem.cs │ │ ├── EConfigType.cs │ │ ├── ECoreType.cs │ │ ├── EGlobalHotkey.cs │ │ ├── EMove.cs │ │ ├── EServerColName.cs │ │ ├── ESpeedActionType.cs │ │ ├── ESysProxyType.cs │ │ ├── EViewAction.cs │ │ ├── GitHubRelease.cs │ │ ├── HiddifyEnums.cs │ │ ├── ProfileExItem.cs │ │ ├── ProfileItem.cs │ │ ├── ProfileItemModel.cs │ │ ├── ProxyMode.cs │ │ ├── RoutingItem.cs │ │ ├── RoutingItemModel.cs │ │ ├── RulesItem.cs │ │ ├── RulesItemModel.cs │ │ ├── ServerSpeedItem.cs │ │ ├── ServerStatItem.cs │ │ ├── ServerTestItem.cs │ │ ├── SingboxConfig.cs │ │ ├── SsSIP008.cs │ │ ├── SubItem.cs │ │ ├── SubscriptionInfo.cs │ │ ├── SysproxyConfig.cs │ │ ├── V2rayConfig.cs │ │ ├── V2rayTcpRequest.cs │ │ └── VmessQRCode.cs │ ├── Resx/ │ │ ├── Hiddify.Designer.cs │ │ ├── Hiddify.resx │ │ ├── ResUI.Designer.cs │ │ ├── ResUI.fa-Ir.resx │ │ ├── ResUI.resx │ │ ├── ResUI.ru.resx │ │ └── ResUI.zh-Hans.resx │ ├── Sample/ │ │ ├── SampleClientConfig │ │ ├── SampleHttprequest │ │ ├── SampleHttpresponse │ │ ├── SampleInbound │ │ ├── SingboxSampleClientConfig │ │ ├── custom_routing_black │ │ ├── custom_routing_global │ │ ├── custom_routing_locked │ │ ├── custom_routing_rules │ │ ├── custom_routing_white │ │ ├── dns_singbox_normal │ │ ├── dns_v2ray_normal │ │ ├── tun_singbox │ │ ├── tun_singbox_dns │ │ ├── tun_singbox_inbound │ │ └── tun_singbox_rules │ ├── Tool/ │ │ ├── DeepLinking.cs │ │ ├── FileManager.cs │ │ ├── Job.cs │ │ ├── Logging.cs │ │ ├── QueryableExtension.cs │ │ ├── TestSpeed.cs │ │ ├── UI.cs │ │ └── Utils.cs │ ├── ViewModels/ │ │ ├── AddServer2ViewModel.cs │ │ ├── AddServerViewModel.cs │ │ ├── AnotherCommandImplementation.cs │ │ ├── DNSSettingViewModel.cs │ │ ├── DemoItem.cs │ │ ├── HomeWindowViewModel.cs │ │ ├── MainWindowViewModel.cs │ │ ├── OptionSettingViewModel.cs │ │ ├── RoutingRuleDetailsViewModel.cs │ │ ├── RoutingRuleSettingViewModel.cs │ │ ├── RoutingSettingViewModel.cs │ │ ├── SubEditViewModel.cs │ │ ├── SubSettingViewModel.cs │ │ └── ViewModelBase.cs │ ├── Views/ │ │ ├── AddServer2Window.xaml │ │ ├── AddServer2Window.xaml.cs │ │ ├── AddServerWindow.xaml │ │ ├── AddServerWindow.xaml.cs │ │ ├── DNSSettingWindow.xaml │ │ ├── DNSSettingWindow.xaml.cs │ │ ├── GlobalHotkeySettingWindow.xaml │ │ ├── GlobalHotkeySettingWindow.xaml.cs │ │ ├── HiddifyUI.xaml │ │ ├── HiddifyUI.xaml.cs │ │ ├── MainSubInfoView.xaml │ │ ├── MainSubInfoView.xaml.cs │ │ ├── MainWindow.xaml │ │ ├── MainWindow.xaml.cs │ │ ├── MsgView.xaml │ │ ├── MsgView.xaml.cs │ │ ├── OptionSettingWindow.xaml │ │ ├── OptionSettingWindow.xaml.cs │ │ ├── QrcodeView.xaml │ │ ├── QrcodeView.xaml.cs │ │ ├── RoutingRuleDetailsWindow.xaml │ │ ├── RoutingRuleDetailsWindow.xaml.cs │ │ ├── RoutingRuleSettingWindow.xaml │ │ ├── RoutingRuleSettingWindow.xaml.cs │ │ ├── RoutingSettingWindow.xaml │ │ ├── RoutingSettingWindow.xaml.cs │ │ ├── SubEditWindow.xaml │ │ ├── SubEditWindow.xaml.cs │ │ ├── SubInfoView.xaml │ │ ├── SubInfoView.xaml.cs │ │ ├── SubSettingWindow.xaml │ │ └── SubSettingWindow.xaml.cs │ ├── app.manifest │ └── v2rayN.csproj └── v2rayN.sln ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/ISSUE_TEMPLATE/01_bug_report.yml ================================================ name: Bug 报告 description: 在提出问题前请先自行排除服务器端问题和升级到最新客户端,同时也请通过搜索确认是否有人提出过相同问题。 title: "[Bug]: " labels: ["bug"] body: - type: input id: "expectation" attributes: label: "预期情况" description: "描述你认为应该发生什么" validations: required: true - type: textarea id: "describe-the-bug" attributes: label: "实际情况" description: "描述实际发生了什么" validations: required: true - type: textarea id: "reproduction-method" attributes: label: "复现方法" description: "在BUG出现前执行了哪些操作" placeholder: 标序号 validations: required: true - type: textarea id: "log" attributes: label: "日志信息" description: "位置在软件当前目录下的guiLogs" placeholder: 在日志开始和结束位置粘贴冒号后的内容:``` validations: required: true - type: textarea id: "more" attributes: label: "额外信息" description: "可选" validations: required: false - type: checkboxes id: "latest-version" attributes: label: "我确认已更新至最新版本" description: "否则请更新后尝试" options: - label: 是 required: true - type: checkboxes id: "issues" attributes: label: "我确认已查询历史issues" description: "否则请查询后提出" options: - label: 是 required: true ================================================ FILE: .github/ISSUE_TEMPLATE/02_feature_request.yml ================================================ name: Feature 请求 description: "为这个项目提出一个建议" title: "[Feature request]: " labels: ['enhancement'] body: - type: input id: problem attributes: label: 相关问题 description: "清楚而简洁地描述问题是什么。" placeholder: "当我想要……时,软件不能……" validations: required: true - type: input id: way-to-solve attributes: label: 描述你希望的解决方案 description: "你希望发生什么" validations: required: true - type: input id: instead attributes: label: 描述你所考虑的替代方案 validations: required: false - type: checkboxes id: "issues" attributes: label: "我确认已查询历史issues" description: "否则请查询后提出" options: - label: 是 required: true ================================================ FILE: .github/workflows/ci.yml ================================================ # This workflow uses actions that are not certified by GitHub. # They are provided by a third-party and are governed by # separate terms of service, privacy policy, and support # documentation. # This workflow will build, test, sign and package a WPF or Windows Forms desktop application # built on .NET Core. # To learn how to migrate your existing application to .NET Core, # refer to https://docs.microsoft.com/en-us/dotnet/desktop-wpf/migration/convert-project-from-net-framework # # To configure this workflow: # # 1. Configure environment variables # GitHub sets default environment variables for every workflow run. # Replace the variables relative to your project in the "env" section below. # # 2. Signing # Generate a signing certificate in the Windows Application # Packaging Project or add an existing signing certificate to the project. # Next, use PowerShell to encode the .pfx file using Base64 encoding # by running the following Powershell script to generate the output string: # # $pfx_cert = Get-Content '.\SigningCertificate.pfx' -Encoding Byte # [System.Convert]::ToBase64String($pfx_cert) | Out-File 'SigningCertificate_Encoded.txt' # # Open the output file, SigningCertificate_Encoded.txt, and copy the # string inside. Then, add the string to the repo as a GitHub secret # and name it "Base64_Encoded_Pfx." # For more information on how to configure your signing certificate for # this workflow, refer to https://github.com/microsoft/github-actions-for-desktop-apps#signing # # Finally, add the signing certificate password to the repo as a secret and name it "Pfx_Key". # See "Build the Windows Application Packaging project" below to see how the secret is used. # # For more information on GitHub Actions, refer to https://github.com/features/actions # For a complete CI/CD sample to get started with GitHub Action workflows for Desktop Applications, # refer to https://github.com/microsoft/github-actions-for-desktop-apps name: .NET Core Desktop on: push: branches: [ "master" ] pull_request: branches: [ "master" ] jobs: build: strategy: matrix: include: - configuration: x64 xray: Xray-windows-64.zip - configuration: x86 xray: Xray-windows-32.zip runs-on: windows-latest # For a list of available runner types, refer to # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on steps: - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 0 - name: Download xray run: | curl -L -o ${{ matrix.xray }} https://github.com/hiddify/Hiddify-Xray-core/releases/latest/download/${{ matrix.xray }} dir # Install the .NET Core workload - name: Install .NET Core uses: actions/setup-dotnet@v3 with: dotnet-version: 6.0.x - name: Restore run: | dotnet restore working-directory: v2rayN - name: Build working-directory: v2rayN run: | dotnet build --configuration Release --no-restore - name: Publish win ${{ matrix.configuration }} working-directory: v2rayN run: | dotnet publish v2rayN\v2rayN.csproj --property WarningLevel=0 -c Release -o ../release/win-${{ matrix.configuration }} -r win-${{ matrix.configuration }} -p:PublishSingleFile=true --self-contained false /p:UseAppHost=true /p:PublishReadyToRun=true /p:PublishSingleFileExecutable=HiddifyN.exe # dotnet publish --property WarningLevel=0 -c Release -o ../release/win-x64 -r win-x64 -p:PublishSingleFile=true --self-contained false /p:UseAppHost=true /p:PublishReadyToRun=true - name: add xray run: | mkdir release\win-${{ matrix.configuration }}\bin\Xray dir 7z x "${{ matrix.xray }}" -i!"*.exe" move *xray.exe release\win-${{ matrix.configuration }}\bin\Xray\ # Upload the MSIX package: https://github.com/marketplace/actions/upload-a-build-artifact - name: Upload build win-${{ matrix.configuration }} uses: actions/upload-artifact@v3 with: name: win-${{ matrix.configuration }} path: release/win-${{ matrix.configuration }} retention-days: 5 ================================================ FILE: .github/workflows/release.yml ================================================ name: Release on: push: # Sequence of patterns matched against refs/tags tags: - "v*" jobs: build: strategy: matrix: include: - configuration: x64 xray: Xray-windows-64.zip - configuration: x86 xray: Xray-windows-32.zip runs-on: windows-latest # For a list of available runner types, refer to # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on steps: - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 0 - name: Download xray run: | curl -L -o ${{ matrix.xray }} https://github.com/hiddify/Hiddify-Xray-core/releases/latest/download/${{ matrix.xray }} dir # Install the .NET Core workload - name: Install .NET Core uses: actions/setup-dotnet@v3 with: dotnet-version: 6.0.x - name: Restore run: | dotnet restore working-directory: v2rayN - name: Build working-directory: v2rayN run: | dotnet build --configuration Release --no-restore - name: Publish win ${{ matrix.configuration }} working-directory: v2rayN run: | dotnet publish v2rayN\v2rayN.csproj --property WarningLevel=0 -c Release -o ../release/win-${{ matrix.configuration }} -r win-${{ matrix.configuration }} -p:PublishSingleFile=true --self-contained false /p:UseAppHost=true /p:PublishReadyToRun=true /p:PublishSingleFileExecutable=HiddifyN.exe # dotnet publish --property WarningLevel=0 -c Release -o ../release/win-x64 -r win-x64 -p:PublishSingleFile=true --self-contained false /p:UseAppHost=true /p:PublishReadyToRun=true - name: add xray run: | mkdir release\win-${{ matrix.configuration }}\bin\Xray dir 7z x "${{ matrix.xray }}" -i!"*.exe" move *xray.exe release\win-${{ matrix.configuration }}\bin\Xray\ # Upload the MSIX package: https://github.com/marketplace/actions/upload-a-build-artifact - name: Upload build win-${{ matrix.configuration }} uses: actions/upload-artifact@v3 with: name: win-${{ matrix.configuration }} path: release/win-${{ matrix.configuration }} retention-days: 5 publish: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - name: Load Release URL File from release job uses: actions/download-artifact@v1 with: name: win-x64.zip - name: Load Release URL File from release job uses: actions/download-artifact@v1 with: name: win-x86.zip - name: Upload Release uses: softprops/action-gh-release@v1 with: # tag: ${{ github.ref_name }} tag_name: ${{ github.ref }} release_name: ${{ github.ref }} files: "*.zip" prerelease: false generate_release_notes: true ================================================ FILE: .gitignore ================================================ ################################################################################ # 此 .gitignore 文件已由 Microsoft(R) Visual Studio 自动创建。 ################################################################################ /vs /v2rayN/.vs/ /v2rayN/v2rayN/bin/Debug/app.publish /v2rayN/v2rayN/bin/Debug /v2rayN/v2rayN/bin/Release /v2rayN/v2rayN/obj/ /v2rayN/.vs/v2rayN/DesignTimeBuild /v2rayN/packages .vs/ProjectSettings.json .vs/slnx.sqlite .vs/VSWorkspaceState.json /v2rayN/v2rayUpgrade/bin/Debug /v2rayN/v2rayUpgrade/bin/Release /v2rayN/v2rayUpgrade/obj/ *.user /v2rayN/v2rayN/Properties/* /v2rayN/v2rayN/Properties/ /.vs/v2rayN ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ================================================ FILE: README.md ================================================ # HiddifyN A GUI client for Windows, support [Xray core](https://github.com/XTLS/Xray-core) and [v2fly core](https://github.com/v2fly/v2ray-core) and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores) ![image](https://user-images.githubusercontent.com/114227601/236046684-35a41cbc-9b4f-4dbf-8592-ef0436fbb5b0.png) [![GitHub commit activity](https://img.shields.io/github/commit-activity/m/2dust/v2rayN)](https://github.com/2dust/v2rayN/commits/master) [![CodeFactor](https://www.codefactor.io/repository/github/2dust/v2rayn/badge)](https://www.codefactor.io/repository/github/2dust/v2rayn) [![GitHub Releases](https://img.shields.io/github/downloads/2dust/v2rayN/latest/total?logo=github)](https://github.com/2dust/v2rayN/releases) [![Chat on Telegram](https://img.shields.io/badge/Chat%20on-Telegram-brightgreen.svg)](https://t.me/v2rayn) ### How to use - If you are new to this, please download v2rayN-Core.zip from [releases](https://github.com/2dust/v2rayN/releases) - Otherwise please download v2rayN.zip (you will also need to download v2ray core into the same folder with HiddifyN.exe) - Run HiddifyN.exe ## Requirements - [Microsoft .NET 6.0 Desktop Runtime ](https://download.visualstudio.microsoft.com/download/pr/513d13b7-b456-45af-828b-b7b7981ff462/edf44a743b78f8b54a2cec97ce888346/windowsdesktop-runtime-6.0.15-win-x64.exe) - [Supported cores](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores) ### Telegram - Channel: [Hiddify](https://t.me/hiddify) - Group: [Hiddify Discussion](https://t.me/hiddify_board) ================================================ FILE: v2rayN/.gitattributes ================================================ ############################################################################### # Set default behavior to automatically normalize line endings. ############################################################################### * text=auto ############################################################################### # Set default behavior for command prompt diff. # # This is need for earlier builds of msysgit that does not have it on by # default for csharp files. # Note: This is only used by command line ############################################################################### #*.cs diff=csharp ############################################################################### # Set the merge driver for project and solution files # # Merging from the command prompt will add diff markers to the files if there # are conflicts (Merging from VS is not affected by the settings below, in VS # the diff markers are never inserted). Diff markers may cause the following # file extensions to fail to load in VS. An alternative would be to treat # these files as binary and thus will always conflict and require user # intervention with every merge. To do so, just uncomment the entries below ############################################################################### #*.sln merge=binary #*.csproj merge=binary #*.vbproj merge=binary #*.vcxproj merge=binary #*.vcproj merge=binary #*.dbproj merge=binary #*.fsproj merge=binary #*.lsproj merge=binary #*.wixproj merge=binary #*.modelproj merge=binary #*.sqlproj merge=binary #*.wwaproj merge=binary ############################################################################### # behavior for image files # # image files are treated as binary by default. ############################################################################### #*.jpg binary #*.png binary #*.gif binary ############################################################################### # diff behavior for common document formats # # Convert binary document formats to text before diffing them. This feature # is only available from the command line. Turn it on by uncommenting the # entries below. ############################################################################### #*.doc diff=astextplain #*.DOC diff=astextplain #*.docx diff=astextplain #*.DOCX diff=astextplain #*.dot diff=astextplain #*.DOT diff=astextplain #*.pdf diff=astextplain #*.PDF diff=astextplain #*.rtf diff=astextplain #*.RTF diff=astextplain ================================================ FILE: v2rayN/.gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files *.rsuser *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Mono auto generated files mono_crash.* # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ [Ww][Ii][Nn]32/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ [Oo]ut/ [Ll]og/ [Ll]ogs/ # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # Visual Studio 2017 auto generated files Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUnit *.VisualState.xml TestResult.xml nunit-*.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # Benchmark Results BenchmarkDotNet.Artifacts/ # .NET Core project.lock.json project.fragment.lock.json artifacts/ # ASP.NET Scaffolding ScaffoldingReadMe.txt # StyleCop StyleCopReport.xml # Files built by Visual Studio *_i.c *_p.c *_h.h *.ilk *.meta *.obj *.iobj *.pch *.pdb *.ipdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *_wpftmp.csproj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx *.sap # Visual Studio Trace Files *.e2e # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # AxoCover is a Code Coverage Tool .axoCover/* !.axoCover/settings.json # Coverlet is a free, cross platform Code Coverage Tool coverage*.json coverage*.xml coverage*.info # Visual Studio code coverage results *.coverage *.coveragexml # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # Note: Comment the next line if you want to checkin your web deploy settings, # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to # checkin your Azure Web App publish settings, but sensitive information contained # in these scripts will be unencrypted PublishScripts/ # NuGet Packages *.nupkg # NuGet Symbol Packages *.snupkg # The packages folder can be ignored because of Package Restore **/[Pp]ackages/* # except build/, which is used as an MSBuild target. !**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/[Pp]ackages/repositories.config # NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directories and files AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt *.appx *.appxbundle *.appxupload # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !?*.[Cc]ache/ # Others ClientBin/ ~$* *~ *.dbmdl *.dbproj.schemaview *.jfm *.pfx *.publishsettings orleans.codegen.cs # Including strong name files can present a security risk # (https://github.com/github/gitignore/pull/2483#issue-259490424) #*.snk # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm ServiceFabricBackup/ *.rptproj.bak # SQL Server files *.mdf *.ldf *.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings *.rptproj.rsuser *- [Bb]ackup.rdl *- [Bb]ackup ([0-9]).rdl *- [Bb]ackup ([0-9][0-9]).rdl # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat node_modules/ # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # Paket dependency manager .paket/paket.exe paket-files/ # FAKE - F# Make .fake/ # CodeRush personal settings .cr/personal # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc # Cake - Uncomment if you are using it # tools/** # !tools/packages.config # Tabs Studio *.tss # Telerik's JustMock configuration file *.jmconfig # BizTalk build output *.btp.cs *.btm.cs *.odx.cs *.xsd.cs # OpenCover UI analysis results OpenCover/ # Azure Stream Analytics local run output ASALocalRun/ # MSBuild Binary and Structured Log *.binlog # NVidia Nsight GPU debugger configuration file *.nvuser # MFractors (Xamarin productivity tool) working folder .mfractor/ # Local History for Visual Studio .localhistory/ # BeatPulse healthcheck temp database healthchecksdb # Backup folder for Package Reference Convert tool in Visual Studio 2017 MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ # Fody - auto-generated XML schema FodyWeavers.xsd ================================================ FILE: v2rayN/HiddifyRestartN/HiddifyRestartN.csproj ================================================ Exe net6.0 enable enable ================================================ FILE: v2rayN/HiddifyRestartN/Program.cs ================================================ using System.Diagnostics; // This program is jsut for restarting main program try { // Killing // Get running main program process id int mainProgramProcessID = int.Parse(Environment.GetCommandLineArgs()[1]); // Get process //var mainProcess = Process.GetProcessById(mainProgramProcessID); // Kill process //mainProcess.Kill(); // Running // Main program exe path string mainProgramPath = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "HiddifyN.exe")); // Command to run program string cmd = $"{mainProgramPath}"; // Run again Process.Start(cmd); } catch (Exception err) { Console.Error.WriteLine(err); } ================================================ FILE: v2rayN/HiddifyRestartN/Properties/launchSettings.json ================================================ { "profiles": { "HiddifyRestartN": { "commandName": "Project", "commandLineArgs": "2342 --admin", "workingDirectory": "C:\\Users\\me\\Desktop\\HiddifyDesktopN\\v2rayN\\v2rayN\\bin\\Debug\\net6.0-windows" } } } ================================================ FILE: v2rayN/HiddifyUpgradeN/HiddifyUpgradeN.csproj ================================================  net6.0-windows WinExe true Copyright © 2019-2023 (GPLv3) 1.1.0.0 app.manifest enable HiddifyUpgradeN ================================================ FILE: v2rayN/HiddifyUpgradeN/MainForm.Designer.cs ================================================ namespace v2rayUpgrade { partial class MainForm { /// /// 必需的设计器变量。 /// private System.ComponentModel.IContainer components = null; /// /// 清理所有正在使用的资源。 /// /// 如果应释放托管资源,为 true;否则为 false。 protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows 窗体设计器生成的代码 /// /// 设计器支持所需的方法 - 不要修改 /// 使用代码编辑器修改此方法的内容。 /// private void InitializeComponent() { this.btnClose = new System.Windows.Forms.Button(); this.btnOK = new System.Windows.Forms.Button(); this.label1 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label(); this.SuspendLayout(); // // btnClose // this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.btnClose.Font = new System.Drawing.Font("微软雅黑", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.btnClose.ImeMode = System.Windows.Forms.ImeMode.NoControl; this.btnClose.Location = new System.Drawing.Point(367, 118); this.btnClose.Name = "btnClose"; this.btnClose.Size = new System.Drawing.Size(184, 89); this.btnClose.TabIndex = 1; this.btnClose.Text = "&Exit(退出)"; this.btnClose.UseVisualStyleBackColor = true; this.btnClose.Click += new System.EventHandler(this.btnClose_Click); // // btnOK // this.btnOK.Font = new System.Drawing.Font("微软雅黑", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.btnOK.ImeMode = System.Windows.Forms.ImeMode.NoControl; this.btnOK.Location = new System.Drawing.Point(81, 118); this.btnOK.Name = "btnOK"; this.btnOK.Size = new System.Drawing.Size(184, 89); this.btnOK.TabIndex = 0; this.btnOK.Text = "&Upgrade(升级)"; this.btnOK.UseVisualStyleBackColor = true; this.btnOK.Click += new System.EventHandler(this.btnOK_Click); // // label1 // this.label1.AutoSize = true; this.label1.Font = new System.Drawing.Font("微软雅黑", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.label1.Location = new System.Drawing.Point(79, 64); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(205, 15); this.label1.TabIndex = 8; this.label1.Text = "升级成功后将自动重启v2rayN"; // // label2 // this.label2.AutoSize = true; this.label2.Font = new System.Drawing.Font("微软雅黑", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.label2.Location = new System.Drawing.Point(79, 37); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(471, 15); this.label2.TabIndex = 9; this.label2.Text = "v2rayN will restart automatically after successful upgrade"; // // MainForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(616, 284); this.Controls.Add(this.label2); this.Controls.Add(this.label1); this.Controls.Add(this.btnClose); this.Controls.Add(this.btnOK); this.Name = "MainForm"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "v2rayUpgrade"; this.ResumeLayout(false); this.PerformLayout(); } #endregion private System.Windows.Forms.Button btnClose; private System.Windows.Forms.Button btnOK; private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label2; } } ================================================ FILE: v2rayN/HiddifyUpgradeN/MainForm.cs ================================================ using System; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Text; using System.Web; using System.Windows.Forms; namespace v2rayUpgrade { public partial class MainForm : Form { private readonly string defaultFilename = "v2ray-windows.zip"; private string? fileName; public MainForm(string[] args) { InitializeComponent(); if (args.Length > 0) { fileName = HttpUtility.UrlDecode(string.Join(" ", args)); } else { fileName = defaultFilename; } } private void ShowWarn(string message) { MessageBox.Show(message, "", MessageBoxButtons.OK, MessageBoxIcon.Warning); } private void btnOK_Click(object sender, EventArgs e) { try { Process[] existing = Process.GetProcessesByName("HiddifyN"); foreach (Process p in existing) { string? path = p.MainModule?.FileName; if (path == GetPath("HiddifyN.exe")) { p.Kill(); p.WaitForExit(100); } } } catch (Exception ex) { // Access may be denied without admin right. The user may not be an administrator. ShowWarn("Failed to close v2rayN(关闭v2rayN失败).\n" + "Close it manually, or the upgrade may fail.(请手动关闭正在运行的v2rayN,否则可能升级失败。\n\n" + ex.StackTrace); } if (!File.Exists(fileName)) { if (File.Exists(defaultFilename)) { fileName = defaultFilename; } else { ShowWarn("Upgrade Failed, File Not Exist(升级失败,文件不存在)."); return; } } StringBuilder sb = new(); try { string thisAppOldFile = $"{Application.ExecutablePath}.tmp"; File.Delete(thisAppOldFile); string startKey = "v2rayN/"; using ZipArchive archive = ZipFile.OpenRead(fileName); foreach (ZipArchiveEntry entry in archive.Entries) { try { if (entry.Length == 0) { continue; } string fullName = entry.FullName; if (fullName.StartsWith(startKey)) { fullName = fullName[startKey.Length..]; } if (string.Equals(Application.ExecutablePath, GetPath(fullName), StringComparison.OrdinalIgnoreCase)) { File.Move(Application.ExecutablePath, thisAppOldFile); } string entryOuputPath = GetPath(fullName); Directory.CreateDirectory(Path.GetDirectoryName(entryOuputPath)!); entry.ExtractToFile(entryOuputPath, true); } catch (Exception ex) { sb.Append(ex.StackTrace); } } } catch (Exception ex) { ShowWarn("Upgrade Failed(升级失败)." + ex.StackTrace); return; } if (sb.Length > 0) { ShowWarn("Upgrade Failed,Hold ctrl + c to copy to clipboard.\n" + "(升级失败,按住ctrl+c可以复制到剪贴板)." + sb.ToString()); return; } Process.Start("HiddifyN.exe"); MessageBox.Show("Upgrade successed(升级成功)", "", MessageBoxButtons.OK, MessageBoxIcon.Information); Close(); } private void btnClose_Click(object sender, EventArgs e) { Close(); } public static string GetExePath() { return Application.ExecutablePath; } public static string StartupPath() { return Application.StartupPath; } public static string GetPath(string fileName) { string startupPath = StartupPath(); if (string.IsNullOrEmpty(fileName)) { return startupPath; } return Path.Combine(startupPath, fileName); } } } ================================================ FILE: v2rayN/HiddifyUpgradeN/MainForm.resx ================================================  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 ================================================ FILE: v2rayN/HiddifyUpgradeN/Program.cs ================================================ using System; using System.Windows.Forms; namespace v2rayUpgrade { internal static class Program { /// /// 应用程序的主入口点。 /// [STAThread] private static void Main(string[] args) { Application.EnableVisualStyles(); Application.SetHighDpiMode(HighDpiMode.SystemAware); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainForm(args)); } } } ================================================ FILE: v2rayN/HiddifyUpgradeN/Properties/Resources.Designer.cs ================================================ //------------------------------------------------------------------------------ // // 此代码由工具生成。 // 运行时版本:4.0.30319.42000 // // 对此文件的更改可能会导致不正确的行为,并且如果 // 重新生成代码,这些更改将会丢失。 // //------------------------------------------------------------------------------ namespace v2rayUpgrade.Properties { using System; /// /// 一个强类型的资源类,用于查找本地化的字符串等。 /// // 此类是由 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 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() { } /// /// 返回此类使用的缓存的 ResourceManager 实例。 /// [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("v2rayUpgrade.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } /// /// 重写当前线程的 CurrentUICulture 属性 /// 重写当前线程的 CurrentUICulture 属性。 /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } } } ================================================ FILE: v2rayN/HiddifyUpgradeN/Properties/Resources.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 ================================================ FILE: v2rayN/HiddifyUpgradeN/Properties/Settings.Designer.cs ================================================ //------------------------------------------------------------------------------ // // 此代码由工具生成。 // 运行时版本:4.0.30319.42000 // // 对此文件的更改可能会导致不正确的行为,并且如果 // 重新生成代码,这些更改将会丢失。 // //------------------------------------------------------------------------------ namespace v2rayUpgrade.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.3.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; } } } } ================================================ FILE: v2rayN/HiddifyUpgradeN/Properties/Settings.settings ================================================  ================================================ FILE: v2rayN/HiddifyUpgradeN/app.manifest ================================================  true PerMonitorV2 ================================================ FILE: v2rayN/PacLib/PacHandler.cs ================================================ using System; using System.IO; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace PacLib; public class PacHandler { private static string _configPath; private static int _httpPort; private static int _pacPort; private static TcpListener? _tcpListener; private static string _pacText; private static bool _isRunning; private static bool _needRestart = true; public static void Start(string configPath, int httpPort, int pacPort) { _needRestart = (configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning); _configPath = configPath; _httpPort = httpPort; _pacPort = pacPort; InitText(); if (_needRestart) { Stop(); RunListener(); } } private static void InitText() { var path = Path.Combine(_configPath, "pac.txt"); if (!File.Exists(path)) { File.AppendAllText(path, Resources.ResourceManager.GetString("pac")); } _pacText = File.ReadAllText(path).Replace("__PROXY__", $"PROXY 127.0.0.1:{_httpPort};DIRECT;"); } private static void RunListener() { _tcpListener = TcpListener.Create(_pacPort); _isRunning = true; _tcpListener.Start(); Task.Factory.StartNew(() => { while (_isRunning) { try { if (!_tcpListener.Pending()) { Thread.Sleep(10); continue; } var client = _tcpListener.AcceptTcpClient(); Task.Run(() => { var stream = client.GetStream(); var sb = new StringBuilder(); sb.AppendLine("HTTP/1.0 200 OK"); sb.AppendLine("Content-type:application/x-ns-proxy-autoconfig"); sb.AppendLine("Connection:close"); sb.AppendLine("Content-Length:" + Encoding.UTF8.GetByteCount(_pacText)); sb.AppendLine(); sb.Append(_pacText); var content = Encoding.UTF8.GetBytes(sb.ToString()); stream.Write(content, 0, content.Length); stream.Flush(); }); } catch (Exception e) { } } }, TaskCreationOptions.LongRunning); } public static void Stop() { if (_tcpListener != null) { try { _isRunning = false; _tcpListener.Stop(); _tcpListener = null; } catch (Exception e) { } } } } ================================================ FILE: v2rayN/PacLib/PacLib.csproj ================================================  net6.0-windows enable True True Resources.resx ResXFileCodeGenerator Resources.Designer.cs ================================================ FILE: v2rayN/PacLib/Resources/pac.txt ================================================ var proxy = '__PROXY__'; var rules = [ [ [], [] ], [ [ "aftygh.gov.tw", "aide.gov.tw", "aliyun.com", "arte.gov.tw", "baidu.com", "chinaso.com", "chinaz.com", "chukuang.gov.tw", "cycab.gov.tw", "dbnsa.gov.tw", "df.gov.tw", "eastcoast-nsa.gov.tw", "erv-nsa.gov.tw", "grb.gov.tw", "haosou.com", "haygo.com", "hchcc.gov.tw", "hsinchu-cc.gov.tw", "iner.gov.tw", "ip.cn", "jike.com", "jpush.cn", "klsio.gov.tw", "kmseh.gov.tw", "locql.com", "lungtanhr.gov.tw", "maolin-nsa.gov.tw", "matsu-news.gov.tw", "matsu-nsa.gov.tw", "matsucc.gov.tw", "moe.gov.tw", "nankan.gov.tw", "ncree.gov.tw", "necoast-nsa.gov.tw", "ner.gov.tw", "nmmba.gov.tw", "nmp.gov.tw", "nmvttc.gov.tw", "northguan-nsa.gov.tw", "npm.gov.tw", "nstm.gov.tw", "ntdmh.gov.tw", "ntl.gov.tw", "ntsec.gov.tw", "ntuh.gov.tw", "nvri.gov.tw", "nyc.gov.tw", "penghu-nsa.gov.tw", "post.gov.tw", "qq.com", "simplecd.me", "sina.cn", "sina.com.cn", "siraya-nsa.gov.tw", "sl-reverse.com", "so.com", "sogou.com", "soso.com", "stdtime.gov.tw", "sunmoonlake.gov.tw", "syniumsoftware.com", "taitung-house.gov.tw", "taoyuan.gov.tw", "tphcc.gov.tw", "trimt-nsa.gov.tw", "uluai.com.cn", "vghks.gov.tw", "vghtc.gov.tw", "vghtpe.gov.tw", "wallproxy.com.cn", "wanfang.gov.tw", "weibo.com", "yahoo.cn", "yatsen.gov.tw", "yda.gov.tw", "youdao.com", "zhongsou.com" ], [ "000webhost.com", "030buy.com", "0rz.tw", "1-apple.com.tw", "10.tt", "1000giri.net", "100ke.org", "10beasts.net", "10conditionsoflove.com", "10musume.com", "123rf.com", "12bet.com", "12vpn.com", "12vpn.net", "1337x.to", "138.com", "141hongkong.com", "141jj.com", "141tube.com", "1688.com.au", "173ng.com", "177pic.info", "17t17p.com", "18board.com", "18board.info", "18onlygirls.com", "18p2p.com", "18virginsex.com", "1949er.org", "1984.city", "1984bbs.com", "1984bbs.org", "1991way.com", "1998cdp.org", "1bao.org", "1dumb.com", "1e100.net", "1eew.com", "1mobile.com", "1mobile.tw", "1pondo.tv", "2-hand.info", "2000fun.com", "2008xianzhang.info", "2017.hk", "2021hkcharter.com", "2047.name", "21andy.com", "21join.com", "21pron.com", "21sextury.com", "228.net.tw", "233abc.com", "24hrs.ca", "24smile.org", "25u.com", "2lipstube.com", "2shared.com", "2waky.com", "3-a.net", "30boxes.com", "315lz.com", "32red.com", "36rain.com", "3a5a.com", "3arabtv.com", "3boys2girls.com", "3d-game.com", "3proxy.ru", "3ren.ca", "3tui.net", "404museum.com", "43110.cf", "466453.com", "4bluestones.biz", "4chan.com", "4dq.com", "4everproxy.com", "4irc.com", "4mydomain.com", "4pu.com", "4rbtv.com", "4shared.com", "4sqi.net", "50webs.com", "51.ca", "51jav.org", "51luoben.com", "5278.cc", "5299.tv", "5aimiku.com", "5i01.com", "5isotoi5.org", "5maodang.com", "63i.com", "64museum.org", "64tianwang.com", "64wiki.com", "66.ca", "666kb.com", "6do.news", "6park.com", "6parkbbs.com", "6parker.com", "6parknews.com", "7-zip.org", "7capture.com", "7cow.com", "8-d.com", "85cc.net", "85cc.us", "85st.com", "881903.com", "888.com", "888poker.com", "89-64.org", "8964museum.com", "8news.com.tw", "8z1.net", "9001700.com", "908taiwan.org", "91porn.com", "91vps.club", "92ccav.com", "991.com", "99btgc01.com", "99cn.info", "9bis.com", "9bis.net", "9cache.com", "9gag.com", "9news.com.au", "a-normal-day.com", "aamacau.com", "abc.com", "abc.net.au", "abc.xyz", "abchinese.com", "abclite.net", "abebooks.com", "ablwang.com", "aboluowang.com", "about.google", "aboutgfw.com", "abs.edu", "acast.com", "accim.org", "accountkit.com", "aceros-de-hispania.com", "acevpn.com", "acg18.me", "acgbox.org", "acgkj.com", "acgnx.se", "acmedia365.com", "acmetoy.com", "acnw.com.au", "actfortibet.org", "actimes.com.au", "activpn.com", "aculo.us", "adcex.com", "addictedtocoffee.de", "addyoutube.com", "adelaidebbs.com", "admob.com", "adpl.org.hk", "ads-twitter.com", "adsense.com", "adult-sex-games.com", "adultfriendfinder.com", "adultkeep.net", "advanscene.com", "advertfan.com", "advertisercommunity.com", "ae.org", "aenhancers.com", "aex.com", "af.mil", "afantibbs.com", "afr.com", "afreecatv.com", "agnesb.fr", "agoogleaday.com", "agro.hk", "ai-kan.net", "ai-wen.net", "ai.google", "aiph.net", "airasia.com", "airconsole.com", "aircrack-ng.org", "airvpn.org", "aisex.com", "ait.org.tw", "aiweiwei.com", "aiweiweiblog.com", "ajsands.com", "akademiye.org", "akamai.net", "akamaihd.net", "akamaistream.net", "akamaized.net", "akiba-online.com", "akiba-web.com", "akow.org", "al-islam.com", "al-qimmah.net", "alabout.com", "alanhou.com", "alarab.qa", "alasbarricadas.org", "alexlur.org", "alforattv.net", "alhayat.com", "alicejapan.co.jp", "aliengu.com", "alive.bar", "alkasir.com", "all4mom.org", "allcoin.com", "allconnected.co", "alldrawnsex.com", "allervpn.com", "allfinegirls.com", "allgirlmassage.com", "allgirlsallowed.org", "allgravure.com", "alliance.org.hk", "allinfa.com", "alljackpotscasino.com", "allmovie.com", "allowed.org", "almasdarnews.com", "almostmy.com", "alphaporno.com", "alternate-tools.com", "alternativeto.net", "altrec.com", "alvinalexander.com", "alwaysdata.com", "alwaysdata.net", "alwaysvpn.com", "am730.com.hk", "amazon.co.jp", "amazon.com", "amazonaws.com", "ameblo.jp", "america.gov", "american.edu", "americangreencard.com", "americanunfinished.com", "americorps.gov", "amiblockedornot.com", "amigobbs.net", "amitabhafoundation.us", "amnesty.org", "amnesty.org.hk", "amnesty.tw", "amnestyusa.org", "amnyemachen.org", "amoiist.com", "ampproject.org", "amtb-taipei.org", "anchor.fm", "anchorfree.com", "ancsconf.org", "andfaraway.net", "android-x86.org", "android.com", "androidify.com", "androidplus.co", "androidtv.com", "andygod.com", "angela-merkel.de", "angelfire.com", "angola.org", "angularjs.org", "animecrazy.net", "aniscartujo.com", "annatam.com", "anobii.com", "anontext.com", "anonymitynetwork.com", "anonymizer.com", "anonymouse.org", "anpopo.com", "answering-islam.org", "antd.org", "anthonycalzadilla.com", "anti1984.com", "antichristendom.com", "antiwave.net", "anws.gov.tw", "anyporn.com", "anysex.com", "ao3.org", "aobo.com.au", "aofriend.com", "aofriend.com.au", "aojiao.org", "aol.ca", "aol.co.uk", "aol.com", "aolnews.com", "aomiwang.com", "ap.org", "apartmentratings.com", "apartments.com", "apat1989.org", "apetube.com", "api.ai", "apiary.io", "apigee.com", "apk-dl.com", "apk.support", "apkcombo.com", "apkmirror.com", "apkmonk.com", "apkplz.com", "apkpure.com", "aplusvpn.com", "appbrain.com", "appdownloader.net", "appledaily.com", "appledaily.com.hk", "appledaily.com.tw", "appshopper.com", "appsocks.net", "appspot.com", "appsto.re", "aptoide.com", "archive.fo", "archive.is", "archive.li", "archive.org", "archive.ph", "archive.today", "archiveofourown.com", "archiveofourown.org", "archives.gov", "archives.gov.tw", "arctosia.com", "areca-backup.org", "arena.taipei", "arethusa.su", "arlingtoncemetery.mil", "army.mil", "art4tibet1998.org", "arte.tv", "artofpeacefoundation.org", "artstation.com", "artsy.net", "asacp.org", "asdfg.jp", "asg.to", "asia-gaming.com", "asiaharvest.org", "asianage.com", "asianews.it", "asianfreeforum.com", "asiansexdiary.com", "asianspiss.com", "asianwomensfilm.de", "asiaone.com", "asiatgp.com", "asiatoday.us", "askstudent.com", "askynz.net", "aspi.org.au", "aspistrategist.org.au", "assembla.com", "assimp.org", "astrill.com", "atc.org.au", "atchinese.com", "atdmt.com", "atgfw.org", "athenaeizou.com", "atlanta168.com", "atlaspost.com", "atnext.com", "audionow.com", "authorizeddns.net", "authorizeddns.org", "authorizeddns.us", "autodraw.com", "av-e-body.com", "av.com", "av.movie", "avaaz.org", "avbody.tv", "avcity.tv", "avcool.com", "avdb.in", "avdb.tv", "avfantasy.com", "avg.com", "avgle.com", "avidemux.org", "avmo.pw", "avmoo.com", "avmoo.net", "avmoo.pw", "avoision.com", "avyahoo.com", "axios.com", "axureformac.com", "azerbaycan.tv", "azerimix.com", "azubu.tv", "azurewebsites.net", "b-ok.cc", "b0ne.com", "baby-kingdom.com", "babylonbee.com", "babynet.com.hk", "backchina.com", "backpackers.com.tw", "backtotiananmen.com", "badiucao.com", "badjojo.com", "badoo.com", "baidu.jp", "baijie.org", "bailandaily.com", "baixing.me", "bakgeekhome.tk", "banana-vpn.com", "band.us", "bandcamp.com", "bandwagonhost.com", "bangbrosnetwork.com", "bangchen.net", "bangdream.space", "bangkokpost.com", "bangyoulater.com", "bankmobilevibe.com", "bannedbook.org", "bannednews.org", "banorte.com", "baramangaonline.com", "barenakedislam.com", "barnabu.co.uk", "barton.de", "bastillepost.com", "bayvoice.net", "baywords.com", "bb-chat.tv", "bbc.co.uk", "bbc.com", "bbc.in", "bbcchinese.com", "bbchat.tv", "bbci.co.uk", "bbg.gov", "bbkz.com", "bbnradio.org", "bbs-tw.com", "bbsdigest.com", "bbsfeed.com", "bbsland.com", "bbsmo.com", "bbsone.com", "bbtoystore.com", "bcast.co.nz", "bcc.com.tw", "bcchinese.net", "bcex.ca", "bcmorning.com", "bdsmvideos.net", "beaconevents.com", "bebo.com", "beeg.com", "beevpn.com", "behance.net", "behindkink.com", "beijing1989.com", "beijing2022.art", "beijingspring.com", "beijingzx.org", "belamionline.com", "bell.wiki", "bemywife.cc", "beric.me", "berlinerbericht.de", "berlintwitterwall.com", "berm.co.nz", "bestforchina.org", "bestgore.com", "bestpornstardb.com", "bestvpn.com", "bestvpnanalysis.com", "bestvpnserver.com", "bestvpnservice.com", "bestvpnusa.com", "bet365.com", "betfair.com", "betternet.co", "bettervpn.com", "bettween.com", "betvictor.com", "bewww.net", "beyondfirewall.com", "bfnn.org", "bfsh.hk", "bgvpn.com", "bianlei.com", "biantailajiao.com", "biantailajiao.in", "biblesforamerica.org", "bibox.com", "bic2011.org", "biedian.me", "big.one", "bigfools.com", "bigjapanesesex.com", "bigmoney.biz", "bignews.org", "bigone.com", "bigsound.org", "bild.de", "biliworld.com", "billypan.com", "binance.com", "bing.com", "binux.me", "binwang.me", "bird.so", "bit-z.com", "bit.do", "bit.ly", "bitbay.net", "bitchute.com", "bitcointalk.org", "bitcoinworld.com", "bitfinex.com", "bithumb.com", "bitinka.com.ar", "bitmex.com", "bitshare.com", "bitsnoop.com", "bitterwinter.org", "bitvise.com", "bitz.ai", "bizhat.com", "bjnewlife.org", "bjs.org", "bjzc.org", "bl-doujinsouko.com", "blacklogic.com", "blackvpn.com", "blewpass.com", "blingblingsquad.net", "blinkx.com", "blinw.com", "blip.tv", "blockcast.it", "blockcn.com", "blockedbyhk.com", "blockless.com", "blog.de", "blog.google", "blog.jp", "blogblog.com", "blogcatalog.com", "blogcity.me", "blogdns.org", "blogger.com", "blogimg.jp", "bloglines.com", "bloglovin.com", "blogs.com", "blogspot.com", "blogspot.hk", "blogspot.jp", "blogspot.tw", "blogtd.net", "blogtd.org", "bloodshed.net", "bloomberg.cn", "bloomberg.com", "bloomberg.de", "bloombergview.com", "bloomfortune.com", "blubrry.com", "blueangellive.com", "bmfinn.com", "bnews.co", "bnext.com.tw", "bnn.co", "bnrmetal.com", "boardreader.com", "bod.asia", "bodog88.com", "bolehvpn.net", "bonbonme.com", "bonbonsex.com", "bonfoundation.org", "bongacams.com", "boobstagram.com", "book.com.tw", "bookdepository.com", "bookepub.com", "books.com.tw", "booktopia.com.au", "boomssr.com", "borgenmagazine.com", "bot.nu", "botanwang.com", "bowenpress.com", "box.com", "box.net", "boxpn.com", "boxun.com", "boxun.tv", "boxunblog.com", "boxunclub.com", "boyangu.com", "boyfriendtv.com", "boysfood.com", "boysmaster.com", "br.st", "brainyquote.com", "brandonhutchinson.com", "braumeister.org", "brave.com", "bravotube.net", "brazzers.com", "breached.to", "break.com", "breakgfw.com", "breaking911.com", "breakingtweets.com", "breakwall.net", "briefdream.com", "briian.com", "brill.com", "brizzly.com", "brkmd.com", "broadbook.com", "broadpressinc.com", "brockbbs.com", "brookings.edu", "brucewang.net", "brutaltgp.com", "bt2mag.com", "bt95.com", "btaia.com", "btbtav.com", "btc98.com", "btcbank.bank", "btctrade.im", "btdigg.org", "btku.me", "btku.org", "btspread.com", "btsynckeys.com", "budaedu.org", "buddhanet.com.tw", "buddhistchannel.tv", "buffered.com", "bullguard.com", "bullog.org", "bullogger.com", "bunbunhk.com", "busayari.com", "business-humanrights.org", "business.page", "businessinsider.com", "businessinsider.com.au", "businesstoday.com.tw", "businessweek.com", "busu.org", "busytrade.com", "buugaa.com", "buzzhand.com", "buzzhand.net", "buzzorange.com", "bvpn.com", "bwbx.io", "bwgyhw.com", "bwh1.net", "bwsj.hk", "bx.in.th", "bx.tl", "bybit.com", "bynet.co.il", "bypasscensorship.org", "byrut.org", "c-est-simple.com", "c-span.org", "c-spanvideo.org", "c100tibet.org", "c2cx.com", "cablegatesearch.net", "cachinese.com", "cacnw.com", "cactusvpn.com", "cafepress.com", "cahr.org.tw", "caijinglengyan.com", "calameo.com", "calebelston.com", "calgarychinese.ca", "calgarychinese.com", "calgarychinese.net", "calibre-ebook.com", "caltech.edu", "cam4.com", "cam4.jp", "cam4.sg", "camfrog.com", "campaignforuyghurs.org", "cams.com", "cams.org.sg", "canadameet.com", "canalporno.com", "cantonese.asia", "canyu.org", "cao.im", "caobian.info", "caochangqing.com", "cap.org.hk", "carabinasypistolas.com", "cardinalkungfoundation.org", "careerengine.us", "carfax.com", "cari.com.my", "caribbeancom.com", "carmotorshow.com", "carrd.co", "carryzhou.com", "cartoonmovement.com", "casadeltibetbcn.org", "casatibet.org.mx", "casinobellini.com", "casinoking.com", "casinoriva.com", "castbox.fm", "catch22.net", "catchgod.com", "catfightpayperview.xxx", "catholic.org.hk", "catholic.org.tw", "cathvoice.org.tw", "cato.org", "cattt.com", "cbc.ca", "cbsnews.com", "cbtc.org.hk", "cc.com", "cccat.cc", "cccat.co", "ccdtr.org", "cchere.com", "ccim.org", "cclife.ca", "cclife.org", "cclifefl.org", "ccthere.com", "ccthere.net", "cctmweb.net", "cctongbao.com", "ccue.ca", "ccue.com", "ccvoice.ca", "ccw.org.tw", "cdbook.org", "cdcparty.com", "cdef.org", "cdig.info", "cdjp.org", "cdnews.com.tw", "cdninstagram.com", "cdp1989.org", "cdp1998.org", "cdp2006.org", "cdpeu.org", "cdpusa.org", "cdpweb.org", "cdpwu.org", "cdw.com", "cecc.gov", "cellulo.info", "cenews.eu", "centauro.com.br", "centerforhumanreprod.com", "centralnation.com", "centurys.net", "certificate-transparency.org", "cfhks.org.hk", "cfos.de", "cfr.org", "cftfc.com", "cgdepot.org", "cgst.edu", "change.org", "changeip.name", "changeip.net", "changeip.org", "changp.com", "changsa.net", "channelnewsasia.com", "chaoex.com", "chapm25.com", "chatnook.com", "chaturbate.com", "checkgfw.com", "chengmingmag.com", "chenguangcheng.com", "chenpokong.com", "chenpokong.net", "chenpokongvip.com", "cherrysave.com", "chhongbi.org", "chicagoncmtv.com", "china-mmm.net", "china-review.com.ua", "china-week.com", "china101.com", "china18.org", "china21.com", "china21.org", "china5000.us", "chinaaffairs.org", "chinaaid.me", "chinaaid.net", "chinaaid.org", "chinaaid.us", "chinachange.org", "chinachannel.hk", "chinacitynews.be", "chinacomments.org", "chinadialogue.net", "chinadigitaltimes.net", "chinaelections.org", "chinaeweekly.com", "chinafreepress.org", "chinagate.com", "chinageeks.org", "chinagfw.org", "chinagonet.com", "chinagreenparty.org", "chinahorizon.org", "chinahush.com", "chinainperspective.com", "chinainterimgov.org", "chinalaborwatch.org", "chinalawandpolicy.com", "chinalawtranslate.com", "chinamule.com", "chinamz.org", "chinanewscenter.com", "chinapost.com.tw", "chinapress.com.my", "chinarightsia.org", "chinasmile.net", "chinasocialdemocraticparty.com", "chinasoul.org", "chinasucks.net", "chinatimes.com", "chinatopsex.com", "chinatown.com.au", "chinatweeps.com", "chinaway.org", "chinaworker.info", "chinaxchina.com", "chinayouth.org.hk", "chinayuanmin.org", "chinese-hermit.net", "chinese-leaders.org", "chinese-memorial.org", "chinesedaily.com", "chinesedailynews.com", "chinesedemocracy.com", "chinesegay.org", "chinesen.de", "chinesenews.net.au", "chinesepen.org", "chineseradioseattle.com", "chinesetalks.net", "chineseupress.com", "chingcheong.com", "chinman.net", "chithu.org", "chobit.cc", "chosun.com", "chrdnet.com", "christianfreedom.org", "christianstudy.com", "christiantimes.org.hk", "christusrex.org", "chrlawyers.hk", "chrome.com", "chromecast.com", "chromeenterprise.google", "chromeexperiments.com", "chromercise.com", "chromestatus.com", "chromium.org", "chuang-yen.org", "chubold.com", "chubun.com", "churchinhongkong.org", "chushigangdrug.ch", "cienen.com", "cineastentreff.de", "cipfg.org", "circlethebayfortibet.org", "cirosantilli.com", "citizencn.com", "citizenlab.ca", "citizenlab.org", "citizenscommission.hk", "citizensradio.org", "city365.ca", "city9x.com", "citypopulation.de", "citytalk.tw", "civicparty.hk", "civildisobediencemovement.org", "civilhrfront.org", "civiliangunner.com", "civilmedia.tw", "civisec.org", "cjb.net", "ck101.com", "clarionproject.org", "classicalguitarblog.net", "clb.org.hk", "cleansite.biz", "cleansite.info", "cleansite.us", "clearharmony.net", "clearsurance.com", "clearwisdom.net", "clementine-player.org", "clinica-tibet.ru", "clipfish.de", "cloakpoint.com", "cloudcone.com", "cloudflare-ipfs.com", "cloudfront.net", "club1069.com", "clubhouseapi.com", "clyp.it", "cmcn.org", "cmi.org.tw", "cmoinc.org", "cms.gov", "cmu.edu", "cmule.com", "cmule.org", "cmx.im", "cn-proxy.com", "cn.com", "cn6.eu", "cna.com.tw", "cnabc.com", "cnd.org", "cnet.com", "cnex.org.cn", "cnineu.com", "cnitter.com", "cnn.com", "cnpolitics.org", "cnproxy.com", "cnyes.com", "co.tv", "coat.co.jp", "cobinhood.com", "cochina.co", "cochina.org", "code1984.com", "codeplex.com", "codeshare.io", "codeskulptor.org", "coin2co.in", "coinbene.com", "coinegg.com", "coinex.com", "coingecko.com", "coingi.com", "coinmarketcap.com", "coinrail.co.kr", "cointiger.com", "cointobe.com", "coinut.com", "collateralmurder.com", "collateralmurder.org", "com.google", "com.ru", "com.uk", "comedycentral.com", "comefromchina.com", "comic-mega.me", "comico.tw", "commandarms.com", "commentshk.com", "communistcrimes.org", "communitychoicecu.com", "comparitech.com", "compileheart.com", "compress.to", "compython.net", "conoha.jp", "constitutionalism.solutions", "contactmagazine.net", "convio.net", "coobay.com", "cool18.com", "coolaler.com", "coolder.com", "coolloud.org.tw", "coolncute.com", "coolstuffinc.com", "corumcollege.com", "cos-moe.com", "cosplayjav.pl", "costco.com", "cotweet.com", "counter.social", "coursehero.com", "cpj.org", "cq99.us", "crackle.com", "crazys.cc", "crazyshit.com", "crbug.com", "crchina.org", "crd-net.org", "creaders.net", "creadersnet.com", "creativelab5.com", "crisisresponse.google", "cristyli.com", "crocotube.com", "crossfire.co.kr", "crossthewall.net", "crossvpn.net", "croxyproxy.com", "crrev.com", "crucial.com", "crunchyroll.com", "cryptographyengineering.com", "csdparty.com", "csis.org", "csmonitor.com", "csuchen.de", "csw.org.uk", "ct.org.tw", "ctao.org", "ctfriend.net", "ctitv.com.tw", "ctowc.org", "cts.com.tw", "ctwant.com", "cuhk.edu.hk", "cuhkacs.org", "cuihua.org", "cuiweiping.net", "culture.tw", "cumlouder.com", "curvefish.com", "cusp.hk", "cusu.hk", "cutscenes.net", "cw.com.tw", "cwb.gov.tw", "cyberctm.com", "cyberghostvpn.com", "cynscribe.com", "cytode.us", "cz.cc", "d-fukyu.com", "d0z.net", "d100.net", "d2bay.com", "d2pass.com", "dabr.co.uk", "dabr.eu", "dabr.me", "dabr.mobi", "dadazim.com", "dadi360.com", "dafabet.com", "dafagood.com", "dafahao.com", "dafoh.org", "daftporn.com", "dagelijksestandaard.nl", "daidostup.ru", "dailidaili.com", "dailymail.co.uk", "dailymotion.com", "dailysabah.com", "dailyview.tw", "daiphapinfo.net", "dajiyuan.com", "dajiyuan.de", "dajiyuan.eu", "dalailama-archives.org", "dalailama.com", "dalailama.mn", "dalailama.ru", "dalailama80.org", "dalailamacenter.org", "dalailamafellows.org", "dalailamafilm.com", "dalailamafoundation.org", "dalailamahindi.com", "dalailamainaustralia.org", "dalailamajapanese.com", "dalailamaprotesters.info", "dalailamaquotes.org", "dalailamatrust.org", "dalailamavisit.org.nz", "dalailamaworld.com", "dalianmeng.org", "daliulian.org", "danke4china.net", "daolan.net", "darktech.org", "darktoy.net", "darpa.mil", "darrenliuwei.com", "dastrassi.org", "data-vocabulary.org", "data.gov.tw", "daum.net", "david-kilgour.com", "dawangidc.com", "daxa.cn", "dayabook.com", "daylife.com", "db.tt", "dbc.hk", "dbgjd.com", "dcard.tw", "dcmilitary.com", "ddc.com.tw", "ddhw.info", "ddns.info", "ddns.me.uk", "ddns.mobi", "ddns.ms", "ddns.name", "ddns.net", "ddns.us", "de-sci.org", "deadline.com", "deaftone.com", "debug.com", "deck.ly", "decodet.co", "deepmind.com", "deezer.com", "definebabe.com", "deja.com", "delcamp.net", "delicious.com", "democrats.org", "demosisto.hk", "depositphotos.com", "desc.se", "design.google", "desipro.de", "dessci.com", "destroy-china.jp", "deutsche-welle.de", "deviantart.com", "deviantart.net", "devio.us", "devpn.com", "dfas.mil", "dfn.org", "dharamsalanet.com", "dharmakara.net", "dhcp.biz", "diaoyuislands.org", "difangwenge.org", "digiland.tw", "digisfera.com", "digitalnomadsproject.org", "diigo.com", "dilber.se", "dingchin.com.tw", "dipity.com", "directcreative.com", "discoins.com", "disconnect.me", "discord.com", "discord.gg", "discordapp.com", "discordapp.net", "discuss.com.hk", "discuss4u.com", "dish.com", "disp.cc", "disqus.com", "dit-inc.us", "dizhidizhi.com", "dizhuzhishang.com", "djangosnippets.org", "djorz.com", "dl-laby.jp", "dlive.tv", "dlsite.com", "dlsite.jp", "dlyoutube.com", "dm530.net", "dmc.nico", "dmcdn.net", "dmhy.org", "dmm.co.jp", "dmm.com", "dns-dns.com", "dns-stuff.com", "dns.google", "dns04.com", "dns05.com", "dns1.us", "dns2.us", "dns2go.com", "dnscrypt.org", "dnset.com", "dnsrd.com", "dnssec.net", "dnvod.tv", "doctorvoice.org", "documentingreality.com", "dogfartnetwork.com", "dojin.com", "dok-forum.net", "dolc.de", "dolf.org.hk", "dollf.com", "domain.club.tw", "domains.google", "domaintoday.com.au", "donga.com", "dongtaiwang.com", "dongtaiwang.net", "dongyangjing.com", "donmai.us", "dontfilter.us", "dontmovetochina.com", "dorjeshugden.com", "dotplane.com", "dotsub.com", "dotvpn.com", "doub.io", "doubibackup.com", "doubmirror.cf", "dougscripts.com", "douhokanko.net", "doujincafe.com", "dowei.org", "dowjones.com", "dphk.org", "dpp.org.tw", "dpr.info", "dragonex.io", "dragonsprings.org", "dreamamateurs.com", "drepung.org", "drgan.net", "drmingxia.org", "dropbooks.tv", "dropbox.com", "dropboxapi.com", "dropboxusercontent.com", "drsunacademy.com", "drtuber.com", "dscn.info", "dsmtp.com", "dstk.dk", "dtdns.net", "dtiblog.com", "dtic.mil", "dtwang.org", "duanzhihu.com", "dubox.com", "duck.com", "duckdns.org", "duckduckgo.com", "duckload.com", "duckmylife.com", "duga.jp", "duihua.org", "duihuahrjournal.org", "dumb1.com", "dunyabulteni.net", "duoweitimes.com", "duping.net", "duplicati.com", "dupola.com", "dupola.net", "dushi.ca", "duyaoss.com", "dvdpac.com", "dvorak.org", "dw-world.com", "dw-world.de", "dw.com", "dw.de", "dwheeler.com", "dwnews.com", "dwnews.net", "dxiong.com", "dynamic-dns.net", "dynamicdns.biz", "dynamicdns.co.uk", "dynamicdns.me.uk", "dynamicdns.org.uk", "dynawebinc.com", "dyndns-ip.com", "dyndns-pics.com", "dyndns.org", "dyndns.pro", "dynssl.com", "dynu.com", "dynu.net", "dysfz.cc", "dzze.com", "e-classical.com.tw", "e-gold.com", "e-hentai.org", "e-hentaidb.com", "e-info.org.tw", "e-traderland.net", "e-zone.com.hk", "e123.hk", "earlytibet.com", "earthcam.com", "earthvpn.com", "eastern-ark.com", "easternlightning.org", "eastturkestan.com", "eastturkistan-gov.org", "eastturkistan.net", "eastturkistancc.org", "eastturkistangovernmentinexile.us", "easyca.ca", "easypic.com", "ebc.net.tw", "ebony-beauty.com", "ebookbrowse.com", "ebookee.com", "ebtcbank.com", "ecfa.org.tw", "echainhost.com", "echofon.com", "ecimg.tw", "ecministry.net", "economist.com", "ecstart.com", "edgecastcdn.net", "edgesuite.net", "edicypages.com", "edmontonchina.cn", "edmontonservice.com", "edns.biz", "edoors.com", "edubridge.com", "edupro.org", "eesti.ee", "eevpn.com", "efcc.org.hk", "effers.com", "efksoft.com", "efukt.com", "eic-av.com", "eireinikotaerukai.com", "eisbb.com", "eksisozluk.com", "electionsmeter.com", "elgoog.im", "ellawine.org", "elpais.com", "eltondisney.com", "emaga.com", "emanna.com", "emilylau.org.hk", "emory.edu", "empfil.com", "emule-ed2k.com", "emulefans.com", "emuparadise.me", "enanyang.my", "encrypt.me", "encyclopedia.com", "enewstree.com", "enfal.de", "engadget.com", "engagedaily.org", "englishforeveryone.org", "englishfromengland.co.uk", "englishpen.org", "enlighten.org.tw", "entermap.com", "environment.google", "epa.gov.tw", "epac.to", "episcopalchurch.org", "epochhk.com", "epochtimes-bg.com", "epochtimes-romania.com", "epochtimes.co.il", "epochtimes.co.kr", "epochtimes.com", "epochtimes.cz", "epochtimes.de", "epochtimes.fr", "epochtimes.ie", "epochtimes.it", "epochtimes.jp", "epochtimes.ru", "epochtimes.se", "epochtimestr.com", "epochweek.com", "epochweekly.com", "eporner.com", "equinenow.com", "erabaru.net", "eracom.com.tw", "eraysoft.com.tr", "erepublik.com", "erights.net", "eriversoft.com", "erktv.com", "ernestmandel.org", "erodaizensyu.com", "erodoujinlog.com", "erodoujinworld.com", "eromanga-kingdom.com", "eromangadouzin.com", "eromon.net", "eroprofile.com", "eroticsaloon.net", "eslite.com", "esmtp.biz", "esu.dog", "esu.im", "esurance.com", "etaa.org.au", "etadult.com", "etaiwannews.com", "etherdelta.com", "etherscan.io", "etizer.org", "etokki.com", "etowns.net", "etowns.org", "etsy.com", "ettoday.net", "etvonline.hk", "eu.org", "eucasino.com", "eulam.com", "eurekavpt.com", "euronews.com", "europa.eu", "evozi.com", "evschool.net", "exblog.co.jp", "exblog.jp", "exchristian.hk", "excite.co.jp", "exhentai.org", "exmo.com", "exmormon.org", "expatshield.com", "expecthim.com", "expekt.com", "experts-univers.com", "exploader.net", "expofutures.com", "expressvpn.com", "exrates.me", "extmatrix.com", "extremetube.com", "exx.com", "eyevio.jp", "eyny.com", "ezpc.tk", "ezpeer.com", "ezua.com", "f8.com", "fa.gov.tw", "facebook.br", "facebook.com", "facebook.design", "facebook.hu", "facebook.in", "facebook.net", "facebook.nl", "facebook.se", "facebookmail.com", "facebookquotes4u.com", "faceless.me", "facesofnyfw.com", "facesoftibetanselfimmolators.info", "factpedia.org", "fail.hk", "faith100.org", "faithfuleye.com", "faiththedog.info", "fakku.net", "fallenark.com", "falsefire.com", "falun-co.org", "falun-ny.net", "falunart.org", "falunasia.info", "falunau.org", "falunaz.net", "falundafa-dc.org", "falundafa-florida.org", "falundafa-nc.org", "falundafa-pa.net", "falundafa-sacramento.org", "falundafa.org", "falundafaindia.org", "falundafamuseum.org", "falungong.club", "falungong.de", "falungong.org.uk", "falunhr.org", "faluninfo.de", "faluninfo.net", "falunpilipinas.net", "falunworld.net", "familyfed.org", "famunion.com", "fan-qiang.com", "fandom.com", "fangbinxing.com", "fangeming.com", "fangeqiang.com", "fanglizhi.info", "fangmincn.org", "fangong.org", "fangongheike.com", "fanhaodang.com", "fanhaolou.com", "fanqiang.network", "fanqiang.tk", "fanqiangdang.com", "fanqianghou.com", "fanqiangyakexi.net", "fanqiangzhe.com", "fanswong.com", "fantv.hk", "fanyue.info", "fapdu.com", "faproxy.com", "faqserv.com", "fartit.com", "farwestchina.com", "fastestvpn.com", "fastly.net", "fastpic.ru", "fastssh.com", "faststone.org", "fatbtc.com", "favotter.net", "favstar.fm", "fawanghuihui.org", "faydao.com", "faz.net", "fb.com", "fb.me", "fb.watch", "fbaddins.com", "fbcdn.net", "fbsbx.com", "fbworkmail.com", "fc2.com", "fc2blog.net", "fc2china.com", "fc2cn.com", "fc2web.com", "fda.gov.tw", "fdbox.com", "fdc64.de", "fdc64.org", "fdc89.jp", "feedburner.com", "feeder.co", "feedly.com", "feedx.net", "feelssh.com", "feer.com", "feifeiss.com", "feitian-california.org", "feitianacademy.org", "feixiaohao.com", "feministteacher.com", "fengzhenghu.com", "fengzhenghu.net", "fevernet.com", "ff.im", "fffff.at", "fflick.com", "ffvpn.com", "fgmtv.net", "fgmtv.org", "fhreports.net", "figprayer.com", "fileflyer.com", "fileforum.com", "files2me.com", "fileserve.com", "filesor.com", "fillthesquare.org", "filmingfortibet.org", "filthdump.com", "financetwitter.com", "finchvpn.com", "findmespot.com", "findyoutube.com", "findyoutube.net", "fingerdaily.com", "finler.net", "firearmsworld.net", "firebaseio.com", "firefox.com", "fireofliberty.org", "firetweet.io", "firstfivefollowers.com", "firstpost.com", "firstrade.com", "fizzik.com", "flagsonline.it", "flecheinthepeche.fr", "fleshbot.com", "fleursdeslettres.com", "flgg.us", "flgjustice.org", "flickr.com", "flickrhivemind.net", "flickriver.com", "fling.com", "flipboard.com", "flipkart.com", "flitto.com", "flnet.org", "flog.tw", "flurry.com", "flyvpn.com", "flyzy2005.com", "fmnnow.com", "fnac.be", "fnac.com", "fochk.org", "focustaiwan.tw", "focusvpn.com", "fofg-europe.net", "fofg.org", "fofldfradio.org", "foolsmountain.com", "fooooo.com", "foreignaffairs.com", "foreignpolicy.com", "forum4hk.com", "forums-free.com", "fotile.me", "fourthinternational.org", "foxbusiness.com", "foxdie.us", "foxgay.com", "foxsub.com", "foxtang.com", "fpmt-osel.org", "fpmt.org", "fpmt.tw", "fpmtmexico.org", "fqok.org", "fqrouter.com", "franklc.com", "freakshare.com", "free-gate.org", "free-hada-now.org", "free-proxy.cz", "free-ss.site", "free-ssh.com", "free.fr", "free4u.com.ar", "freealim.com", "freebeacon.com", "freebearblog.org", "freebrowser.org", "freechal.com", "freechina.net", "freechina.news", "freechinaforum.org", "freechinaweibo.com", "freeddns.com", "freeddns.org", "freedomchina.info", "freedomcollection.org", "freedomhouse.org", "freedomsherald.org", "freeforums.org", "freefq.com", "freefuckvids.com", "freegao.com", "freehongkong.org", "freeilhamtohti.org", "freekazakhs.org", "freekwonpyong.org", "freelotto.com", "freeman2.com", "freemoren.com", "freemorenews.com", "freemuse.org", "freenet-china.org", "freenetproject.org", "freenewscn.com", "freeones.com", "freeopenvpn.com", "freeoz.org", "freerk.com", "freessh.us", "freetcp.com", "freetibet.net", "freetibet.org", "freetibetanheroes.org", "freetribe.me", "freeviewmovies.com", "freevpn.me", "freevpn.nl", "freewallpaper4.me", "freewebs.com", "freewechat.com", "freeweibo.com", "freewww.biz", "freewww.info", "freexinwen.com", "freeyellow.com", "freeyoutubeproxy.net", "frienddy.com", "friendfeed-media.com", "friendfeed.com", "friendfinder.com", "friends-of-tibet.org", "friendsoftibet.org", "fring.com", "fringenetwork.com", "from-pr.com", "from-sd.com", "fromchinatousa.net", "frommel.net", "frontlinedefenders.org", "frootvpn.com", "fscked.org", "fsurf.com", "ftchinese.com", "ftp1.biz", "ftpserver.biz", "ftv.com.tw", "ftvnews.com.tw", "ftx.com", "fucd.com", "fuckcnnic.net", "fuckgfw.org", "fuckgfw233.org", "fulione.com", "fullerconsideration.com", "fulue.com", "funf.tw", "funkyimg.com", "funp.com", "fuq.com", "furbo.org", "furhhdl.org", "furinkan.com", "furl.net", "futurechinaforum.org", "futuremessage.org", "fux.com", "fuyin.net", "fuyindiantai.org", "fuyu.org.tw", "fw.cm", "fxcm-chinese.com", "fxnetworks.com", "fzh999.com", "fzh999.net", "fzlm.com", "g-area.org", "g-queen.com", "g.co", "g0v.social", "g6hentai.com", "gab.com", "gabocorp.com", "gaeproxy.com", "gaforum.org", "gagaoolala.com", "galaxymacau.com", "galenwu.com", "galstars.net", "game735.com", "gamebase.com.tw", "gamejolt.com", "gamer.com.tw", "gamerp.jp", "gamez.com.tw", "gamousa.com", "ganges.com", "ganjingworld.com", "gaoming.net", "gaopi.net", "gaozhisheng.net", "gaozhisheng.org", "gardennetworks.com", "gardennetworks.org", "gartlive.com", "gate-project.com", "gate.io", "gatecoin.com", "gather.com", "gatherproxy.com", "gati.org.tw", "gaybubble.com", "gaycn.net", "gayhub.com", "gaymap.cc", "gaymenring.com", "gaytube.com", "gaywatch.com", "gazotube.com", "gcc.org.hk", "gclooney.com", "gclubs.com", "gcmasia.com", "gcpnews.com", "gcr.io", "gdbt.net", "gdzf.org", "geek-art.net", "geekerhome.com", "geekheart.info", "gekikame.com", "gelbooru.com", "genius.com", "geocities.co.jp", "geocities.com", "geocities.jp", "geph.io", "gerefoundation.org", "get.app", "get.dev", "get.how", "get.page", "getastrill.com", "getchu.com", "getcloak.com", "getfoxyproxy.org", "getfreedur.com", "getgom.com", "geti2p.net", "getiton.com", "getjetso.com", "getlantern.org", "getmalus.com", "getmdl.io", "getoutline.org", "getsocialscope.com", "getsync.com", "gettr.com", "gettrials.com", "gettyimages.com", "getuploader.com", "gfbv.de", "gfgold.com.hk", "gfsale.com", "gfw.org.ua", "gfw.press", "gfw.report", "ggpht.com", "ggssl.com", "ghidra-sre.org", "ghostpath.com", "ghut.org", "giantessnight.com", "gifree.com", "giga-web.jp", "gigacircle.com", "giganews.com", "gigporno.ru", "girlbanker.com", "git.io", "gitbooks.io", "githack.com", "github.blog", "github.com", "github.io", "githubassets.com", "githubusercontent.com", "gizlen.net", "gjczz.com", "glass8.eu", "globaljihad.net", "globalmediaoutreach.com", "globalmuseumoncommunism.org", "globalrescue.net", "globaltm.org", "globalvoices.org", "globalvoicesonline.org", "globalvpn.net", "glock.com", "gloryhole.com", "glorystar.me", "gluckman.com", "glype.com", "gmail.com", "gmgard.com", "gmhz.org", "gmiddle.com", "gmiddle.net", "gmll.org", "gmodules.com", "gmx.net", "gnci.org.hk", "gnews.org", "go-pki.com", "go141.com", "goagent.biz", "goagentplus.com", "gobet.cc", "godfootsteps.org", "godns.work", "godoc.org", "godsdirectcontact.co.uk", "godsdirectcontact.org", "godsdirectcontact.org.tw", "godsimmediatecontact.com", "gofundme.com", "gogotunnel.com", "gohappy.com.tw", "gokbayrak.com", "golang.org", "goldbet.com", "goldbetsports.com", "golden-ages.org", "goldeneyevault.com", "goldenfrog.com", "goldjizz.com", "goldstep.net", "goldwave.com", "gongm.in", "gongmeng.info", "gongminliliang.com", "gongwt.com", "goo.gl", "goo.gle", "goo.ne.jp", "gooday.xyz", "gooddns.info", "goodhope.school", "goodreaders.com", "goodreads.com", "goodtv.com.tw", "goodtv.tv", "goofind.com", "google.ac", "google.ad", "google.ae", "google.af", "google.ai", "google.al", "google.am", "google.as", "google.at", "google.az", "google.ba", "google.be", "google.bf", "google.bg", "google.bi", "google.bj", "google.bs", "google.bt", "google.by", "google.ca", "google.cat", "google.cd", "google.cf", "google.cg", "google.ch", "google.ci", "google.cl", "google.cm", "google.cn", "google.co.ao", "google.co.bw", "google.co.ck", "google.co.cr", "google.co.id", "google.co.il", "google.co.in", "google.co.jp", "google.co.ke", "google.co.kr", "google.co.ls", "google.co.ma", "google.co.mz", "google.co.nz", "google.co.th", "google.co.tz", "google.co.ug", "google.co.uk", "google.co.uz", "google.co.ve", "google.co.vi", "google.co.za", "google.co.zm", "google.co.zw", "google.com", "google.com.af", "google.com.ag", "google.com.ai", "google.com.ar", "google.com.au", "google.com.bd", "google.com.bh", "google.com.bn", "google.com.bo", "google.com.br", "google.com.bz", "google.com.co", "google.com.cu", "google.com.cy", "google.com.do", "google.com.ec", "google.com.eg", "google.com.et", "google.com.fj", "google.com.gh", "google.com.gi", "google.com.gt", "google.com.hk", "google.com.jm", "google.com.kh", "google.com.kw", "google.com.lb", "google.com.ly", "google.com.mm", "google.com.mt", "google.com.mx", "google.com.my", "google.com.na", "google.com.nf", "google.com.ng", "google.com.ni", "google.com.np", "google.com.om", "google.com.pa", "google.com.pe", "google.com.pg", "google.com.ph", "google.com.pk", "google.com.pr", "google.com.py", "google.com.qa", "google.com.sa", "google.com.sb", "google.com.sg", "google.com.sl", "google.com.sv", "google.com.tj", "google.com.tr", "google.com.tw", "google.com.ua", "google.com.uy", "google.com.vc", "google.com.vn", "google.cv", "google.cz", "google.de", "google.dev", "google.dj", "google.dk", "google.dm", "google.dz", "google.ee", "google.es", "google.eu", "google.fi", "google.fm", "google.fr", "google.ga", "google.ge", "google.gg", "google.gl", "google.gm", "google.gp", "google.gr", "google.gy", "google.hk", "google.hn", "google.hr", "google.ht", "google.hu", "google.ie", "google.im", "google.iq", "google.is", "google.it", "google.it.ao", "google.je", "google.jo", "google.kg", "google.ki", "google.kz", "google.la", "google.li", "google.lk", "google.lt", "google.lu", "google.lv", "google.md", "google.me", "google.mg", "google.mk", "google.ml", "google.mn", "google.ms", "google.mu", "google.mv", "google.mw", "google.mx", "google.ne", "google.nl", "google.no", "google.nr", "google.nu", "google.org", "google.pl", "google.pn", "google.ps", "google.pt", "google.ro", "google.rs", "google.ru", "google.rw", "google.sc", "google.se", "google.sh", "google.si", "google.sk", "google.sm", "google.sn", "google.so", "google.sr", "google.st", "google.td", "google.tg", "google.tk", "google.tl", "google.tm", "google.tn", "google.to", "google.tt", "google.us", "google.vg", "google.vn", "google.vu", "google.ws", "googleapis.cn", "googleapis.com", "googleapps.com", "googlearth.com", "googleartproject.com", "googleblog.com", "googlebot.com", "googlechinawebmaster.com", "googlecode.com", "googlecommerce.com", "googledomains.com", "googledrive.com", "googleearth.com", "googlefiber.net", "googlegroups.com", "googlehosted.com", "googleideas.com", "googleinsidesearch.com", "googlelabs.com", "googlemail.com", "googlemashups.com", "googlepagecreator.com", "googleplay.com", "googleplus.com", "googlesile.com", "googlesource.com", "googleusercontent.com", "googlevideo.com", "googleweblight.com", "googlezip.net", "gopetition.com", "goproxing.net", "goreforum.com", "goregrish.com", "gospelherald.com", "got-game.org", "gotdns.ch", "gotgeeks.com", "gotrusted.com", "gotw.ca", "gov.taipei", "gr8domain.biz", "gr8name.biz", "gradconnection.com", "grammaly.com", "grandtrial.org", "grangorz.org", "graphis.ne.jp", "graphql.org", "gravatar.com", "greasespot.net", "great-firewall.com", "great-roc.org", "greatfire.org", "greatfirewall.biz", "greatfirewallofchina.net", "greatfirewallofchina.org", "greatroc.org", "greatroc.tw", "greatzhonghua.org", "greenfieldbookstore.com.hk", "greenparty.org.tw", "greenpeace.com.tw", "greenpeace.org", "greenreadings.com", "greenvpn.net", "greenvpn.org", "grotty-monday.com", "grow.google", "gs-discuss.com", "gsearch.media", "gstatic.com", "gtricks.com", "gts-vpn.com", "gtv.org", "gtv1.org", "gu-chu-sum.org", "guaguass.com", "guaguass.org", "guancha.org", "guaneryu.com", "guangming.com.my", "guangnianvpn.com", "guardster.com", "guishan.org", "gumroad.com", "gun-world.net", "gunsamerica.com", "gunsandammo.com", "guo.media", "guruonline.hk", "gutteruncensored.com", "gvlib.com", "gvm.com.tw", "gvt0.com", "gvt1.com", "gvt3.com", "gwins.org", "gwtproject.org", "gyalwarinpoche.com", "gyatsostudio.com", "gzm.tv", "gzone-anime.info", "h-china.org", "h-moe.com", "h1n1china.org", "h528.com", "h5dm.com", "h5galgame.me", "hacg.club", "hacg.in", "hacg.li", "hacg.me", "hacg.red", "hacken.cc", "hacker.org", "hackmd.io", "hackthatphone.net", "hahlo.com", "hakkatv.org.tw", "handcraftedsoftware.org", "hanime.tv", "hanminzu.org", "hanunyi.com", "hao.news", "hao123.com", "hao123img.com", "happy-vpn.com", "haproxy.org", "hardsextube.com", "harunyahya.com", "hasi.wang", "hautelook.com", "hautelookcdn.com", "have8.com", "hbg.com", "hbo.com", "hclips.com", "hdlt.me", "hdtvb.net", "hdzog.com", "he.net", "heartyit.com", "heavy-r.com", "hec.su", "hecaitou.net", "hechaji.com", "heeact.edu.tw", "hegre-art.com", "helixstudios.net", "helloandroid.com", "helloqueer.com", "helloss.pw", "hellotxt.com", "hellouk.org", "helpeachpeople.com", "helplinfen.com", "helpster.de", "helpuyghursnow.org", "helpzhuling.org", "hentai.to", "hentaitube.tv", "hentaivideoworld.com", "heqinglian.net", "here.com", "heritage.org", "heroku.com", "heungkongdiscuss.com", "hexieshe.com", "hexieshe.xyz", "hexxeh.net", "heyuedi.com", "heywire.com", "heyzo.com", "hgseav.com", "hhdcb3office.org", "hhthesakyatrizin.org", "hi-on.org.tw", "hidden-advent.org", "hide.me", "hidecloud.com", "hidein.net", "hideipvpn.com", "hideman.net", "hideme.nl", "hidemy.name", "hidemyass.com", "hidemycomp.com", "higfw.com", "highpeakspureearth.com", "highrockmedia.com", "hightail.com", "hihiforum.com", "hihistory.net", "hiitch.com", "hikinggfw.org", "hilive.tv", "himalayan-foundation.org", "himalayanglacier.com", "himemix.com", "himemix.net", "hinet.net", "hitbtc.com", "hitomi.la", "hiwifi.com", "hizb-ut-tahrir.info", "hizb-ut-tahrir.org", "hizbuttahrir.org", "hjclub.info", "hk-pub.com", "hk01.com", "hk32168.com", "hkacg.com", "hkacg.net", "hkatvnews.com", "hkbc.net", "hkbf.org", "hkbookcity.com", "hkchronicles.com", "hkchurch.org", "hkci.org.hk", "hkcmi.edu", "hkcnews.com", "hkcoc.com", "hkctu.org.hk", "hkdailynews.com.hk", "hkday.net", "hkdc.us", "hkdf.org", "hkej.com", "hkepc.com", "hket.com", "hkfaa.com", "hkfreezone.com", "hkfront.org", "hkgalden.com", "hkgolden.com", "hkgpao.com", "hkgreenradio.org", "hkheadline.com", "hkhkhk.com", "hkhrc.org.hk", "hkhrm.org.hk", "hkip.org.uk", "hkja.org.hk", "hkjc.com", "hkjp.org", "hklft.com", "hklts.org.hk", "hkmap.live", "hkopentv.com", "hkpeanut.com", "hkptu.org", "hkreporter.com", "hku.hk", "hkusu.net", "hkvwet.com", "hkwcc.org.hk", "hkzone.org", "hmoegirl.com", "hmonghot.com", "hmv.co.jp", "hmvdigital.ca", "hmvdigital.com", "hnjhj.com", "hnntube.com", "hola.com", "hola.org", "holymountaincn.com", "holyspiritspeaks.org", "homedepot.com", "homeip.net", "homeperversion.com", "homeservershow.com", "honeynet.org", "hongkongfp.com", "hongmeimei.com", "hongzhi.li", "honven.xyz", "hootsuite.com", "hoover.org", "hoovers.com", "hopedialogue.org", "hopto.org", "hornygamer.com", "hornytrip.com", "horrorporn.com", "hotair.com", "hotav.tv", "hotels.cn", "hotfrog.com.tw", "hotgoo.com", "hotpornshow.com", "hotpot.hk", "hotshame.com", "hotspotshield.com", "hottg.com", "hotvpn.com", "hougaige.com", "howtoforge.com", "hoxx.com", "hpa.gov.tw", "hqcdp.org", "hqjapanesesex.com", "hqmovies.com", "hrcchina.org", "hrcir.com", "hrea.org", "hrichina.org", "hrtsea.com", "hrw.org", "hrweb.org", "hsjp.net", "hsselite.com", "hst.net.tw", "hstern.net", "hstt.net", "ht.ly", "htkou.net", "htl.li", "html5rocks.com", "https443.net", "https443.org", "hua-yue.net", "huaglad.com", "huanghuagang.org", "huangyiyu.com", "huaren.us", "huaren4us.com", "huashangnews.com", "huasing.org", "huaxia-news.com", "huaxiabao.org", "huaxin.ph", "huayuworld.org", "hudatoriq.web.id", "hudson.org", "huffingtonpost.com", "hugoroy.eu", "huhaitai.com", "huhamhire.com", "huhangfei.com", "huiyi.in", "hulkshare.com", "hulu.com", "huluim.com", "hung-ya.com", "hungerstrikeforaids.org", "huobi.co", "huobi.com", "huobi.me", "huobi.pro", "huobi.sc", "huobipro.com", "huping.net", "hurgokbayrak.com", "hurriyet.com.tr", "hustler.com", "hustlercash.com", "hut2.ru", "hutianyi.net", "hutong9.net", "huyandex.com", "hwadzan.tw", "hwayue.org.tw", "hwinfo.com", "hxwk.org", "hxwq.org", "hybrid-analysis.com", "hyperrate.com", "hyread.com.tw", "i-cable.com", "i-part.com.tw", "i-scmp.com", "i1.hk", "i2p2.de", "i2runner.com", "i818hk.com", "iam.soy", "iamtopone.com", "iask.bz", "iask.ca", "iav19.com", "ibiblio.org", "ibit.am", "iblist.com", "iblogserv-f.net", "ibros.org", "ibtimes.com", "ibvpn.com", "icams.com", "icerocket.com", "icij.org", "icl-fi.org", "icoco.com", "iconfactory.net", "iconpaper.org", "icu-project.org", "idaiwan.com", "idemocracy.asia", "identi.ca", "idiomconnection.com", "idlcoyote.com", "idouga.com", "idreamx.com", "idsam.com", "ieasy5.com", "ied2k.net", "ienergy1.com", "iepl.us", "ifanqiang.com", "ifcss.org", "ifjc.org", "ifreewares.com", "ift.tt", "igcd.net", "igfw.net", "igfw.tech", "igmg.de", "ignitedetroit.net", "igoogle.com", "igotmail.com.tw", "igvita.com", "ihakka.net", "ihao.org", "iicns.com", "ikstar.com", "ikwb.com", "ilbe.com", "ilhamtohtiinstitute.org", "illusionfactory.com", "ilove80.be", "ilovelongtoes.com", "im.tv", "im88.tw", "imageab.com", "imagefap.com", "imageflea.com", "images-gaytube.com", "imageshack.us", "imagevenue.com", "imagezilla.net", "imb.org", "imdb.com", "img.ly", "imgchili.net", "imgmega.com", "imgur.com", "imkev.com", "imlive.com", "immigration.gov.tw", "immoral.jp", "impact.org.au", "impp.mn", "in-disguise.com", "in.com", "in99.org", "incapdns.net", "incloak.com", "incredibox.fr", "independent.co.uk", "indiablooms.com", "indianarrative.com", "indiandefensenews.in", "indiatimes.com", "indiemerch.com", "info-graf.fr", "informer.com", "initiativesforchina.org", "inkui.com", "inmediahk.net", "innermongolia.org", "inoreader.com", "inote.tw", "insecam.org", "inside.com.tw", "insidevoa.com", "instagram.com", "instanthq.com", "institut-tibetain.org", "internet.org", "internetdefenseleague.org", "internetfreedom.org", "internetpopculture.com", "inthenameofconfuciusmovie.com", "inxian.com", "iownyour.biz", "iownyour.org", "ipalter.com", "ipfire.org", "ipfs.io", "iphone4hongkong.com", "iphonehacks.com", "iphonetaiwan.org", "iphonix.fr", "ipicture.ru", "ipjetable.net", "ipobar.com", "ipoock.com", "iportal.me", "ippotv.com", "ipredator.se", "iptv.com.tw", "iptvbin.com", "ipvanish.com", "iqiyi.com", "iredmail.org", "irib.ir", "ironpython.net", "ironsocket.com", "is-a-hunter.com", "is.gd", "isaacmao.com", "isasecret.com", "isgreat.org", "islahhaber.net", "islam.org.hk", "islamawareness.net", "islamhouse.com", "islamicity.com", "islamicpluralism.org", "islamtoday.net", "ismaelan.com", "ismalltits.com", "ismprofessional.net", "isohunt.com", "israbox.com", "issuu.com", "istars.co.nz", "istarshine.com", "istef.info", "istiqlalhewer.com", "istockphoto.com", "isunaffairs.com", "isuntv.com", "isupportuyghurs.org", "itaboo.info", "itaiwan.gov.tw", "italiatibet.org", "itasoftware.com", "itemdb.com", "ithome.com.tw", "itsaol.com", "itshidden.com", "itsky.it", "itweet.net", "iu45.com", "iuhrdf.org", "iuksky.com", "ivacy.com", "iverycd.com", "ivpn.net", "ixquick.com", "ixxx.com", "iyouport.com", "iyouport.org", "izaobao.us", "izihost.org", "izles.net", "izlesem.org", "j.mp", "jable.tv", "jackjia.com", "jamaat.org", "jamestown.org", "jamyangnorbu.com", "jandyx.com", "janwongphoto.com", "japan-whores.com", "japantimes.co.jp", "jav.com", "jav101.com", "jav2be.com", "jav68.tv", "javakiba.org", "javbus.com", "javfor.me", "javhd.com", "javhip.com", "javhub.net", "javhuge.com", "javlibrary.com", "javmobile.net", "javmoo.com", "javmoo.xyz", "javseen.com", "javtag.com", "javzoo.com", "jbtalks.cc", "jbtalks.com", "jbtalks.my", "jcpenney.com", "jdwsy.com", "jeanyim.com", "jetos.com", "jex.com", "jfqu36.club", "jfqu37.xyz", "jgoodies.com", "jiangweiping.com", "jiaoyou8.com", "jichangtj.com", "jiehua.cz", "jiepang.com", "jieshibaobao.com", "jigglegifs.com", "jigong1024.com", "jigsy.com", "jihadology.net", "jiji.com", "jims.net", "jinbushe.org", "jingpin.org", "jingsim.org", "jinhai.de", "jinpianwang.com", "jinroukong.com", "jintian.net", "jinx.com", "jiruan.net", "jitouch.com", "jizzthis.com", "jjgirls.com", "jkb.cc", "jkforum.net", "jkub.com", "jma.go.jp", "jmscult.com", "joachims.org", "jobso.tv", "joinbbs.net", "joinclubhouse.com", "joinmastodon.org", "joins.com", "jornaldacidadeonline.com.br", "journalchretien.net", "journalofdemocracy.org", "joymiihub.com", "joyourself.com", "jp.net", "jpopforum.net", "jqueryui.com", "jsdelivr.net", "jshell.net", "jtvnw.net", "jubushoushen.com", "juhuaren.com", "jukujo-club.com", "juliepost.com", "juliereyc.com", "junauza.com", "june4commemoration.org", "junefourth-20.net", "jungleheart.com", "junglobal.net", "juoaa.com", "justdied.com", "justfreevpn.com", "justicefortenzin.org", "justmysocks1.net", "justpaste.it", "justtristan.com", "juyuange.org", "juziyue.com", "jwmusic.org", "jyxf.net", "k-doujin.net", "ka-wai.com", "kadokawa.co.jp", "kagyu.org", "kagyu.org.za", "kagyumonlam.org", "kagyunews.com.hk", "kagyuoffice.org", "kagyuoffice.org.tw", "kaiyuan.de", "kakao.com", "kalachakralugano.org", "kangye.org", "kankan.today", "kannewyork.com", "kanshifang.com", "kantie.org", "kanzhongguo.com", "kanzhongguo.eu", "kaotic.com", "karayou.com", "karkhung.com", "karmapa-teachings.org", "karmapa.org", "kawaiikawaii.jp", "kawase.com", "kba-tx.org", "kcoolonline.com", "kebrum.com", "kechara.com", "keepandshare.com", "keezmovies.com", "kendatire.com", "kendincos.net", "kenengba.com", "keontech.net", "kepard.com", "keso.cn", "kex.com", "keycdn.com", "khabdha.org", "khatrimaza.org", "khmusic.com.tw", "kichiku-doujinko.com", "kik.com", "killwall.com", "kimy.com.tw", "kindleren.com", "kingdomsalvation.org", "kinghost.com", "kingstone.com.tw", "kink.com", "kinmen.org.tw", "kinmen.travel", "kinokuniya.com", "kir.jp", "kissbbao.cn", "kiwi.kz", "kk-whys.co.jp", "kkbox.com", "kknews.cc", "klip.me", "kmuh.org.tw", "knowledgerush.com", "knowyourmeme.com", "kobo.com", "kobobooks.com", "kodingen.com", "kompozer.net", "konachan.com", "kone.com", "koolsolutions.com", "koornk.com", "koranmandarin.com", "korenan2.com", "kqes.net", "krtco.com.tw", "ksdl.org", "ksnews.com.tw", "kspcoin.com", "ktzhk.com", "kucoin.com", "kui.name", "kukuku.uk", "kun.im", "kurashsultan.com", "kurtmunger.com", "kusocity.com", "kwcg.ca", "kwok7.com", "kwongwah.com.my", "kxsw.life", "kyofun.com", "kyohk.net", "kyoyue.com", "kyzyhello.com", "kzeng.info", "la-forum.org", "labiennale.org", "ladbrokes.com", "lagranepoca.com", "lala.im", "lalulalu.com", "lama.com.tw", "lamayeshe.com", "lamenhu.com", "lamnia.co.uk", "lamrim.com", "landofhope.tv", "lanterncn.cn", "lantosfoundation.org", "laod.cn", "laogai.org", "laogairesearch.org", "laomiu.com", "laoyang.info", "laptoplockdown.com", "laqingdan.net", "larsgeorge.com", "lastcombat.com", "lastfm.es", "latelinenews.com", "lausan.hk", "law.com", "lbank.info", "le-vpn.com", "leafyvpn.net", "lecloud.net", "leeao.com.cn", "lefora.com", "left21.hk", "legalporno.com", "legsjapan.com", "leirentv.ca", "leisurecafe.ca", "leisurepro.com", "lematin.ch", "lemonde.fr", "lenwhite.com", "leorockwell.com", "lerosua.org", "lers.google", "lesoir.be", "lester850.info", "letou.com", "letscorp.net", "letsencrypt.org", "levyhsu.com", "lflink.com", "lflinkup.com", "lflinkup.net", "lflinkup.org", "lfpcontent.com", "lhakar.org", "lhasocialwork.org", "liangyou.net", "liangzhichuanmei.com", "lianyue.net", "liaowangxizang.net", "liberal.org.hk", "libertytimes.com.tw", "libraryinformationtechnology.com", "libredd.it", "lifemiles.com", "lighten.org.tw", "lighti.me", "lightnovel.cn", "lightyearvpn.com", "lihkg.com", "like.com", "limiao.net", "line-apps.com", "line-scdn.net", "line.me", "linglingfa.com", "lingvodics.com", "link-o-rama.com", "linkedin.com", "linkideo.com", "linksalpha.com", "linkuswell.com", "linpie.com", "linux.org.hk", "linuxtoy.org", "lionsroar.com", "lipuman.com", "liquiditytp.com", "liquidvpn.com", "list-manage.com", "listennotes.com", "listentoyoutube.com", "listorious.com", "lithium.com", "liu-xiaobo.org", "liudejun.com", "liuhanyu.com", "liujianshu.com", "liuxiaobo.net", "liuxiaotong.com", "live.com", "livecoin.net", "livedoor.jp", "liveleak.com", "livemint.com", "livestation.com", "livestream.com", "livevideo.com", "livingonline.us", "livingstream.com", "liwangyang.com", "lizhizhuangbi.com", "lkcn.net", "llss.me", "lncn.org", "load.to", "lobsangwangyal.com", "localbitcoins.com", "localdomain.ws", "localpresshk.com", "lockestek.com", "logbot.net", "logiqx.com", "logmein.com", "logos.com.hk", "londonchinese.ca", "longhair.hk", "longmusic.com", "longtermly.net", "longtoes.com", "lookpic.com", "looktoronto.com", "lotsawahouse.org", "lotuslight.org.hk", "lotuslight.org.tw", "loved.hk", "lovetvshow.com", "lpsg.com", "lrfz.com", "lrip.org", "lsd.org.hk", "lsforum.net", "lsm.org", "lsmchinese.org", "lsmkorean.org", "lsmradio.com", "lsmwebcast.com", "lsxszzg.com", "ltn.com.tw", "luckydesigner.space", "luke54.com", "luke54.org", "lupm.org", "lushstories.com", "luxebc.com", "lvhai.org", "lvv2.com", "lyfhk.net", "lzjscript.com", "lzmtnews.org", "m-sport.co.uk", "m-team.cc", "m.me", "macgamestore.com", "macrovpn.com", "macts.com.tw", "mad-ar.ch", "madewithcode.com", "madonna-av.com", "madrau.com", "madthumbs.com", "magic-net.info", "mahabodhi.org", "maiio.net", "mail-archive.com", "mail.ru", "mailchimp.com", "maildns.xyz", "maiplus.com", "maizhong.org", "makemymood.com", "makkahnewspaper.com", "malaysiakini.com", "mamingzhe.com", "manchukuo.net", "mandiant.com", "mangafox.com", "mangafox.me", "maniash.com", "manicur4ik.ru", "mansion.com", "mansionpoker.com", "manta.com", "manyvoices.news", "maplew.com", "marc.info", "marguerite.su", "martau.com", "martincartoons.com", "martinoei.com", "martsangkagyuofficial.org", "maruta.be", "marxist.com", "marxist.net", "marxists.org", "mash.to", "maskedip.com", "mastodon.cloud", "mastodon.host", "mastodon.social", "mastodon.xyz", "matainja.com", "material.io", "mathable.io", "mathiew-badimon.com", "matome-plus.com", "matome-plus.net", "matrix.org", "matsushimakaede.com", "matters.news", "mattwilcox.net", "maturejp.com", "maxing.jp", "mayimayi.com", "mcadforums.com", "mcaf.ee", "mcfog.com", "mcreasite.com", "md-t.org", "me.me", "meansys.com", "media.org.hk", "mediachinese.com", "mediafire.com", "mediafreakcity.com", "medium.com", "meetav.com", "meetup.com", "mefeedia.com", "meforum.org", "mefound.com", "mega.co.nz", "mega.io", "mega.nz", "megaproxy.com", "megarotic.com", "megavideo.com", "megurineluka.com", "meizhong.blog", "meizhong.report", "meltoday.com", "memehk.com", "memorybbs.com", "memri.org", "memrijttm.org", "mercatox.com", "mercdn.net", "mercyprophet.org", "mergersandinquisitions.org", "meridian-trust.org", "meripet.biz", "meripet.com", "merit-times.com.tw", "meshrep.com", "mesotw.com", "messenger.com", "metacafe.com", "metafilter.com", "metart.com", "metarthunter.com", "meteorshowersonline.com", "metro.taipei", "metrohk.com.hk", "metrolife.ca", "metroradio.com.hk", "mewe.com", "meyou.jp", "meyul.com", "mfxmedia.com", "mgoon.com", "mgstage.com", "mh4u.org", "mhradio.org", "michaelanti.com", "michaelmarketl.com", "microvpn.com", "middle-way.net", "mihk.hk", "mihr.com", "mihua.org", "mikesoltys.com", "mikocon.com", "milph.net", "milsurps.com", "mimiai.net", "mimivip.com", "mimivv.com", "mindrolling.org", "mingdemedia.org", "minghui-a.org", "minghui-b.org", "minghui-school.org", "minghui.or.kr", "minghui.org", "mingjinglishi.com", "mingjingnews.com", "mingjingtimes.com", "mingpao.com", "mingpaocanada.com", "mingpaomonthly.com", "mingpaonews.com", "mingpaony.com", "mingpaosf.com", "mingpaotor.com", "mingpaovan.com", "mingshengbao.com", "minhhue.net", "miniforum.org", "ministrybooks.org", "minzhuhua.net", "minzhuzhanxian.com", "minzhuzhongguo.org", "miroguide.com", "mirrorbooks.com", "mirrormedia.mg", "mist.vip", "mit.edu", "mitao.com.tw", "mitbbs.com", "mitbbsau.com", "mixero.com", "mixi.jp", "mixpod.com", "mixx.com", "mizzmona.com", "mjib.gov.tw", "mk5000.com", "mlcool.com", "mlzs.work", "mm-cg.com", "mmaaxx.com", "mmmca.com", "mnewstv.com", "mobatek.net", "mobile01.com", "mobileways.de", "moby.to", "mobypicture.com", "mod.io", "modernchinastudies.org", "moeaic.gov.tw", "moeerolibrary.com", "moegirl.org", "mofa.gov.tw", "mofaxiehui.com", "mofos.com", "mog.com", "mohu.club", "mohu.ml", "mohu.rocks", "mojim.com", "mol.gov.tw", "molihua.org", "monar.ch", "mondex.org", "money-link.com.tw", "moneyhome.biz", "monitorchina.org", "monitorware.com", "monlamit.org", "monster.com", "moodyz.com", "moon.fm", "moonbbs.com", "moonbingo.com", "moptt.tw", "morbell.com", "morningsun.org", "moroneta.com", "mos.ru", "motherless.com", "motiyun.com", "motor4ik.ru", "mousebreaker.com", "movements.org", "moviefap.com", "moztw.org", "mp3buscador.com", "mpettis.com", "mpfinance.com", "mpinews.com", "mponline.hk", "mqxd.org", "mrbasic.com", "mrbonus.com", "mrface.com", "mrslove.com", "mrtweet.com", "msa-it.org", "msguancha.com", "msha.gov", "msn.com", "msn.com.tw", "mswe1.org", "mthruf.com", "mtw.tl", "mubi.com", "muchosucko.com", "mullvad.net", "multiply.com", "multiproxy.org", "multiupload.com", "mummysgold.com", "murmur.tw", "musicade.net", "muslimvideo.com", "muzi.com", "muzi.net", "muzu.tv", "mvdis.gov.tw", "mvg.jp", "mx981.com", "my-formosa.com", "my-private-network.co.uk", "my-proxy.com", "my03.com", "my903.com", "myactimes.com", "myanniu.com", "myaudiocast.com", "myav.com.tw", "mybbs.us", "mybet.com", "myca168.com", "mycanadanow.com", "mychat.to", "mychinamyhome.com", "mychinanet.com", "mychinanews.com", "mychinese.news", "mycnnews.com", "mycould.com", "mydad.info", "myddns.com", "myeasytv.com", "myeclipseide.com", "myforum.com.hk", "myfreecams.com", "myfreepaysite.com", "myfreshnet.com", "myftp.info", "myftp.name", "myiphide.com", "mykomica.org", "mylftv.com", "mymaji.com", "mymediarom.com", "mymoe.moe", "mymom.info", "mymusic.net.tw", "mynetav.net", "mynetav.org", "mynumber.org", "myparagliding.com", "mypicture.info", "mypikpak.com", "mypop3.net", "mypop3.org", "mypopescu.com", "myradio.hk", "myreadingmanga.info", "mysecondarydns.com", "mysinablog.com", "myspace.com", "myspacecdn.com", "mytalkbox.com", "mytizi.com", "mywww.biz", "myz.info", "naacoalition.org", "nabble.com", "naitik.net", "nakido.com", "nakuz.com", "nalandabodhi.org", "nalandawest.org", "namgyal.org", "namgyalmonastery.org", "namsisi.com", "nanyang.com", "nanyangpost.com", "nanzao.com", "naol.ca", "naol.cc", "narod.ru", "nasa.gov", "nat.gov.tw", "nat.moe", "natado.com", "national-lottery.co.uk", "nationalawakening.org", "nationalgeographic.com", "nationalinterest.org", "nationalreview.com", "nationsonline.org", "nationwide.com", "naughtyamerica.com", "naver.jp", "navy.mil", "naweeklytimes.com", "nbc.com", "nbcnews.com", "nbtvpn.com", "nccwatch.org.tw", "nch.com.tw", "nchrd.org", "ncn.org", "ncol.com", "nde.de", "ndi.org", "ndr.de", "ned.org", "nekoslovakia.net", "neo-miracle.com", "neowin.net", "nepusoku.com", "nesnode.com", "net-fits.pro", "netalert.me", "netbig.com", "netbirds.com", "netcolony.com", "netfirms.com", "netflav.com", "netflix.com", "netflix.net", "netme.cc", "netsarang.com", "netsneak.com", "network54.com", "networkedblogs.com", "networktunnel.net", "neverforget8964.org", "new-3lunch.net", "new-akiba.com", "new96.ca", "newcenturymc.com", "newcenturynews.com", "newchen.com", "newgrounds.com", "newhighlandvision.com", "newipnow.com", "newlandmagazine.com.au", "newnews.ca", "news100.com.tw", "newsancai.com", "newschinacomment.org", "newscn.org", "newsdetox.ca", "newsdh.com", "newsmagazine.asia", "newsmax.com", "newspeak.cc", "newstamago.com", "newstapa.org", "newstarnet.com", "newstatesman.com", "newsweek.com", "newtaiwan.com.tw", "newtalk.tw", "newyorker.com", "newyorktimes.com", "nexon.com", "next11.co.jp", "nextdigital.com.hk", "nextmag.com.tw", "nextmedia.com", "nexton-net.jp", "nexttv.com.tw", "nf.id.au", "nfjtyd.com", "nflxext.com", "nflximg.com", "nflximg.net", "nflxso.net", "nflxvideo.net", "ng.mil", "nga.mil", "ngensis.com", "ngodupdongchung.com", "nhentai.net", "nhi.gov.tw", "nhk-ondemand.jp", "nic.google", "nic.gov", "nicovideo.jp", "nighost.org", "nightlife141.com", "nike.com", "nikkei.com", "ninecommentaries.com", "ning.com", "ninjacloak.com", "ninjaproxy.ninja", "nintendium.com", "ninth.biz", "nitter.cc", "nitter.net", "niu.moe", "niusnews.com", "njactb.org", "njuice.com", "nlfreevpn.com", "nmsl.website", "nnews.eu", "no-ip.com", "no-ip.org", "nobel.se", "nobelprize.org", "nobodycanstop.us", "nodesnoop.com", "nofile.io", "nokogiri.org", "nokola.com", "noodlevpn.com", "norbulingka.org", "nordstrom.com", "nordstromimage.com", "nordstromrack.com", "nordvpn.com", "notepad-plus-plus.org", "nottinghampost.com", "novelasia.com", "now.com", "now.im", "nownews.com", "nowtorrents.com", "noxinfluencer.com", "noypf.com", "npa.go.jp", "npa.gov.tw", "npnt.me", "nps.gov", "npsboost.com", "nradio.me", "nrk.no", "ns01.biz", "ns01.info", "ns01.us", "ns02.biz", "ns02.info", "ns02.us", "ns1.name", "ns2.name", "ns3.name", "nsc.gov.tw", "ntbk.gov.tw", "ntbna.gov.tw", "ntbt.gov.tw", "ntd.tv", "ntdtv.ca", "ntdtv.co.kr", "ntdtv.com", "ntdtv.com.tw", "ntdtv.cz", "ntdtv.org", "ntdtv.ru", "ntdtvla.com", "ntrfun.com", "ntsna.gov.tw", "ntu.edu.tw", "nu.nl", "nubiles.net", "nudezz.com", "nuexpo.com", "nukistream.com", "nurgo-software.com", "nusatrip.com", "nutaku.net", "nutsvpn.work", "nuuvem.com", "nuvid.com", "nuzcom.com", "nvdst.com", "nvquan.org", "nvtongzhisheng.org", "nwtca.org", "nyaa.eu", "nyaa.si", "nybooks.com", "nydus.ca", "nylon-angel.com", "nylonstockingsonline.com", "nypost.com", "nyt.com", "nytchina.com", "nytcn.me", "nytco.com", "nyti.ms", "nytimes.com", "nytimg.com", "nytlog.com", "nytstyle.com", "nzchinese.com", "nzchinese.net.nz", "oanda.com", "oann.com", "oauth.net", "observechina.net", "obutu.com", "ocaspro.com", "occupytiananmen.com", "oclp.hk", "ocreampies.com", "ocry.com", "october-review.org", "oculus.com", "oculuscdn.com", "odysee.com", "oex.com", "offbeatchina.com", "officeoftibet.com", "ofile.org", "ogaoga.org", "ogate.org", "ohchr.org", "ohmyrss.com", "oikos.com.tw", "oiktv.com", "oizoblog.com", "ok.ru", "okayfreedom.com", "okex.com", "okk.tw", "okx.com", "olabloga.pl", "old-cat.net", "olevod.com", "olumpo.com", "olympicwatch.org", "omct.org", "omgili.com", "omni7.jp", "omnitalk.com", "omnitalk.org", "omny.fm", "omy.sg", "on.cc", "on2.com", "onapp.com", "onedumb.com", "onejav.com", "onion.city", "onion.ly", "onlinecha.com", "onlineyoutube.com", "onlygayvideo.com", "onlytweets.com", "onmoon.com", "onmoon.net", "onmypc.biz", "onmypc.info", "onmypc.net", "onmypc.org", "onmypc.us", "onthehunt.com", "ontrac.com", "oopsforum.com", "open.com.hk", "openallweb.com", "opendemocracy.net", "opendn.xyz", "openervpn.in", "openid.net", "openleaks.org", "opensea.io", "opensource.google", "opentech.fund", "openvpn.net", "openvpn.org", "openwebster.com", "openwrt.org.cn", "opera-mini.net", "opera.com", "opus-gaming.com", "orchidbbs.com", "organcare.org.tw", "organharvestinvestigation.net", "organiccrap.com", "orgasm.com", "orgfree.com", "oricon.co.jp", "orient-doll.com", "orientaldaily.com.my", "orn.jp", "orzdream.com", "orzistic.org", "osfoora.com", "otcbtc.com", "otnd.org", "otto.de", "otzo.com", "ourdearamy.com", "ourhobby.com", "oursogo.com", "oursteps.com.au", "oursweb.net", "ourtv.hk", "over-blog.com", "overcast.fm", "overdaily.org", "overplay.net", "ovi.com", "ovpn.com", "ow.ly", "owind.com", "owl.li", "owltail.com", "oxfordscholarship.com", "oxid.it", "oyax.com", "oyghan.com", "ozchinese.com", "ozvoice.org", "ozxw.com", "ozyoyo.com", "pachosting.com", "pacificpoker.com", "packetix.net", "pacopacomama.com", "padmanet.com", "page.tl", "page2rss.com", "pages.dev", "pagodabox.com", "palacemoon.com", "paldengyal.com", "paljorpublications.com", "palmislife.com", "paltalk.com", "pandapow.co", "pandapow.net", "pandavpn-jp.com", "pandavpnpro.com", "pandora.com", "pandora.tv", "panluan.net", "panoramio.com", "pao-pao.net", "paper.li", "paperb.us", "paradisehill.cc", "paradisepoker.com", "parkansky.com", "parler.com", "parse.com", "parsevideo.com", "partycasino.com", "partypoker.com", "passion.com", "passiontimes.hk", "paste.ee", "pastebin.com", "pastie.org", "pathtosharepoint.com", "patreon.com", "paxful.com", "pbs.org", "pbwiki.com", "pbworks.com", "pbxes.com", "pbxes.org", "pcanywhere.net", "pcc.gov.tw", "pcdvd.com.tw", "pchome.com.tw", "pcij.org", "pcloud.com", "pcstore.com.tw", "pct.org.tw", "pdetails.com", "pdproxy.com", "peace.ca", "peacefire.org", "peacehall.com", "pearlher.org", "peeasian.com", "peing.net", "pekingduck.org", "pemulihan.or.id", "pen.io", "penchinese.com", "penchinese.net", "pengyulong.com", "penisbot.com", "pentalogic.net", "penthouse.com", "pentoy.hk", "peoplebookcafe.com", "peoplenews.tw", "peopo.org", "percy.in", "perfect-privacy.com", "perfectgirls.net", "periscope.tv", "persecutionblog.com", "persiankitty.com", "phapluan.org", "phayul.com", "philborges.com", "philly.com", "phmsociety.org", "phncdn.com", "phonegap.com", "photodharma.net", "photofocus.com", "phuquocservices.com", "picacomic.com", "picacomiccn.com", "picasaweb.com", "picidae.net", "picturedip.com", "picturesocial.com", "pimg.tw", "pin-cong.com", "pin6.com", "pincong.rocks", "ping.fm", "pinimg.com", "pinkrod.com", "pinoy-n.com", "pinterest.at", "pinterest.ca", "pinterest.co.kr", "pinterest.co.uk", "pinterest.com", "pinterest.com.mx", "pinterest.de", "pinterest.dk", "pinterest.fr", "pinterest.jp", "pinterest.nl", "pinterest.se", "pipii.tv", "piposay.com", "piraattilahti.org", "piring.com", "pixelqi.com", "pixiv.net", "pixnet.in", "pixnet.net", "pk.com", "pki.goog", "placemix.com", "playboy.com", "playboyplus.com", "player.fm", "playno1.com", "playpcesor.com", "plays.com.tw", "plexvpn.pro", "plixi.com", "plm.org.hk", "plunder.com", "plurk.com", "plus.codes", "plus28.com", "plusbb.com", "pmatehunter.com", "pmates.com", "po2b.com", "pobieramy.top", "podbean.com", "podcast.co", "podictionary.com", "pokerstars.com", "pokerstars.net", "pokerstrategy.com", "politicalchina.org", "politicalconsultation.org", "politiscales.net", "poloniex.com", "polymer-project.org", "polymerhk.com", "poolin.com", "popo.tw", "popvote.hk", "popxi.click", "popyard.com", "popyard.org", "porn.com", "porn2.com", "porn5.com", "pornbase.org", "pornerbros.com", "pornhd.com", "pornhost.com", "pornhub.com", "pornhubdeutsch.net", "pornmm.net", "pornoxo.com", "pornrapidshare.com", "pornsharing.com", "pornsocket.com", "pornstarclub.com", "porntube.com", "porntubenews.com", "porntvblog.com", "pornvisit.com", "port25.biz", "portablevpn.nl", "poskotanews.com", "post01.com", "post76.com", "post852.com", "postadult.com", "postimg.org", "potato.im", "potvpn.com", "power.com", "powerapple.com", "powercx.com", "powerphoto.org", "powerpointninja.com", "pp.ru", "prayforchina.net", "premeforwindows7.com", "premproxy.com", "presentationzen.com", "presidentlee.tw", "prestige-av.com", "pride.google", "printfriendly.com", "prism-break.org", "prisoneralert.com", "pritunl.com", "privacybox.de", "private.com", "privateinternetaccess.com", "privatepaste.com", "privatetunnel.com", "privatevpn.com", "privoxy.org", "procopytips.com", "project-syndicate.org", "prosiben.de", "proton.me", "protonvpn.com", "provideocoalition.com", "provpnaccounts.com", "proxfree.com", "proxifier.com", "proxlet.com", "proxomitron.info", "proxpn.com", "proxyanonimo.es", "proxydns.com", "proxylist.org.uk", "proxynetwork.org.uk", "proxypy.net", "proxyroad.com", "proxytunnel.net", "proyectoclubes.com", "prozz.net", "psblog.name", "pscp.tv", "pshvpn.com", "psiphon.ca", "psiphon3.com", "psiphontoday.com", "pt.im", "pts.org.tw", "ptt.cc", "pttgame.com", "pttvan.org", "pubu.com.tw", "puffinbrowser.com", "puffstore.com", "pullfolio.com", "punyu.com", "pure18.com", "pureapk.com", "pureconcepts.net", "pureinsight.org", "purepdf.com", "purevpn.com", "purplelotus.org", "pursuestar.com", "pushchinawall.com", "pussthecat.org", "pussyspace.com", "putihome.org", "putlocker.com", "putty.org", "puuko.com", "pwned.com", "pximg.net", "python.com", "python.com.tw", "pythonhackers.com", "pythonic.life", "pytorch.org", "qanote.com", "qgirl.com.tw", "qhigh.com", "qi-gong.me", "qianbai.tw", "qiandao.today", "qiangwaikan.com", "qiangyou.org", "qidian.ca", "qienkuen.org", "qiwen.lu", "qixianglu.cn", "qkshare.com", "qmzdd.com", "qoos.com", "qooza.hk", "qpoe.com", "qq.co.za", "qstatus.com", "qtrac.eu", "qtweeter.com", "quannengshen.org", "quantumbooter.net", "questvisual.com", "quitccp.net", "quitccp.org", "quora.com", "quoracdn.net", "quran.com", "quranexplorer.com", "qusi8.net", "qvodzy.org", "qx.net", "qxbbs.org", "qz.com", "r0.ru", "r18.com", "ra.gg", "radicalparty.org", "radiko.jp", "radio.garden", "radioaustralia.net.au", "radiohilight.net", "radioline.co", "radiotime.com", "radiovaticana.org", "radiovncr.com", "rael.org", "raggedbanner.com", "raidcall.com.tw", "raidtalk.com.tw", "rainbowplan.org", "raindrop.io", "raizoji.or.jp", "ramcity.com.au", "rangwang.biz", "rangzen.com", "rangzen.net", "rangzen.org", "ranxiang.com", "ranyunfei.com", "rapbull.net", "rapidgator.net", "rapidmoviez.com", "rapidvpn.com", "rarbgprx.org", "raremovie.cc", "raremovie.net", "rateyourmusic.com", "rationalwiki.org", "rawgit.com", "rawgithub.com", "raxcdn.com", "razyboard.com", "rcinet.ca", "rd.com", "rdio.com", "read01.com", "read100.com", "readingtimes.com.tw", "readmoo.com", "readydown.com", "realcourage.org", "realitykings.com", "realraptalk.com", "realsexpass.com", "reason.com", "rebatesrule.net", "recaptcha.net", "recordhistory.org", "recovery.org.tw", "recoveryversion.com.tw", "recoveryversion.org", "red-lang.org", "redballoonsolidarity.org", "redbubble.com", "redchinacn.net", "redchinacn.org", "redd.it", "reddit.com", "redditlist.com", "redditmedia.com", "redditstatic.com", "redhotlabs.com", "redtube.com", "referer.us", "reflectivecode.com", "registry.google", "relaxbbs.com", "relay.com.tw", "releaseinternational.org", "religionnews.com", "religioustolerance.org", "renminbao.com", "renyurenquan.org", "rerouted.org", "research.google", "resilio.com", "resistchina.org", "retweeteffect.com", "retweetist.com", "retweetrank.com", "reuters.com", "reutersmedia.net", "revleft.com", "revocationcheck.com", "revver.com", "rfa.org", "rfachina.com", "rfamobile.org", "rfaweb.org", "rferl.org", "rfi.fr", "rfi.my", "rightbtc.com", "rightster.com", "rigpa.org", "riku.me", "rileyguide.com", "riseup.net", "ritouki.jp", "ritter.vg", "rixcloud.com", "rixcloud.us", "rlwlw.com", "rmjdw.com", "rmjdw132.info", "roadshow.hk", "roboforex.com", "robustnessiskey.com", "rocket-inc.net", "rocketbbs.com", "rocksdb.org", "rojo.com", "rolfoundation.org", "rolia.net", "rolsociety.org", "ronjoneswriter.com", "roodo.com", "rosechina.net", "rotten.com", "rsdlmonitor.com", "rsf-chinese.org", "rsf.org", "rsgamen.org", "rsshub.app", "rssing.com", "rssmeme.com", "rtalabel.org", "rthk.hk", "rthk.org.hk", "rti.org.tw", "rti.tw", "rtycminnesota.org", "ruanyifeng.com", "rukor.org", "rule34.xxx", "runbtx.com", "rushbee.com", "rusvpn.com", "ruten.com.tw", "rutracker.net", "rutube.ru", "ruyiseek.com", "rxhj.net", "s-cute.com", "s-dragon.org", "s1heng.com", "s1s1s1.com", "s4miniarchive.com", "s8forum.com", "sa.com", "saboom.com", "sacks.com", "sacom.hk", "sadistic-v.com", "sadpanda.us", "safechat.com", "safeguarddefenders.com", "safervpn.com", "safety.google", "saintyculture.com", "saiq.me", "sakuralive.com", "sakya.org", "salvation.org.hk", "samair.ru", "sambhota.org", "sandscotaicentral.com", "sankei.com", "sanmin.com.tw", "sans.edu", "sapikachu.net", "saveliuxiaobo.com", "savemedia.com", "savethedate.foo", "savethesounds.info", "savetibet.de", "savetibet.fr", "savetibet.nl", "savetibet.org", "savetibet.ru", "savetibetstore.org", "saveuighur.org", "savevid.com", "say2.info", "sbme.me", "sbs.com.au", "scasino.com", "schema.org", "sciencemag.org", "sciencenets.com", "scieron.com", "scmp.com", "scmpchinese.com", "scramble.io", "scribd.com", "scriptspot.com", "search.com", "search.xxx", "searchtruth.com", "searx.me", "seatguru.com", "seattlefdc.com", "secretchina.com", "secretgarden.no", "secretsline.biz", "secureservercdn.net", "securetunnel.com", "securityinabox.org", "securitykiss.com", "seed4.me", "seehua.com", "seesmic.com", "seevpn.com", "seezone.net", "sejie.com", "sellclassics.com", "sendsmtp.com", "sendspace.com", "sensortower.com", "seraph.me", "servehttp.com", "serveuser.com", "serveusers.com", "sesawe.net", "sesawe.org", "sethwklein.net", "setn.com", "settv.com.tw", "setty.com.tw", "sevenload.com", "sex-11.com", "sex.com", "sex3.com", "sex8.cc", "sexandsubmission.com", "sexbot.com", "sexhu.com", "sexhuang.com", "sexidude.com", "sexinsex.net", "sextvx.com", "sexxxy.biz", "sf.net", "sfileydy.com", "sfshibao.com", "sftindia.org", "sftuk.org", "shadeyouvpn.com", "shadow.ma", "shadowsky.xyz", "shadowsocks-r.com", "shadowsocks.asia", "shadowsocks.be", "shadowsocks.com", "shadowsocks.com.hk", "shadowsocks.org", "shadowsocks9.com", "shafaqna.com", "shahit.biz", "shambalapost.com", "shambhalasun.com", "shangfang.org", "shapeservices.com", "sharebee.com", "sharecool.org", "sharpdaily.com.hk", "sharpdaily.hk", "sharpdaily.tw", "shat-tibet.com", "shattered.io", "sheikyermami.com", "shellfire.de", "shemalez.com", "shenshou.org", "shenyun.com", "shenyunperformingarts.org", "shenyunshop.com", "shenzhoufilm.com", "shenzhouzhengdao.org", "sherabgyaltsen.com", "shiatv.net", "shicheng.org", "shiksha.com", "shinychan.com", "shipcamouflage.com", "shireyishunjian.com", "shitaotv.org", "shixiao.org", "shizhao.org", "shkspr.mobi", "shodanhq.com", "shooshtime.com", "shop2000.com.tw", "shopee.tw", "shopping.com", "showhaotu.com", "showtime.jp", "showwe.tw", "shutterstock.com", "shvoong.com", "shwchurch.org", "shwchurch3.com", "siddharthasintent.org", "sidelinesnews.com", "sidelinessportseatery.com", "sierrafriendsoftibet.org", "signal.org", "sijihuisuo.club", "sijihuisuo.com", "silkbook.com", "simbolostwitter.com", "simplecd.org", "simpleproductivityblog.com", "sina.com", "sina.com.hk", "sina.com.tw", "sinchew.com.my", "singaporepools.com.sg", "singfortibet.com", "singpao.com.hk", "singtao.ca", "singtao.com", "singtaousa.com", "sino-monthly.com", "sinoants.com", "sinoca.com", "sinocast.com", "sinocism.com", "sinoinsider.com", "sinomontreal.ca", "sinonet.ca", "sinopitt.info", "sinoquebec.com", "sipml5.org", "sis.xxx", "sis001.com", "sis001.us", "site2unblock.com", "site90.net", "sitebro.tw", "sitekreator.com", "sitemaps.org", "six-degrees.io", "sixth.biz", "sjrt.org", "sjum.cn", "sketchappsources.com", "skimtube.com", "skk.moe", "skybet.com", "skyking.com.tw", "skykiwi.com", "skynet.be", "skype.com", "skyvegas.com", "skyxvpn.com", "slacker.com", "slandr.net", "slaytizle.com", "sleazydream.com", "slheng.com", "slickvpn.com", "slideshare.net", "slime.com.tw", "slinkset.com", "slutload.com", "slutmoonbeam.com", "slyip.com", "slyip.net", "sm-miracle.com", "smartdnsproxy.com", "smarthide.com", "smartmailcloud.com", "smchbooks.com", "smh.com.au", "smhric.org", "smith.edu", "smyxy.org", "snapchat.com", "snaptu.com", "sndcdn.com", "sneakme.net", "snowlionpub.com", "so-net.net.tw", "sobees.com", "soc.mil", "socialblade.com", "socialwhale.com", "socks-proxy.net", "sockscap64.com", "sockslist.net", "socrec.org", "sod.co.jp", "softether-download.com", "softether.co.jp", "softether.org", "softfamous.com", "softlayer.net", "softnology.biz", "softsmirror.cf", "softwarebychuck.com", "sogclub.com", "sogoo.org", "sogrady.me", "soh.tw", "sohcradio.com", "sohfrance.org", "soifind.com", "sokamonline.com", "sokmil.com", "solana.com", "solidaritetibet.org", "solidfiles.com", "solv.finance", "somee.com", "songjianjun.com", "sonicbbs.cc", "sonidodelaesperanza.org", "sopcast.com", "sopcast.org", "sophos.com", "sorazone.net", "sorting-algorithms.com", "sos.org", "sosreader.com", "sostibet.org", "sou-tong.org", "soubory.com", "soul-plus.net", "soulcaliburhentai.net", "soumo.info", "soundcloud.com", "soundofhope.kr", "soundofhope.org", "soup.io", "soupofmedia.com", "sourceforge.net", "sourcewadio.com", "south-plus.org", "southnews.com.tw", "sowers.org.hk", "sowiki.net", "soylent.com", "soylentnews.org", "spankbang.com", "spankingtube.com", "spankwire.com", "spb.com", "speakerdeck.com", "speedify.com", "spem.at", "spencertipping.com", "spendee.com", "spicevpn.com", "spideroak.com", "spike.com", "spotflux.com", "spotify.com", "spreadshirt.es", "spring4u.info", "springboardplatform.com", "sprite.org", "sproutcore.com", "sproxy.info", "squirly.info", "squirrelvpn.com", "srocket.us", "ss-link.com", "ssglobal.co", "ssglobal.me", "ssh91.com", "ssl443.org", "sspanel.net", "sspro.ml", "ssr.tools", "ssrshare.com", "sss.camp", "sstm.moe", "sstmlt.moe", "sstmlt.net", "stackoverflow.com", "stage64.hk", "standupfortibet.org", "standwithhk.org", "stanford.edu", "starfishfx.com", "starp2p.com", "startpage.com", "startuplivingchina.com", "stat.gov.tw", "state.gov", "static-economist.com", "staticflickr.com", "statueofdemocracy.org", "stboy.net", "stc.com.sa", "steamcommunity.com", "steampowered.com", "steel-storm.com", "steemit.com", "steganos.com", "steganos.net", "stepchina.com", "stephaniered.com", "stgloballink.com", "stheadline.com", "sthoo.com", "stickam.com", "stickeraction.com", "stileproject.com", "sto.cc", "stoporganharvesting.org", "stoptibetcrisis.net", "storagenewsletter.com", "stories.google", "storify.com", "storm.mg", "stormmediagroup.com", "stoweboyd.com", "straitstimes.com", "stranabg.com", "straplessdildo.com", "streamable.com", "streamate.com", "streamingthe.net", "streema.com", "streetvoice.com", "strikingly.com", "strongvpn.com", "strongwindpress.com", "student.tw", "studentsforafreetibet.org", "stumbleupon.com", "stupidvideos.com", "substack.com", "successfn.com", "sueddeutsche.de", "sugarsync.com", "sugobbs.com", "sugumiru18.com", "suissl.com", "sulian.me", "summify.com", "sumrando.com", "sun1911.com", "sundayguardianlive.com", "sunmedia.ca", "sunporno.com", "sunskyforum.com", "sunta.com.tw", "sunvpn.net", "suoluo.org", "supchina.com", "superfreevpn.com", "superokayama.com", "superpages.com", "supervpn.net", "superzooi.com", "suppig.net", "suprememastertv.com", "surfeasy.com", "surfeasy.com.au", "surfshark.com", "suroot.com", "surrenderat20.net", "sustainability.google", "svsfx.com", "swagbucks.com", "swissinfo.ch", "swissvpn.net", "switch1.jp", "switchvpn.net", "sydneytoday.com", "sylfoundation.org", "syncback.com", "synergyse.com", "sysresccd.org", "sytes.net", "syx86.cn", "syx86.com", "szbbs.net", "szetowah.org.hk", "t-g.com", "t.co", "t.me", "t35.com", "t66y.com", "t91y.com", "taa-usa.org", "taaze.tw", "tablesgenerator.com", "tabtter.jp", "tacem.org", "taconet.com.tw", "taedp.org.tw", "tafm.org", "tagwa.org.au", "tagwalk.com", "tahr.org.tw", "taipei.gov.tw", "taipeisociety.org", "taipeitimes.com", "taiwan-sex.com", "taiwanbible.com", "taiwancon.com", "taiwandaily.net", "taiwandc.org", "taiwanhot.net", "taiwanjobs.gov.tw", "taiwanjustice.com", "taiwanjustice.net", "taiwankiss.com", "taiwannation.com", "taiwannation.com.tw", "taiwanncf.org.tw", "taiwannews.com.tw", "taiwanonline.cc", "taiwantp.net", "taiwantt.org.tw", "taiwanus.net", "taiwanyes.com", "talk853.com", "talkboxapp.com", "talkcc.com", "talkonly.net", "tamiaode.tk", "tampabay.com", "tanc.org", "tangben.com", "tangren.us", "taoism.net", "taolun.info", "tapanwap.com", "tapatalk.com", "taragana.com", "target.com", "tascn.com.au", "taup.net", "taup.org.tw", "taweet.com", "tbcollege.org", "tbi.org.hk", "tbicn.org", "tbjyt.org", "tbpic.info", "tbrc.org", "tbs-rainbow.org", "tbsec.org", "tbsmalaysia.org", "tbsn.org", "tbsseattle.org", "tbssqh.org", "tbswd.org", "tbtemple.org.uk", "tbthouston.org", "tccwonline.org", "tcewf.org", "tchrd.org", "tcnynj.org", "tcpspeed.co", "tcpspeed.com", "tcsofbc.org", "tcsovi.org", "tdesktop.com", "tdm.com.mo", "teachparentstech.org", "teamamericany.com", "technews.tw", "techspot.com", "techviz.net", "teck.in", "teco-hk.org", "teco-mo.org", "teddysun.com", "teeniefuck.net", "teensinasia.com", "tehrantimes.com", "telecomspace.com", "telegra.ph", "telegram.dog", "telegram.me", "telegram.org", "telegramdownload.com", "telegraph.co.uk", "telesco.pe", "tellme.pw", "tenacy.com", "tensorflow.org", "tenzinpalmo.com", "terabox.com", "tew.org", "textnow.me", "tfhub.dev", "tfiflve.com", "thaicn.com", "thb.gov.tw", "theatlantic.com", "theatrum-belli.com", "theaustralian.com.au", "thebcomplex.com", "theblaze.com", "theblemish.com", "thebobs.com", "thebodyshop-usa.com", "thechinabeat.org", "thechinacollection.org", "thechinastory.org", "theconversation.com", "thedalailamamovie.com", "thediplomat.com", "thedw.us", "theepochtimes.com", "thefacebook.com", "thefrontier.hk", "thegay.com", "thegioitinhoc.vn", "thegly.com", "theguardian.com", "thehots.info", "thehousenews.com", "thehun.net", "theinitium.com", "themoviedb.org", "thenewslens.com", "thepiratebay.org", "theporndude.com", "theportalwiki.com", "theprint.in", "thereallove.kr", "therock.net.nz", "thesaturdaypaper.com.au", "thestandnews.com", "thetibetcenter.org", "thetibetconnection.org", "thetibetmuseum.org", "thetibetpost.com", "thetinhat.com", "thetrotskymovie.com", "thetvdb.com", "thevivekspot.com", "thewgo.org", "theync.com", "thinkgeek.com", "thinkingtaiwan.com", "thinkwithgoogle.com", "thisav.com", "thlib.org", "thomasbernhard.org", "thongdreams.com", "threatchaos.com", "throughnightsfire.com", "thumbzilla.com", "thywords.com", "thywords.com.tw", "tiananmenduizhi.com", "tiananmenmother.org", "tiananmenuniv.com", "tiananmenuniv.net", "tiandixing.org", "tianhuayuan.com", "tianlawoffice.com", "tianti.io", "tiantibooks.org", "tianyantong.org.cn", "tianzhu.org", "tibet-envoy.eu", "tibet-foundation.org", "tibet-house-trust.co.uk", "tibet-initiative.de", "tibet-munich.de", "tibet.a.se", "tibet.at", "tibet.ca", "tibet.com", "tibet.fr", "tibet.net", "tibet.nu", "tibet.org", "tibet.org.tw", "tibet.sk", "tibet.to", "tibet3rdpole.org", "tibetaction.net", "tibetaid.org", "tibetalk.com", "tibetan-alliance.org", "tibetan.fr", "tibetanaidproject.org", "tibetanarts.org", "tibetanbuddhistinstitute.org", "tibetancommunity.org", "tibetancommunityuk.net", "tibetanculture.org", "tibetanentrepreneurs.org", "tibetanfeministcollective.org", "tibetanhealth.org", "tibetanjournal.com", "tibetanlanguage.org", "tibetanliberation.org", "tibetanpaintings.com", "tibetanphotoproject.com", "tibetanpoliticalreview.org", "tibetanreview.net", "tibetansports.org", "tibetanwomen.org", "tibetanyouth.org", "tibetanyouthcongress.org", "tibetcharity.dk", "tibetcharity.in", "tibetchild.org", "tibetcity.com", "tibetcollection.com", "tibetcorps.org", "tibetexpress.net", "tibetfocus.com", "tibetfund.org", "tibetgermany.com", "tibetgermany.de", "tibethaus.com", "tibetheritagefund.org", "tibethouse.jp", "tibethouse.org", "tibethouse.us", "tibetinfonet.net", "tibetjustice.org", "tibetkomite.dk", "tibetmuseum.org", "tibetnetwork.org", "tibetoffice.ch", "tibetoffice.com.au", "tibetoffice.eu", "tibetoffice.org", "tibetonline.com", "tibetonline.tv", "tibetoralhistory.org", "tibetpolicy.eu", "tibetrelieffund.co.uk", "tibetsites.com", "tibetsociety.com", "tibetsun.com", "tibetsupportgroup.org", "tibetswiss.ch", "tibettelegraph.com", "tibettimes.net", "tibetwrites.org", "ticket.com.tw", "tigervpn.com", "tiktok.com", "tiltbrush.com", "timdir.com", "time.com", "timesnownews.com", "timsah.com", "timtales.com", "tinc-vpn.org", "tiney.com", "tineye.com", "tintuc101.com", "tiny.cc", "tinychat.com", "tinypaste.com", "tipas.net", "tipo.gov.tw", "tistory.com", "tkcs-collins.com", "tl.gd", "tma.co.jp", "tmagazine.com", "tmdfish.com", "tmi.me", "tmpp.org", "tnaflix.com", "tngrnow.com", "tngrnow.net", "tnp.org", "to-porno.com", "togetter.com", "toh.info", "tokyo-247.com", "tokyo-hot.com", "tokyo-porn-tube.com", "tokyocn.com", "tomonews.net", "tongil.or.kr", "tono-oka.jp", "tonyyan.net", "toodoc.com", "toonel.net", "top.tv", "top10vpn.com", "top81.ws", "topbtc.com", "topnews.in", "toppornsites.com", "topshareware.com", "topsy.com", "toptip.ca", "tora.to", "torcn.com", "torguard.net", "torlock.com", "torproject.org", "torrentkitty.tv", "torrentprivacy.com", "torrentproject.se", "torrenty.org", "torrentz.eu", "torvpn.com", "totalvpn.com", "toutiaoabc.com", "towngain.com", "toypark.in", "toythieves.com", "toytractorshow.com", "tparents.org", "tpi.org.tw", "tracfone.com", "tradingview.com", "translate.goog", "translate.google", "transparency.org", "treemall.com.tw", "trendsmap.com", "trialofccp.org", "trickip.net", "trickip.org", "trimondi.de", "tronscan.org", "trouw.nl", "trt.net.tr", "trtc.com.tw", "truebuddha-md.org", "trulyergonomic.com", "truthontour.org", "truthsocial.com", "truveo.com", "tryheart.jp", "tsctv.net", "tsemtulku.com", "tsquare.tv", "tsu.org.tw", "tsunagarumon.com", "tt1069.com", "tttan.com", "ttv.com.tw", "ttvnw.net", "tu8964.com", "tubaholic.com", "tube.com", "tube8.com", "tube911.com", "tubecup.com", "tubegals.com", "tubeislam.com", "tubepornclassic.com", "tubestack.com", "tubewolf.com", "tuibeitu.net", "tuidang.net", "tuidang.org", "tuidang.se", "tuitui.info", "tuitwit.com", "tumblr.com", "tumutanzi.com", "tumview.com", "tunein.com", "tunnelbear.com", "tunnelblick.net", "tunnelr.com", "tunsafe.com", "turansam.org", "turbobit.net", "turbohide.com", "turbotwitter.com", "turkistantimes.com", "turntable.fm", "tushycash.com", "tutanota.com", "tuvpn.com", "tuzaijidi.com", "tv.com", "tv.google", "tvants.com", "tvb.com", "tvboxnow.com", "tvbs.com.tw", "tvider.com", "tvmost.com.hk", "tvplayvideos.com", "tvunetworks.com", "tw-blog.com", "tw-npo.org", "tw01.org", "twaitter.com", "twapperkeeper.com", "twaud.io", "twavi.com", "twbbs.net.tw", "twbbs.org", "twbbs.tw", "twblogger.com", "tweepguide.com", "tweeplike.me", "tweepmag.com", "tweepml.org", "tweetbackup.com", "tweetboard.com", "tweetboner.biz", "tweetcs.com", "tweetdeck.com", "tweetedtimes.com", "tweetmylast.fm", "tweetphoto.com", "tweetrans.com", "tweetree.com", "tweettunnel.com", "tweetwally.com", "tweetymail.com", "tweez.net", "twelve.today", "twerkingbutt.com", "twftp.org", "twgreatdaily.com", "twibase.com", "twibble.de", "twibbon.com", "twibs.com", "twicountry.org", "twicsy.com", "twiends.com", "twifan.com", "twiffo.com", "twiggit.org", "twilightsex.com", "twilio.com", "twilog.org", "twimbow.com", "twimg.com", "twindexx.com", "twip.me", "twipple.jp", "twishort.com", "twistar.cc", "twister.net.co", "twisterio.com", "twisternow.com", "twistory.net", "twit2d.com", "twitbrowser.net", "twitcause.com", "twitch.tv", "twitchcdn.net", "twitgether.com", "twitgoo.com", "twitiq.com", "twitlonger.com", "twitmania.com", "twitoaster.com", "twitonmsn.com", "twitpic.com", "twitstat.com", "twittbot.net", "twitter.com", "twitter.jp", "twitter4j.org", "twittercounter.com", "twitterfeed.com", "twittergadget.com", "twitterkr.com", "twittermail.com", "twitterrific.com", "twittertim.es", "twitthat.com", "twitturk.com", "twitturly.com", "twitvid.com", "twitzap.com", "twiyia.com", "twnorth.org.tw", "twreporter.org", "twskype.com", "twstar.net", "twt.tl", "twtkr.com", "twtrland.com", "twttr.com", "twurl.nl", "twyac.org", "txxx.com", "tycool.com", "typepad.com", "typora.io", "u15.info", "u9un.com", "ub0.cc", "ubddns.org", "uberproxy.net", "uc-japan.org", "ucam.org", "ucanews.com", "ucdc1998.org", "uchicago.edu", "uderzo.it", "udn.com", "udn.com.tw", "udnbkk.com", "uforadio.com.tw", "ufreevpn.com", "ugo.com", "uhdwallpapers.org", "uhrp.org", "uighur.nl", "uighurbiz.net", "uk.to", "ukcdp.co.uk", "ukliferadio.co.uk", "uku.im", "ulike.net", "ulop.net", "ultravpn.fr", "ultraxs.com", "umich.edu", "unblock-us.com", "unblockdmm.com", "unblocker.yt", "unblocksit.es", "uncyclomedia.org", "uncyclopedia.hk", "uncyclopedia.tw", "underwoodammo.com", "unholyknight.com", "uni.cc", "unicode.org", "unification.net", "unification.org.tw", "unirule.cloud", "unitedsocialpress.com", "unix100.com", "unknownspace.org", "unodedos.com", "unpo.org", "unseen.is", "unstable.icu", "untraceable.us", "uocn.org", "updatestar.com", "upghsbc.com", "upholdjustice.org", "upload4u.info", "uploaded.net", "uploaded.to", "uploadstation.com", "upmedia.mg", "upornia.com", "uproxy.org", "uptodown.com", "upwill.org", "ur7s.com", "uraban.me", "urbandictionary.com", "urbansurvival.com", "urchin.com", "url.com.tw", "url.tw", "urlborg.com", "urlparser.com", "us.to", "usacn.com", "usaip.eu", "usc.edu", "uscnpm.org", "usembassy.gov", "usfk.mil", "usma.edu", "usmc.mil", "usocctn.com", "uspto.gov", "ustibetcommittee.org", "ustream.tv", "usus.cc", "utopianpal.com", "uu-gg.com", "uukanshu.com", "uvwxyz.xyz", "uwants.com", "uwants.net", "uyghur-j.org", "uyghur.co.uk", "uyghuraa.org", "uyghuramerican.org", "uyghurbiz.org", "uyghurcanadian.ca", "uyghurcongress.org", "uyghurpen.org", "uyghurpress.com", "uyghurstudies.org", "uyghurtribunal.com", "uygur.org", "uymaarip.com", "v2ex.com", "v2fly.org", "v2ray.com", "v2raycn.com", "v2raytech.com", "valeursactuelles.com", "van001.com", "van698.com", "vanemu.cn", "vanilla-jp.com", "vanpeople.com", "vansky.com", "vaticannews.va", "vatn.org", "vcf-online.org", "vcfbuilder.org", "vegasred.com", "velkaepocha.sk", "venbbs.com", "venchina.com", "venetianmacao.com", "ventureswell.com", "veoh.com", "vercel.app", "verizon.net", "vermonttibet.org", "versavpn.com", "verybs.com", "vevo.com", "vft.com.tw", "viber.com", "vica.info", "victimsofcommunism.org", "vid.me", "vidble.com", "videobam.com", "videodetective.com", "videomega.tv", "videomo.com", "videopediaworld.com", "videopress.com", "vidinfo.org", "vietdaikynguyen.com", "vijayatemple.org", "vilavpn.com", "vimeo.com", "vimperator.org", "vincnd.com", "vine.co", "vinniev.com", "vip-enterprise.com", "virginia.edu", "virtualrealporn.com", "visibletweets.com", "visiontimes.com", "vital247.org", "viu.com", "viu.tv", "vivahentai4u.net", "vivaldi.com", "vivatube.com", "vivthomas.com", "vizvaz.com", "vjav.com", "vjmedia.com.hk", "vllcs.org", "vmixcore.com", "vmpsoft.com", "vnet.link", "voa.mobi", "voacambodia.com", "voacantonese.com", "voachinese.com", "voachineseblog.com", "voagd.com", "voaindonesia.com", "voanews.com", "voatibetan.com", "voatibetanenglish.com", "vocativ.com", "vocn.tv", "vocus.cc", "voicettank.org", "vot.org", "vovo2000.com", "voxer.com", "voy.com", "vpn.ac", "vpn4all.com", "vpnaccount.org", "vpnaccounts.com", "vpnbook.com", "vpncomparison.org", "vpncoupons.com", "vpncup.com", "vpndada.com", "vpnfan.com", "vpnfire.com", "vpnfires.biz", "vpnforgame.net", "vpngate.jp", "vpngate.net", "vpngratis.net", "vpnhq.com", "vpnhub.com", "vpninja.net", "vpnintouch.com", "vpnintouch.net", "vpnjack.com", "vpnmaster.com", "vpnmentor.com", "vpnpick.com", "vpnpop.com", "vpnpronet.com", "vpnreactor.com", "vpnreviewz.com", "vpnsecure.me", "vpnshazam.com", "vpnshieldapp.com", "vpnsp.com", "vpntraffic.com", "vpntunnel.com", "vpnuk.info", "vpnunlimitedapp.com", "vpnvip.com", "vpnworldwide.com", "vporn.com", "vpser.net", "vraiesagesse.net", "vrmtr.com", "vrsmash.com", "vs.com", "vtunnel.com", "vuku.cc", "vultryhw.com", "vzw.com", "w3.org", "w3schools.com", "waffle1999.com", "wahas.com", "waigaobu.com", "waikeung.org", "wailaike.net", "wainao.me", "waiwaier.com", "wallmama.com", "wallornot.org", "wallpapercasa.com", "wallproxy.com", "wallsttv.com", "waltermartin.com", "waltermartin.org", "wan-press.org", "wanderinghorse.net", "wangafu.net", "wangjinbo.org", "wanglixiong.com", "wango.org", "wangruoshui.net", "wangruowang.org", "want-daily.com", "wanz-factory.com", "wapedia.mobi", "warehouse333.com", "warroom.org", "waselpro.com", "washeng.net", "washingtonpost.com", "watch8x.com", "watchinese.com", "watchmygf.net", "watchout.tw", "wattpad.com", "wav.tv", "waveprotocol.org", "waymo.com", "wda.gov.tw", "wdf5.com", "wealth.com.tw", "wearehairy.com", "wearn.com", "weather.com.hk", "web.dev", "web2project.net", "webbang.net", "webevader.org", "webfreer.com", "webjb.org", "weblagu.com", "webmproject.org", "webpack.de", "webrtc.org", "webrush.net", "webs-tv.net", "websitepulse.com", "websnapr.com", "webwarper.net", "webworkerdaily.com", "wechatlawsuit.com", "weekmag.info", "wefightcensorship.org", "wefong.com", "weiboleak.com", "weihuo.org", "weijingsheng.org", "weiming.info", "weiquanwang.org", "weisuo.ws", "welovecock.com", "welt.de", "wemigrate.org", "wengewang.com", "wengewang.org", "wenhui.ch", "wenweipo.com", "wenxuecity.com", "wenyunchao.com", "wenzhao.ca", "westca.com", "westernshugdensociety.org", "westernwolves.com", "westkit.net", "westpoint.edu", "wetplace.com", "wetpussygames.com", "wexiaobo.org", "wezhiyong.org", "wezone.net", "wforum.com", "wha.la", "whatblocked.com", "whatbrowser.org", "whatsapp.com", "whatsapp.net", "whatsonweibo.com", "wheatseeds.org", "wheelockslatin.com", "whereiswerner.com", "wheretowatch.com", "whippedass.com", "whispersystems.org", "whodns.xyz", "whoer.net", "whotalking.com", "whylover.com", "whyx.org", "widevine.com", "wikaba.com", "wikia.com", "wikileaks-forum.com", "wikileaks.ch", "wikileaks.com", "wikileaks.de", "wikileaks.eu", "wikileaks.lu", "wikileaks.org", "wikileaks.pl", "wikilivres.info", "wikimapia.org", "wikimedia.org", "wikinews.org", "wikipedia.org", "wikiquote.org", "wikisource.org", "wikiwand.com", "wikiwiki.jp", "wildammo.com", "williamhill.com", "willw.net", "windowsphoneme.com", "windscribe.com", "windy.com", "wingamestore.com", "wingy.site", "winning11.com", "winwhispers.info", "wionews.com", "wire.com", "wiredbytes.com", "wiredpen.com", "wireguard.com", "wisdompubs.org", "wisevid.com", "wistia.com", "withgoogle.com", "withyoutube.com", "witnessleeteaching.com", "witopia.net", "wizcrafts.net", "wjbk.org", "wn.com", "wnacg.com", "wnacg.org", "wo.tc", "woeser.com", "woesermiddle-way.net", "wokar.org", "wolfax.com", "wombo.ai", "woolyss.com", "woopie.jp", "woopie.tv", "wordpress.com", "workatruna.com", "workerdemo.org.hk", "workerempowerment.org", "workers.dev", "workersthebig.net", "workflow.is", "worldcat.org", "worldjournal.com", "worldvpn.net", "wow-life.net", "wow.com", "wowgirls.com", "wowhead.com", "wowlegacy.ml", "wowporn.com", "wowrk.com", "woxinghuiguo.com", "woyaolian.org", "wozy.in", "wp.com", "wpoforum.com", "wqyd.org", "wrchina.org", "wretch.cc", "wsj.com", "wsj.net", "wsjhk.com", "wtbn.org", "wtfpeople.com", "wuerkaixi.com", "wufafangwen.com", "wufi.org.tw", "wuguoguang.com", "wujie.net", "wujieliulan.com", "wukangrui.net", "wuw.red", "wuyanblog.com", "wwe.com", "wwitv.com", "www1.biz", "wwwhost.biz", "wzyboy.im", "x-art.com", "x-berry.com", "x-wall.org", "x.co", "x.company", "x1949x.com", "x24hr.com", "x365x.com", "xanga.com", "xbabe.com", "xbookcn.com", "xbtce.com", "xcafe.in", "xcity.jp", "xcritic.com", "xda-developers.com", "xerotica.com", "xfiles.to", "xfinity.com", "xgmyd.com", "xhamster.com", "xianba.net", "xianchawang.net", "xianjian.tw", "xianqiao.net", "xiaobaiwu.com", "xiaochuncnjp.com", "xiaod.in", "xiaohexie.com", "xiaolan.me", "xiaoma.org", "xiaxiaoqiang.net", "xiezhua.com", "xihua.es", "xinbao.de", "xing.com", "xinhuanet.org", "xinjiangpolicefiles.org", "xinmiao.com.hk", "xinsheng.net", "xinshijue.com", "xinyubbs.net", "xiongpian.com", "xiuren.org", "xixicui.icu", "xizang-zhiye.org", "xjp.cc", "xjtravelguide.com", "xkiwi.tk", "xlfmtalk.com", "xlfmwz.info", "xm.com", "xml-training-guide.com", "xmovies.com", "xn--4gq171p.com", "xn--9pr62r24a.com", "xn--czq75pvv1aj5c.org", "xn--i2ru8q2qg.com", "xn--ngstr-lra8j.com", "xn--oiq.cc", "xn--p8j9a0d9c9a.xn--q9jyb4c", "xnxx.com", "xpdo.net", "xpud.org", "xrentdvd.com", "xsden.info", "xskywalker.com", "xskywalker.net", "xtube.com", "xuchao.net", "xuchao.org", "xuehua.us", "xuite.net", "xuzhiyong.net", "xvbelink.com", "xvideo.cc", "xvideos-cdn.com", "xvideos.com", "xvideos.es", "xvinlink.com", "xxbbx.com", "xxlmovies.com", "xxuz.com", "xxx.com", "xxx.xxx", "xxxfuckmom.com", "xxxx.com.au", "xxxy.biz", "xxxy.info", "xxxymovies.com", "xys.org", "xysblogs.org", "xyy69.com", "xyy69.info", "y2mate.com", "yadi.sk", "yahoo.co.jp", "yahoo.com", "yahoo.com.hk", "yahoo.com.tw", "yahoo.net", "yakbutterblues.com", "yam.com", "yam.org.tw", "yande.re", "yandex.com", "yanghengjun.com", "yangjianli.com", "yasni.co.uk", "yayabay.com", "ycombinator.com", "ydy.com", "yeahteentube.com", "yecl.net", "yeelou.com", "yeeyi.com", "yegle.net", "yes-news.com", "yes.xxx", "yes123.com.tw", "yesasia.com", "yesasia.com.hk", "yespornplease.com", "yeyeclub.com", "ygto.com", "yhcw.net", "yibada.com", "yibaochina.com", "yidio.com", "yigeni.com", "yilubbs.com", "yimg.com", "yingsuoss.com", "yinlei.org", "yipub.com", "yiyechat.com", "yizhihongxing.com", "yobit.net", "yobt.com", "yobt.tv", "yogichen.org", "yolasite.com", "yomiuri.co.jp", "yong.hu", "yorkbbs.ca", "you-get.org", "youdontcare.com", "youjizz.com", "youmaker.com", "youngpornvideos.com", "youngspiration.hk", "youpai.org", "youporn.com", "youporngay.com", "your-freedom.net", "yourepeat.com", "yourlisten.com", "yourlust.com", "yourprivatevpn.com", "yourtrap.com", "yousendit.com", "youshun12.com", "youthforfreechina.org", "youthnetradio.org", "youthwant.com.tw", "youtu.be", "youtube-nocookie.com", "youtube.com", "youtubecn.com", "youtubeeducation.com", "youtubegaming.com", "youtubekids.com", "youversion.com", "youwin.com", "youxu.info", "yt.be", "ytht.net", "ytimg.com", "ytn.co.kr", "yuanming.net", "yuanzhengtang.org", "yulghun.com", "yunchao.net", "yuntipub.com", "yuvutu.com", "yvesgeleyn.com", "ywpw.com", "yx51.net", "yyii.org", "yyjlymb.xyz", "yzzk.com", "z-lib.org", "zacebook.com", "zalmos.com", "zannel.com", "zaobao.com", "zaobao.com.sg", "zaozon.com", "zapto.org", "zattoo.com", "zb.com", "zdnet.com.tw", "zello.com", "zengjinyan.org", "zenmate.com", "zerohedge.com", "zeronet.io", "zeutch.com", "zfreet.com", "zgsddh.com", "zgzcjj.net", "zhanbin.net", "zhangboli.net", "zhangtianliang.com", "zhanlve.org", "zhenghui.org", "zhengjian.org", "zhengwunet.org", "zhenlibu.info", "zhenlibu1984.com", "zhenxiang.biz", "zhinengluyou.com", "zhongguo.ca", "zhongguorenquan.org", "zhongguotese.net", "zhongmeng.org", "zhoushuguang.com", "zhreader.com", "zhuangbi.me", "zhuanxing.cn", "zhuatieba.com", "zhuichaguoji.org", "zi.media", "zi5.me", "ziddu.com", "zillionk.com", "zim.vn", "zinio.com", "ziporn.com", "zippyshare.com", "zkaip.com", "zkiz.com", "zmw.cn", "zodgame.us", "zoho.com", "zomobo.net", "zonaeuropa.com", "zonghexinwen.com", "zonghexinwen.net", "zoogvpn.com", "zootool.com", "zoozle.net", "zophar.net", "zorrovpn.com", "zozotown.com", "zpn.im", "zspeeder.me", "zsrhao.com", "zuo.la", "zuobiao.me", "zuola.com", "zvereff.com", "zynaima.com", "zynamics.com", "zyns.com", "zyxel.com", "zyzc9.com", "zzcartoon.com", "zzcloud.me", "zzux.com" ] ] ]; var lastRule = ''; function FindProxyForURL(url, host) { for (var i = 0; i < rules.length; i++) { ret = testHost(host, i); if (ret != undefined) return ret; } return 'DIRECT'; } function testHost(host, index) { for (var i = 0; i < rules[index].length; i++) { for (var j = 0; j < rules[index][i].length; j++) { lastRule = rules[index][i][j]; if (host == lastRule || host.endsWith('.' + lastRule)) return i % 2 == 0 ? 'DIRECT' : proxy; } } lastRule = ''; } // REF: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith if (!String.prototype.endsWith) { String.prototype.endsWith = function(searchString, position) { var subjectString = this.toString(); if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) { position = subjectString.length; } position -= searchString.length; var lastIndex = subjectString.indexOf(searchString, position); return lastIndex !== -1 && lastIndex === position; }; } ================================================ FILE: v2rayN/PacLib/Resources.Designer.cs ================================================ //------------------------------------------------------------------------------ // // 此代码由工具生成。 // 运行时版本:4.0.30319.42000 // // 对此文件的更改可能会导致不正确的行为,并且如果 // 重新生成代码,这些更改将会丢失。 // //------------------------------------------------------------------------------ namespace PacLib { using System; /// /// 一个强类型的资源类,用于查找本地化的字符串等。 /// // 此类是由 StronglyTypedResourceBuilder // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen // (以 /str 作为命令选项),或重新生成 VS 项目。 [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.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() { } /// /// 返回此类使用的缓存的 ResourceManager 实例。 /// [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("PacLib.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } /// /// 重写当前线程的 CurrentUICulture 属性,对 /// 使用此强类型资源类的所有资源查找执行重写。 /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } /// /// 查找类似 var proxy = '__PROXY__'; ///var rules = [ /// [ /// [], /// [] /// ], /// [ /// [ /// "aftygh.gov.tw", /// "aide.gov.tw", /// "aliyun.com", /// "arte.gov.tw", /// "baidu.com", /// "chinaso.com", /// "chinaz.com", /// "chukuang.gov.tw", /// "cycab.gov.tw", /// "dbnsa.gov.tw", /// "df.gov.tw", /// "eastcoast-nsa.gov.tw", /// "erv-nsa.gov.tw", /// "grb.gov.tw", /// "haosou.com", /// [字符串的其余部分被截断]"; 的本地化字符串。 /// internal static string pac { get { return ResourceManager.GetString("pac", resourceCulture); } } } } ================================================ FILE: v2rayN/PacLib/Resources.resx ================================================  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\pac.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;gb2312 ================================================ FILE: v2rayN/ProtosLib/ProtosLib.csproj ================================================  net6.0-windows enable all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: v2rayN/ProtosLib/Statistics.proto ================================================ syntax = "proto3"; package v2ray.core.app.stats.command; option csharp_namespace = "ProtosLib.Statistics"; message GetStatsRequest { // Name of the stat counter. string name = 1; // Whether or not to reset the counter to fetching its value. bool reset = 2; } message Stat { string name = 1; int64 value = 2; } message GetStatsResponse { Stat stat = 1; } message QueryStatsRequest { string pattern = 1; bool reset = 2; } message QueryStatsResponse { repeated Stat stat = 1; } message SysStatsRequest { } message SysStatsResponse { uint32 NumGoroutine = 1; uint32 NumGC = 2; uint64 Alloc = 3; uint64 TotalAlloc = 4; uint64 Sys = 5; uint64 Mallocs = 6; uint64 Frees = 7; uint64 LiveObjects = 8; uint64 PauseTotalNs = 9; uint32 Uptime = 10; } service StatsService { rpc GetStats(GetStatsRequest) returns (GetStatsResponse) {} rpc QueryStats(QueryStatsRequest) returns (QueryStatsResponse) {} rpc GetSysStats(SysStatsRequest) returns (SysStatsResponse) {} } message Config {} ================================================ FILE: v2rayN/ProtosLib/Tests.cs ================================================ using ProtosLib.Statistics; namespace ProtosLib { public class Tests { private StatsService.StatsServiceClient client_; public Tests() { } } } ================================================ FILE: v2rayN/v2rayN/App.xaml ================================================  26 12 13 14 11 ================================================ FILE: v2rayN/v2rayN/App.xaml.cs ================================================ using System.Windows; using System.Windows.Threading; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Tool; using v2rayN.ViewModels; using v2rayN.Tool; using System.Net; using HiddifyN.Tool; using v2rayN.Views; using System.IO.Pipes; using System.IO; namespace v2rayN { /// /// Interaction logic for App.xaml /// public partial class App : Application { public static EventWaitHandle ProgramStarted; public static bool IsNewInstance = false; private static Config _config; public App() { // Locator.CurrentMutable.RegisterViewsForViewModels(Assembly.GetCallingAssembly()); this.DispatcherUnhandledException += App_DispatcherUnhandledException; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; } /// /// 只打开一个进程 /// /// protected override void OnStartup(StartupEventArgs e) { DeepLinking.RegisterSchemes(); Global.ExePathKey = Utils.GetMD5(Utils.GetExePath()); var rebootas = (e.Args ?? new string[] { }).Any(t => t == Global.RebootAs); ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, Global.ExePathKey, out bool bCreatedNew); if (!rebootas && !bCreatedNew) { ProgramStarted.Set(); IsNewInstance = true; sendLinkToUi(); } Global.processJob = new Job(); Logging.Setup(); Init(); Logging.LoggingEnabled(_config.guiItem.enableLog); Utils.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}"); Logging.ClearLogs(); Thread.CurrentThread.CurrentUICulture = new(_config.uiItem.currentLanguage); base.OnStartup(e); } private void sendLinkToUi() { try { using (var pipeClient = new NamedPipeClientStream("HiddifyPipe")) { pipeClient.Connect(); using (var writer = new StreamWriter(pipeClient)) { var args = Environment.GetCommandLineArgs(); // Write the message to the named pipe string message = args.Length>1? args[1]:""; writer.WriteLine(message); writer.Flush(); Thread.Sleep(10000); } pipeClient.Close(); } } catch (Exception ex) { // Handle any exceptions that occur while sending the message // ... } // Exit the new instance of the application Application.Current.Shutdown(); } private void Init() { if (ConfigHandler.LoadConfig(ref _config) != 0) { UI.ShowWarning($"Loading GUI configuration file is abnormal,please restart the application{Environment.NewLine}加载GUI配置文件异常,请重启应用"); Current.Shutdown(); Environment.Exit(0); return; } //if (RuntimeInformation.ProcessArchitecture != Architecture.X86 && RuntimeInformation.ProcessArchitecture != Architecture.X64) //{ // _config.guiItem.enableStatistics = false; //} } private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) { Utils.SaveLog("App_DispatcherUnhandledException", e.Exception); e.Handled = true; } private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { if (e.ExceptionObject != null) { Utils.SaveLog("CurrentDomain_UnhandledException", (Exception)e.ExceptionObject!); } } private void TaskScheduler_UnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e) { Utils.SaveLog("TaskScheduler_UnobservedTaskException", e.Exception); } } } ================================================ FILE: v2rayN/v2rayN/AssemblyInfo.cs ================================================ 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) )] ================================================ FILE: v2rayN/v2rayN/Base/DownloaderHelper.cs ================================================ using Downloader; using System.IO; using System.Net; namespace v2rayN.Base { internal class DownloaderHelper { private static readonly Lazy _instance = new(() => new()); public static DownloaderHelper Instance => _instance.Value; public async Task DownloadStringAsync(IWebProxy? webProxy, string url, string? userAgent, int timeout) { if (string.IsNullOrEmpty(url)) { return null; } Uri uri = new(url); //Authorization Header var headers = new WebHeaderCollection(); if (!Utils.IsNullOrEmpty(uri.UserInfo)) { headers.Add(HttpRequestHeader.Authorization, "Basic " + Utils.Base64Encode(uri.UserInfo)); } var downloadOpt = new DownloadConfiguration() { Timeout = timeout * 1000, MaxTryAgainOnFailover = 2, RequestConfiguration = { Headers = headers, UserAgent = userAgent, Timeout = timeout * 1000, Proxy = webProxy } }; using var downloader = new DownloadService(downloadOpt); downloader.DownloadFileCompleted += (sender, value) => { if (value.Error != null) throw value.Error; }; using var cts = new CancellationTokenSource(); using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token); using StreamReader reader = new(stream); downloadOpt = null; return reader.ReadToEnd(); } public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress progress, int timeout) { if (string.IsNullOrEmpty(url)) { throw new ArgumentNullException(nameof(url)); } var downloadOpt = new DownloadConfiguration() { Timeout = timeout * 1000, MaxTryAgainOnFailover = 2, RequestConfiguration = { Timeout= timeout * 1000, Proxy = webProxy } }; DateTime totalDatetime = DateTime.Now; int totalSecond = 0; var hasValue = false; double maxSpeed = 0; using var downloader = new DownloadService(downloadOpt); //downloader.DownloadStarted += (sender, value) => //{ // if (progress != null) // { // progress.Report("Start download data..."); // } //}; downloader.DownloadProgressChanged += (sender, value) => { TimeSpan ts = (DateTime.Now - totalDatetime); if (progress != null && ts.Seconds > totalSecond) { hasValue = true; totalSecond = ts.Seconds; if (value.BytesPerSecondSpeed > maxSpeed) { maxSpeed = value.BytesPerSecondSpeed; var speed = (maxSpeed / 1000 / 1000).ToString("#0.0"); progress.Report(speed); } } }; downloader.DownloadFileCompleted += (sender, value) => { if (progress != null) { if (!hasValue && value.Error != null) { progress.Report(value.Error?.Message); } } }; //progress.Report("......"); using var cts = new CancellationTokenSource(); cts.CancelAfter(timeout * 1000); using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token); downloadOpt = null; } public async Task DownloadFileAsync(IWebProxy? webProxy, string url, string fileName, IProgress progress, int timeout) { if (string.IsNullOrEmpty(url)) { throw new ArgumentNullException(nameof(url)); } if (string.IsNullOrEmpty(fileName)) { throw new ArgumentNullException(nameof(fileName)); } if (File.Exists(fileName)) { File.Delete(fileName); } var downloadOpt = new DownloadConfiguration() { Timeout = timeout * 1000, MaxTryAgainOnFailover = 2, RequestConfiguration = { Timeout= timeout * 1000, Proxy = webProxy } }; var progressPercentage = 0; var hasValue = false; using var downloader = new DownloadService(downloadOpt); downloader.DownloadStarted += (sender, value) => { progress?.Report(0); }; downloader.DownloadProgressChanged += (sender, value) => { hasValue = true; var percent = (int)value.ProgressPercentage;// Convert.ToInt32((totalRead * 1d) / (total * 1d) * 100); if (progressPercentage != percent && percent % 10 == 0) { progressPercentage = percent; progress.Report(percent); } }; downloader.DownloadFileCompleted += (sender, value) => { if (progress != null) { if (hasValue && value.Error == null) { progress.Report(101); } } }; using var cts = new CancellationTokenSource(); await downloader.DownloadFileTaskAsync(url, fileName, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token); downloadOpt = null; } } } ================================================ FILE: v2rayN/v2rayN/Base/HttpClientHelper.cs ================================================ using System.IO; using System.Net.Http; using System.Net.Mime; using System.Text; namespace v2rayN.Base { /// /// public class HttpClientHelper { private static readonly Lazy _instance = new(() => { HttpClientHandler handler = new() { UseCookies = false }; HttpClientHelper helper = new(new HttpClient(handler)); return helper; }); public static HttpClientHelper Instance => _instance.Value; private readonly HttpClient httpClient; private HttpClientHelper(HttpClient httpClient) => this.httpClient = httpClient; public async Task GetAsync(string url) { if (string.IsNullOrEmpty(url)) return null; return await httpClient.GetStringAsync(url); } public async Task GetAsync(HttpClient client, string url, CancellationToken token = default) { if (string.IsNullOrWhiteSpace(url)) return null; return await client.GetStringAsync(url, token); } public async Task PutAsync(string url, Dictionary headers) { var jsonContent = Utils.ToJson(headers); var content = new StringContent(jsonContent, Encoding.UTF8, MediaTypeNames.Application.Json); var result = await httpClient.PutAsync(url, content); } public static async Task DownloadFileAsync(HttpClient client, string url, string fileName, IProgress? progress, CancellationToken token = default) { ArgumentNullException.ThrowIfNull(url); ArgumentNullException.ThrowIfNull(fileName); if (File.Exists(fileName)) File.Delete(fileName); using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token); if (!response.IsSuccessStatusCode) throw new Exception(response.StatusCode.ToString()); var total = response.Content.Headers.ContentLength ?? -1L; var canReportProgress = total != -1 && progress != null; using var stream = await response.Content.ReadAsStreamAsync(token); using var file = File.Create(fileName); var totalRead = 0L; var buffer = new byte[1024 * 1024]; var progressPercentage = 0; while (true) { token.ThrowIfCancellationRequested(); var read = await stream.ReadAsync(buffer, token); totalRead += read; if (read == 0) break; file.Write(buffer, 0, read); if (canReportProgress) { var percent = (int)(100.0 * totalRead / total); //if (progressPercentage != percent && percent % 10 == 0) { progressPercentage = percent; progress!.Report(percent); } } } if (canReportProgress) { progress!.Report(101); } } public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress progress, CancellationToken token = default) { if (string.IsNullOrEmpty(url)) { throw new ArgumentNullException(nameof(url)); } var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token); if (!response.IsSuccessStatusCode) { throw new Exception(response.StatusCode.ToString()); } //var total = response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : -1L; //var canReportProgress = total != -1 && progress != null; using var stream = await response.Content.ReadAsStreamAsync(token); var totalRead = 0L; var buffer = new byte[1024 * 64]; var isMoreToRead = true; string progressSpeed = string.Empty; DateTime totalDatetime = DateTime.Now; int totalSecond = 0; do { if (token.IsCancellationRequested) { if (totalRead > 0) { return; } else { token.ThrowIfCancellationRequested(); } } var read = await stream.ReadAsync(buffer, token); if (read == 0) { isMoreToRead = false; } else { var data = new byte[read]; buffer.ToList().CopyTo(0, data, 0, read); totalRead += read; TimeSpan ts = (DateTime.Now - totalDatetime); if (progress != null && ts.Seconds > totalSecond) { totalSecond = ts.Seconds; var speed = (totalRead * 1d / ts.TotalMilliseconds / 1000).ToString("#0.0"); if (progressSpeed != speed) { progressSpeed = speed; progress.Report(speed); } } } } while (isMoreToRead); } } } ================================================ FILE: v2rayN/v2rayN/Base/MyDGTextColumn.cs ================================================ using System.Windows.Controls; namespace v2rayN.Base { internal class MyDGTextColumn : DataGridTextColumn { public string ExName { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Base/SqliteHelper.cs ================================================ using SQLite; using System.Collections; namespace v2rayN.Base { public sealed class SqliteHelper { private static readonly Lazy _instance = new(() => new()); public static SqliteHelper Instance => _instance.Value; private string _connstr; private SQLiteConnection _db; private SQLiteAsyncConnection _dbAsync; private static readonly object objLock = new(); public SqliteHelper() { _connstr = Utils.GetConfigPath(Global.ConfigDB); _db = new SQLiteConnection(_connstr, false); _dbAsync = new SQLiteAsyncConnection(_connstr, false); } public CreateTableResult CreateTable() { return _db.CreateTable(); } public int Insert(object model) { return _db.Insert(model); } public int InsertAll(IEnumerable models) { lock (objLock) { return _db.InsertAll(models); } } public async Task InsertAsync(object model) { return await _dbAsync.InsertAsync(model); } public int Replace(object model) { lock (objLock) { return _db.InsertOrReplace(model); } } public async Task Replacesync(object model) { return await _dbAsync.InsertOrReplaceAsync(model); } public int Update(object model) { lock (objLock) { return _db.Update(model); } } public async Task UpdateAsync(object model) { return await _dbAsync.UpdateAsync(model); } public int UpdateAll(IEnumerable models) { lock (objLock) { return _db.UpdateAll(models); } } public int Delete(object model) { lock (objLock) { return _db.Delete(model); } } public async Task DeleteAsync(object model) { return await _dbAsync.DeleteAsync(model); } public List Query(string sql) where T : new() { return _db.Query(sql); } public async Task> QueryAsync(string sql) where T : new() { return await _dbAsync.QueryAsync(sql); } public int Execute(string sql) { return _db.Execute(sql); } public async Task ExecuteAsync(string sql) { return await _dbAsync.ExecuteAsync(sql); } public TableQuery Table() where T : new() { return _db.Table(); } public AsyncTableQuery TableAsync() where T : new() { return _dbAsync.Table(); } } } ================================================ FILE: v2rayN/v2rayN/Base/StringEx.cs ================================================ using System.Diagnostics.CodeAnalysis; using System.IO; namespace v2rayN.Base { internal static class StringEx { public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value) { return string.IsNullOrEmpty(value); } public static bool IsNullOrWhiteSpace([NotNullWhen(false)] this string? value) { return string.IsNullOrWhiteSpace(value); } public static bool BeginWithAny(this string s, IEnumerable chars) { if (s.IsNullOrEmpty()) return false; return chars.Contains(s[0]); } public static bool IsWhiteSpace(this string value) { foreach (char c in value) { if (char.IsWhiteSpace(c)) continue; return false; } return true; } public static IEnumerable NonWhiteSpaceLines(this TextReader reader) { string? line; while ((line = reader.ReadLine()) != null) { if (line.IsWhiteSpace()) continue; yield return line; } } public static string TrimEx(this string? value) { return value == null ? string.Empty : value.Trim(); } } } ================================================ FILE: v2rayN/v2rayN/Converters/DelayColorConverter.cs ================================================ using System.Windows.Data; using System.Windows.Media; namespace v2rayN.Converters { public class DelayColorConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { int.TryParse(value.ToString(), out var delay); if (delay <= 0) return new SolidColorBrush(Colors.Red); if (delay <= 200) return new SolidColorBrush(Colors.Green); else return new SolidColorBrush(Colors.IndianRed); } public object? ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return null; } } } ================================================ FILE: v2rayN/v2rayN/Converters/LocalizeConverter.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Data; using System.Windows; using v2rayN.Mode; namespace v2rayN.Converters { public class LocalizeConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is ProxyModeEnum) return ((ProxyModeEnum)value).ToLocalizedDescriptionString(); string resourceName = value.ToString(); return Application.Current.FindResource(resourceName); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } } ================================================ FILE: v2rayN/v2rayN/Converters/MaterialDesignFonts.cs ================================================ using System.Windows.Media; using v2rayN.Handler; namespace v2rayN.Converters { public class MaterialDesignFonts { public static FontFamily MyFont { get; } static MaterialDesignFonts() { try { var fontFamily = LazyConfig.Instance.GetConfig().uiItem.currentFontFamily; if (!string.IsNullOrEmpty(fontFamily)) { var fontPath = Utils.GetFontsPath(); MyFont = new FontFamily(new Uri(@$"file:///{fontPath}\"), $"./#{fontFamily}"); } } catch { } MyFont ??= new FontFamily("Microsoft YaHei"); } } } ================================================ FILE: v2rayN/v2rayN/Converters/SizeConverter.cs ================================================ using System.Globalization; using System.Windows.Data; using System.Windows.Media; namespace v2rayN.Converters { public class SizeConverter : IValueConverter { private static readonly string[] SizeSuffixes = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; private static bool IsNumber(object value) { return value is sbyte || value is byte || value is short || value is ushort || value is int || value is uint || value is long || value is ulong || value is float || value is double || value is decimal; } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null || !IsNumber(value)) { return null; } long fileSizeInBytes = System.Convert.ToInt64(value); if (fileSizeInBytes == 0) { return "0 B"; } var sizeIndex = (int)Math.Floor(Math.Log(fileSizeInBytes, 1024)); var size = fileSizeInBytes / Math.Pow(1024, sizeIndex); var sizeSuffix = SizeSuffixes[sizeIndex]; var formattedSize = string.Format("{0:n1}", size); return $"{formattedSize} {sizeSuffix}"; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } } ================================================ FILE: v2rayN/v2rayN/FodyWeavers.xml ================================================  ================================================ FILE: v2rayN/v2rayN/Global.cs ================================================ using System.IO; namespace v2rayN { internal class Global { #region const public const string githubUrl = "https://github.com"; public const string githubApiUrl = "https://api.github.com/repos"; public const string v2rayWebsiteUrl = @"https://www.hiddify.com/"; public const string AboutUrl = @"https://github.com/hiddify/HiddifyDesktopN"; public const string UpdateUrl = AboutUrl + @"/releases"; public const string v2flyCoreUrl = "https://github.com/v2fly/v2ray-core/releases"; public const string xrayCoreUrl = "https://github.com/hiddify/hiddify-Xray-core/releases"; public const string SagerNetCoreUrl = "https://github.com/SagerNet/v2ray-core/releases"; public const string NUrl = @"https://github.com/hiddify/HiddifyDesktopN/releases"; public const string clashCoreUrl = "https://github.com/Dreamacro/clash/releases"; public const string clashMetaCoreUrl = "https://github.com/MetaCubeX/Clash.Meta/releases"; public const string hysteriaCoreUrl = "https://github.com/apernet/hysteria/releases"; public const string naiveproxyCoreUrl = "https://github.com/klzgrad/naiveproxy/releases"; public const string tuicCoreUrl = "https://github.com/EAimTY/tuic/releases"; public const string singboxCoreUrl = "https://github.com/SagerNet/sing-box/releases"; public const string geoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat"; public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/"; public const string singboxGeoUrl = "https://github.com/soffchen/sing-{0}/releases/latest/download/{0}.db"; public const string SpeedPingTestUrl = @"https://www.google.com/generate_204"; public const string SpeedPingTestUrlGoogle = @"https://www.google.com/generate_204"; public const string SpeedPingTestUrlCloadFlare = @"https://cp.cloudflare.com/generate_2"; public const int DefaultUpdateSubUsageIntervalSeconds = 60; public const string PromotionUrl = @"dGc6Ly9yZXNvbHZlP2RvbWFpbj1oaWRkaWZ5"; public const string ConfigFileName = "guiNConfig.json"; public const string ConfigDB = "guiNDB.db"; public const string coreConfigFileName = "config.json"; public const string corePreConfigFileName = "configPre.json"; public const string v2raySampleClient = "v2rayN.Sample.SampleClientConfig"; public const string SingboxSampleClient = "v2rayN.Sample.SingboxSampleClientConfig"; public const string v2raySampleHttprequestFileName = "v2rayN.Sample.SampleHttprequest"; public const string v2raySampleHttpresponseFileName = "v2rayN.Sample.SampleHttpresponse"; public const string v2raySampleInbound = "v2rayN.Sample.SampleInbound"; public const string CustomRoutingFileName = "v2rayN.Sample.custom_routing_"; public const string TunSingboxFileName = "v2rayN.Sample.tun_singbox"; public const string TunSingboxDNSFileName = "v2rayN.Sample.tun_singbox_dns"; public const string TunSingboxInboundFileName = "v2rayN.Sample.tun_singbox_inbound"; public const string TunSingboxRulesFileName = "v2rayN.Sample.tun_singbox_rules"; public const string DNSV2rayNormalFileName = "v2rayN.Sample.dns_v2ray_normal"; public const string DNSSingboxNormalFileName = "v2rayN.Sample.dns_singbox_normal"; public const string DefaultSecurity = "auto"; public const string DefaultNetwork = "tcp"; public const string TcpHeaderHttp = "http"; public const string None = "none"; public const string agentTag = "proxy"; public const string directTag = "direct"; public const string blockTag = "block"; public const string StreamSecurity = "tls"; public const string StreamSecurityReality = "reality"; public const string InboundSocks = "socks"; public const string InboundHttp = "http"; public const string InboundSocks2 = "socks2"; public const string InboundHttp2 = "http2"; public const string Loopback = "127.0.0.1"; public const string InboundAPITagName = "api"; public const string InboundAPIProtocal = "dokodemo-door"; public const string vmessProtocol = "vmess://"; public const string vmessProtocolLite = "vmess"; public const string ssProtocol = "ss://"; public const string ssProtocolLite = "shadowsocks"; public const string socksProtocol = "socks://"; public const string socksProtocolLite = "socks"; public const string httpProtocol = "http://"; public const string httpsProtocol = "https://"; public const string vlessProtocol = "vless://"; public const string vlessProtocolLite = "vless"; public const string trojanProtocol = "trojan://"; public const string trojanProtocolLite = "trojan"; public const string userEMail = "t@t.tt"; public const string MyRegPath = "Software\\hiddifyNGUI"; public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run"; public const string AutoRunName = "hiddifyNAutoRun"; public const string MyRegKeyLanguage = "CurrentLanguage"; public const string CustomIconName = "v2rayN.ico"; public const string IEProxyExceptions = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*"; public const string RoutingRuleComma = ""; public const string GrpcgunMode = "gun"; public const string GrpcmultiMode = "multi"; public const int MaxPort = 65536; public const string CommandClearMsg = "CommandClearMsg"; public const string DelayUnit = ""; public const string SpeedUnit = ""; public const int MinFontSize = 10; public const string RebootAs = "rebootas"; public static readonly List IEProxyProtocols = new() { "{ip}:{http_port}", "socks={ip}:{socks_port}", "http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}", "http=http://{ip}:{http_port};https=http://{ip}:{http_port}", "" }; public static readonly List SubConvertUrls = new List { @"https://sub.xeton.dev/sub?url={0}", @"https://api.dler.io/sub?url={0}", @"http://127.0.0.1:25500/sub?url={0}", "" }; public static readonly List SubConvertConfig = new List { @"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini" }; public static readonly List SubConvertTargets = new List { "", "mixed", "v2ray", "clash", "ss", }; public static readonly List SpeedTestUrls = new() { @"http://cachefly.cachefly.net/100mb.test", @"http://cachefly.cachefly.net/10mb.test" }; public static readonly Dictionary userAgentTxt = new() { {"chrome","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" }, {"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" }, {"safari","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15" }, {"edge","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.70" }, {"none",""} }; public static readonly List vmessSecuritys = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" }; public static readonly List ssSecuritys = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" }; public static readonly List ssSecuritysInSagerNet = new() { "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "rc4", "rc4-md5", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-cfb8", "aes-192-cfb8", "aes-256-cfb8", "aes-128-ofb", "aes-192-ofb", "aes-256-ofb", "bf-cfb", "cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "camellia-128-cfb8", "camellia-192-cfb8", "camellia-256-cfb8", "salsa20", "chacha20", "chacha20-ietf", "xchacha20" }; public static readonly List ssSecuritysInXray = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" }; public static readonly List flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" }; public static readonly List networks = new() { "tcp", "kcp", "ws", "h2", "quic", "grpc" }; public static readonly List kcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" }; public static readonly List coreTypes = new() { "v2fly", "SagerNet", "Xray", "v2fly_v5", "sing_box" }; public static readonly List coreTypes4VLESS = new() { "Xray", "sing_box" }; public static readonly List domainStrategys = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" }; public static readonly List domainStrategys4Singbox = new() { "ipv4_only", "ipv6_only", "prefer_ipv4", "prefer_ipv6", "" }; public static readonly List domainMatchers = new() { "linear", "mph", "" }; public static readonly List fingerprints = new() { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" }; public static readonly List userAgent = new() { "chrome", "firefox", "safari", "edge", "none" }; public static readonly List allowInsecures = new() { "true", "false", "" }; public static readonly List fragmentStrategies = new() { "random", "sni", "" };//hiddify public static readonly List domainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" }; public static readonly List Languages = new() { "en", "fa-Ir", "ru", "zh-Hans"}; public static readonly List alpns = new() { "h2", "http/1.1", "h2,http/1.1", "" }; public static readonly List LogLevel = new() { "debug", "info", "warning", "error", "none" }; public static readonly List InboundTags = new() { "socks", "http", "socks2", "http2" }; public static readonly List Protocols = new() { "http", "tls", "bittorrent" }; public static readonly List TunMtus = new() { "9000", "1500" }; public static readonly List TunStacks = new() { "gvisor", "system" }; public static readonly List PresetMsgFilters = new() { "proxy", "direct", "block", "" }; #endregion const #region global variable public static int statePort { get; set; } public static Job processJob { get; set; } public static bool ShowInTaskbar { get; set; } public static string ExePathKey { get; set; } public static string MainFormReloadFilePath { get; set; } = Utils.GetTempPath("mainPageReloadLockFile.txt"); public static readonly string RestartProgramExePath = Path.GetFullPath(Path.Combine(Utils.StartupPath(), "bin", "hiddifyRestartN", "HiddifyRestartN.exe")); public static readonly string UpgradeProgramExePath = Path.GetFullPath(Path.Combine(Utils.StartupPath(), "bin", "hiddifyUpgradeN", "HiddifyUpgradeN.exe")); public static readonly string SpeedTestProgramExePath = Path.GetFullPath(Path.Combine(Utils.StartupPath(), "bin", "speedTest", "librespeed-cli.exe")); #endregion global variable } } ================================================ FILE: v2rayN/v2rayN/Handler/ConfigHandler.cs ================================================ using Splat; using System.Collections.Specialized; using System.Data; using System.IO; using System.Security.Policy; using System.Text.RegularExpressions; using v2rayN.Base; using v2rayN.Mode; using v2rayN.Tool; using v2rayN.ViewModels; namespace v2rayN.Handler { /// /// 本软件配置文件处理类 /// internal class ConfigHandler { private static string configRes = Global.ConfigFileName; private static readonly object objLock = new(); #region ConfigHandler /// /// 载入配置文件 /// /// /// public static int LoadConfig(ref Config config) { //载入配置文件 string result = Utils.LoadResource(Utils.GetConfigPath(configRes)); if (!Utils.IsNullOrEmpty(result)) { //转成Json config = Utils.FromJson(result); } else { if (File.Exists(Utils.GetConfigPath(configRes))) { Utils.SaveLog("LoadConfig Exception"); return -1; } } if (config == null) { config = new Config { }; } if (config.coreBasicItem == null) { config.coreBasicItem = new() { logEnabled = false, loglevel = "warning", muxEnabled = false, }; } //本地监听 if (config.inbound == null) { config.inbound = new List(); InItem inItem = new() { protocol = Global.InboundSocks, localPort = 10808, udpEnabled = true, sniffingEnabled = true, routeOnly = false, }; config.inbound.Add(inItem); //inItem = new InItem(); //inItem.protocol = "http"; //inItem.localPort = 1081; //inItem.udpEnabled = true; //config.inbound.Add(inItem); } else { if (config.inbound.Count > 0) { config.inbound[0].protocol = Global.InboundSocks; } } if (config.routingBasicItem == null) { config.routingBasicItem = new() { enableRoutingAdvanced = true }; } //路由规则 if (Utils.IsNullOrEmpty(config.routingBasicItem.domainStrategy)) { config.routingBasicItem.domainStrategy = Global.domainStrategys[0];//"IPIfNonMatch"; } //if (Utils.IsNullOrEmpty(config.domainMatcher)) //{ // config.domainMatcher = "linear"; //} //kcp if (config.kcpItem == null) { config.kcpItem = new KcpItem { mtu = 1350, tti = 50, uplinkCapacity = 12, downlinkCapacity = 100, readBufferSize = 2, writeBufferSize = 2, congestion = false }; } if (config.grpcItem == null) { config.grpcItem = new GrpcItem { idle_timeout = 60, health_check_timeout = 20, permit_without_stream = false, initial_windows_size = 0, }; } if (config.tunModeItem == null) { config.tunModeItem = new TunModeItem { enableTun = false, showWindow = true, mtu = 9000, }; } if (config.guiItem == null) { config.guiItem = new() { enableStatistics = false, statisticsFreshRate = 1, }; } if (config.uiItem == null) { config.uiItem = new UIItem() { enableAutoAdjustMainLvColWidth = true }; } if (config.uiItem.mainColumnItem == null) { config.uiItem.mainColumnItem = new(); } if (Utils.IsNullOrEmpty(config.uiItem.currentLanguage)) { config.uiItem.currentLanguage = Global.Languages[0]; } if (config.constItem == null) { config.constItem = new ConstItem(); } if (Utils.IsNullOrEmpty(config.constItem.defIEProxyExceptions)) { config.constItem.defIEProxyExceptions = Global.IEProxyExceptions; } if (config.speedTestItem == null) { config.speedTestItem = new(); } if (config.speedTestItem.speedTestTimeout < 10) { config.speedTestItem.speedTestTimeout = 10; } if (Utils.IsNullOrEmpty(config.speedTestItem.speedTestUrl)) { config.speedTestItem.speedTestUrl = Global.SpeedTestUrls[0]; } //if (Utils.IsNullOrEmpty(config.speedTestItem.speedPingTestUrl)) { config.speedTestItem.speedPingTestUrl = Global.SpeedPingTestUrlGoogle; } if (config.guiItem.statisticsFreshRate is > 100 or < 1) { config.guiItem.statisticsFreshRate = 1; } LazyConfig.Instance.SetConfig(config); return 0; } /// /// 保参数 /// /// /// public static int SaveConfig(ref Config config, bool reload = true) { ToJsonFile(config); return 0; } /// /// 存储文件 /// /// private static void ToJsonFile(Config config) { lock (objLock) { try { //save temp file var resPath = Utils.GetConfigPath(configRes); var tempPath = $"{resPath}_temp"; if (Utils.ToJsonFile(config, tempPath) != 0) { return; } if (File.Exists(resPath)) { File.Delete(resPath); } //rename File.Move(tempPath, resPath); } catch (Exception ex) { Utils.SaveLog("ToJsonFile", ex); } } } public static int ImportOldGuiConfig(ref Config config, string fileName) { string result = Utils.LoadResource(fileName); if (Utils.IsNullOrEmpty(result)) { return -1; } var configOld = Utils.FromJson(result); if (configOld == null) { return -1; } var subItem = Utils.FromJson>(Utils.ToJson(configOld.subItem)); foreach (var it in subItem) { if (Utils.IsNullOrEmpty(it.id)) { it.id = Utils.GetGUID(false); } SqliteHelper.Instance.Replace(it); } var profileItems = Utils.FromJson>(Utils.ToJson(configOld.vmess)); foreach (var it in profileItems) { if (Utils.IsNullOrEmpty(it.indexId)) { it.indexId = Utils.GetGUID(false); } SqliteHelper.Instance.Replace(it); } foreach (var it in configOld.routings) { if (it.locked) { continue; } var routing = Utils.FromJson(Utils.ToJson(it)); foreach (var it2 in it.rules) { it2.id = Utils.GetGUID(false); } routing.ruleNum = it.rules.Count; routing.ruleSet = Utils.ToJson(it.rules, false); if (Utils.IsNullOrEmpty(routing.id)) { routing.id = Utils.GetGUID(false); } SqliteHelper.Instance.Replace(routing); } config = Utils.FromJson(Utils.ToJson(configOld)); if (config.coreBasicItem == null) { config.coreBasicItem = new() { logEnabled = configOld.logEnabled, loglevel = configOld.loglevel, muxEnabled = configOld.muxEnabled, }; } if (config.routingBasicItem == null) { config.routingBasicItem = new() { enableRoutingAdvanced = configOld.enableRoutingAdvanced, domainStrategy = configOld.domainStrategy }; } if (config.guiItem == null) { config.guiItem = new() { enableStatistics = configOld.enableStatistics, statisticsFreshRate = configOld.statisticsFreshRate, keepOlderDedupl = configOld.keepOlderDedupl, ignoreGeoUpdateCore = configOld.ignoreGeoUpdateCore, autoUpdateInterval = configOld.autoUpdateInterval, checkPreReleaseUpdate = configOld.checkPreReleaseUpdate, enableSecurityProtocolTls13 = configOld.enableSecurityProtocolTls13, trayMenuServersLimit = configOld.trayMenuServersLimit, }; } GetDefaultServer(ref config); GetDefaultRouting(ref config); SaveConfig(ref config); LoadConfig(ref config); return 0; } #endregion ConfigHandler #region Server /// /// 添加服务器或编辑 /// /// /// /// public static int AddServer(ref Config config, ProfileItem profileItem, bool toFile = true) { profileItem.configType = EConfigType.VMess; profileItem.address = profileItem.address.TrimEx(); profileItem.id = profileItem.id.TrimEx(); profileItem.security = profileItem.security.TrimEx(); profileItem.network = profileItem.network.TrimEx(); profileItem.headerType = profileItem.headerType.TrimEx(); profileItem.requestHost = profileItem.requestHost.TrimEx(); profileItem.path = profileItem.path.TrimEx(); profileItem.streamSecurity = profileItem.streamSecurity.TrimEx(); if (!Global.vmessSecuritys.Contains(profileItem.security)) { return -1; } AddServerCommon(ref config, profileItem, toFile); return 0; } /// /// 移除服务器 /// /// /// /// public static int RemoveServer(Config config, List indexs) { var subid = "TempRemoveSubId"; foreach (var item in indexs) { item.subid = subid; } SqliteHelper.Instance.UpdateAll(indexs); RemoveServerViaSubid(ref config, subid, false); return 0; } /// /// 克隆服务器 /// /// /// /// public static int CopyServer(ref Config config, List indexs) { foreach (var it in indexs) { var item = LazyConfig.Instance.GetProfileItem(it.indexId); if (item is null) { continue; } ProfileItem profileItem = Utils.DeepCopy(item); profileItem.indexId = string.Empty; profileItem.remarks = $"{item.remarks}-clone"; if (profileItem.configType == EConfigType.Custom) { profileItem.address = Utils.GetConfigPath(profileItem.address); if (AddCustomServer(ref config, profileItem, false) == 0) { } } else { AddServerCommon(ref config, profileItem, true); } } return 0; } /// /// 设置活动服务器 /// /// /// /// public static int SetDefaultServerIndex(ref Config config, string? indexId) { if (Utils.IsNullOrEmpty(indexId)) { return -1; } config.indexId = indexId; ToJsonFile(config); return 0; } public static int SetDefaultServer(Config config, List lstProfile) { if (lstProfile.Exists(t => t.indexId == config.indexId)) { return 0; } if (SqliteHelper.Instance.Table().Where(t => t.indexId == config.indexId).Any()) { return 0; } if (lstProfile.Count > 0) { return SetDefaultServerIndex(ref config, lstProfile.Where(t => t.port > 0).FirstOrDefault()?.indexId); } return SetDefaultServerIndex(ref config, SqliteHelper.Instance.Table().Where(t => t.port > 0).Select(t => t.indexId).FirstOrDefault()); } public static ProfileItem? GetDefaultServer(ref Config config) { var item = LazyConfig.Instance.GetProfileItem(config.indexId); if (item is null) { var item2 = SqliteHelper.Instance.Table().FirstOrDefault(); SetDefaultServerIndex(ref config, item2?.indexId); return item2; } return item; } /// /// 移动服务器 /// /// /// /// /// /// public static int MoveServer(ref Config config, ref List lstProfile, int index, EMove eMove, int pos = -1) { int count = lstProfile.Count; if (index < 0 || index > lstProfile.Count - 1) { return -1; } for (int i = 0; i < lstProfile.Count; i++) { ProfileExHandler.Instance.SetSort(lstProfile[i].indexId, (i + 1) * 10); } var sort = 0; switch (eMove) { case EMove.Top: { if (index == 0) { return 0; } sort = ProfileExHandler.Instance.GetSort(lstProfile[0].indexId) - 1; break; } case EMove.Up: { if (index == 0) { return 0; } sort = ProfileExHandler.Instance.GetSort(lstProfile[index - 1].indexId) - 1; break; } case EMove.Down: { if (index == count - 1) { return 0; } sort = ProfileExHandler.Instance.GetSort(lstProfile[index + 1].indexId) + 1; break; } case EMove.Bottom: { if (index == count - 1) { return 0; } sort = ProfileExHandler.Instance.GetSort(lstProfile[^1].indexId) + 1; break; } case EMove.Position: sort = pos * 10 + 1; break; } ProfileExHandler.Instance.SetSort(lstProfile[index].indexId, sort); return 0; } /// /// 添加自定义服务器 /// /// /// /// public static int AddCustomServer(ref Config config, ProfileItem profileItem, bool blDelete) { var fileName = profileItem.address; if (!File.Exists(fileName)) { return -1; } var ext = Path.GetExtension(fileName); string newFileName = $"{Utils.GetGUID()}{ext}"; //newFileName = Path.Combine(Utils.GetTempPath(), newFileName); try { File.Copy(fileName, Utils.GetConfigPath(newFileName)); if (blDelete) { File.Delete(fileName); } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); return -1; } profileItem.address = newFileName; profileItem.configType = EConfigType.Custom; if (Utils.IsNullOrEmpty(profileItem.remarks)) { profileItem.remarks = $"import custom@{DateTime.Now.ToShortDateString()}"; } AddServerCommon(ref config, profileItem, true); return 0; } /// /// 添加服务器或编辑 /// /// /// /// public static int EditCustomServer(ref Config config, ProfileItem profileItem) { if (SqliteHelper.Instance.Update(profileItem) > 0) { return 0; } else { return -1; } //ToJsonFile(config); } /// /// 添加服务器或编辑 /// /// /// /// public static int AddShadowsocksServer(ref Config config, ProfileItem profileItem, bool toFile = true) { profileItem.configType = EConfigType.Shadowsocks; profileItem.address = profileItem.address.TrimEx(); profileItem.id = profileItem.id.TrimEx(); profileItem.security = profileItem.security.TrimEx(); if (!LazyConfig.Instance.GetShadowsocksSecuritys(profileItem).Contains(profileItem.security)) { return -1; } AddServerCommon(ref config, profileItem, toFile); return 0; } /// /// 添加服务器或编辑 /// /// /// /// public static int AddSocksServer(ref Config config, ProfileItem profileItem, bool toFile = true) { profileItem.configType = EConfigType.Socks; profileItem.address = profileItem.address.TrimEx(); AddServerCommon(ref config, profileItem, toFile); return 0; } /// /// 添加服务器或编辑 /// /// /// /// public static int AddTrojanServer(ref Config config, ProfileItem profileItem, bool toFile = true) { profileItem.configType = EConfigType.Trojan; profileItem.address = profileItem.address.TrimEx(); profileItem.id = profileItem.id.TrimEx(); if (Utils.IsNullOrEmpty(profileItem.streamSecurity)) { profileItem.streamSecurity = Global.StreamSecurity; } AddServerCommon(ref config, profileItem, toFile); return 0; } public static int SortServers(ref Config config, string subId, string colName, bool asc) { var lstModel = LazyConfig.Instance.ProfileItems(subId, ""); if (lstModel.Count <= 0) { return -1; } var lstProfileExs = ProfileExHandler.Instance.ProfileExs; var lstProfile = (from t in lstModel join t3 in lstProfileExs on t.indexId equals t3.indexId into t3b from t33 in t3b.DefaultIfEmpty() select new ProfileItemModel { indexId = t.indexId, configType = t.configType, remarks = t.remarks, address = t.address, port = t.port, security = t.security, network = t.network, streamSecurity = t.streamSecurity, delay = t33 == null ? 0 : t33.delay, speed = t33 == null ? 0 : t33.speed, sort = t33 == null ? 0 : t33.sort }).ToList(); Enum.TryParse(colName, true, out EServerColName name); var propertyName = string.Empty; switch (name) { case EServerColName.configType: case EServerColName.remarks: case EServerColName.address: case EServerColName.port: case EServerColName.security: case EServerColName.network: case EServerColName.streamSecurity: propertyName = name.ToString(); break; case EServerColName.delayVal: propertyName = "delay"; break; case EServerColName.speedVal: propertyName = "speed"; break; case EServerColName.subRemarks: propertyName = "subid"; break; default: //return -1; propertyName = "indexId"; break; } var items = lstProfile.AsQueryable(); if (asc) { lstProfile = items.OrderBy(propertyName).ToList(); } else { lstProfile = items.OrderByDescending(propertyName).ToList(); } var lbi = lstProfile.FirstOrDefault(p => p.configType == EConfigType.LoadBalance); if (lbi != null) { lstProfile.Remove(lbi); lstProfile.Insert(0, lbi); } var lpi = lstProfile.FirstOrDefault(p => p.configType == EConfigType.LowestPing); if (lpi != null) { lstProfile.Remove(lpi); lstProfile.Insert(0, lpi); } var usagei = lstProfile.FirstOrDefault(p => p.configType == EConfigType.Usage); if (usagei != null) { lstProfile.Remove(usagei); lstProfile.Insert(0, usagei); } for (int i = 0; i < lstProfile.Count; i++) { ProfileExHandler.Instance.SetSort(lstProfile[i].indexId, (i + 1) * 10); } if (name == EServerColName.delayVal) { var maxSort = lstProfile.Max(t => t.sort) + 10; foreach (var item in lstProfile) { if (item.delay <= 0) { ProfileExHandler.Instance.SetSort(item.indexId, maxSort); } } } if (name == EServerColName.speedVal) { var maxSort = lstProfile.Max(t => t.sort) + 10; foreach (var item in lstProfile) { if (item.speed <= 0) { ProfileExHandler.Instance.SetSort(item.indexId, maxSort); } } } return 0; } class CustomComparer : IComparer { CustomComparer(String property) { } public int Compare(ProfileItem a, ProfileItem b) { if ((int)a.configType > 100 && (int)b.configType < 100) return -1; if ((int)a.configType < 100 && (int)b.configType > 100) return 1; if ((int)a.configType > 100 && (int)b.configType > 100) return (int)a.configType - (int)b.configType; return 0; //return positive if a should be higher, return negative if b should be higher } } /// /// 添加服务器或编辑 /// /// /// /// public static int AddVlessServer(ref Config config, ProfileItem profileItem, bool toFile = true) { profileItem.configType = EConfigType.VLESS; profileItem.address = profileItem.address.TrimEx(); profileItem.id = profileItem.id.TrimEx(); profileItem.security = profileItem.security.TrimEx(); profileItem.network = profileItem.network.TrimEx(); profileItem.headerType = profileItem.headerType.TrimEx(); profileItem.requestHost = profileItem.requestHost.TrimEx(); profileItem.path = profileItem.path.TrimEx(); profileItem.streamSecurity = profileItem.streamSecurity.TrimEx(); if (!Global.flows.Contains(profileItem.flow)) { profileItem.flow = Global.flows.First(); } AddServerCommon(ref config, profileItem, toFile); return 0; } public static Tuple DedupServerList(Config config, string subId) { var lstProfile = LazyConfig.Instance.ProfileItems(subId); List lstKeep = new(); List lstRemove = new(); if (!config.guiItem.keepOlderDedupl) lstProfile.Reverse(); foreach (ProfileItem item in lstProfile) { if (!lstKeep.Exists(i => CompareProfileItem(i, item, false))) { lstKeep.Add(item); } else { lstRemove.Add(item); } } RemoveServer(config, lstRemove); return new Tuple(lstProfile.Count, lstKeep.Count); } public static int AddServerCommon(ref Config config, ProfileItem profileItem, bool toFile = true) { profileItem.configVersion = 2; if (!Utils.IsNullOrEmpty(profileItem.streamSecurity)) { if (Utils.IsNullOrEmpty(profileItem.allowInsecure)) { profileItem.allowInsecure = config.coreBasicItem.defAllowInsecure.ToString().ToLower(); } if (Utils.IsNullOrEmpty(profileItem.fingerprint)) { profileItem.fingerprint = config.coreBasicItem.defFingerprint; } } if (!Utils.IsNullOrEmpty(profileItem.network) && !Global.networks.Contains(profileItem.network)) { profileItem.network = Global.DefaultNetwork; } if (Utils.IsNullOrEmpty(profileItem.indexId)) { profileItem.indexId = Utils.GetGUID(false); var maxSort = ProfileExHandler.Instance.GetMaxSort(); ProfileExHandler.Instance.SetSort(profileItem.indexId, maxSort + 1); } if (toFile) { SqliteHelper.Instance.Replace(profileItem); } return 0; } private static bool CompareProfileItem(ProfileItem o, ProfileItem n, bool remarks) { if (o == null || n == null) { return false; } return o.configType == n.configType && o.address == n.address && o.port == n.port && o.id == n.id && o.alterId == n.alterId && o.security == n.security && o.network == n.network && o.headerType == n.headerType && o.requestHost == n.requestHost && o.path == n.path && (o.configType == EConfigType.Trojan || o.streamSecurity == n.streamSecurity) && o.flow == n.flow && o.sni == n.sni && (!remarks || o.remarks == n.remarks); } private static int RemoveProfileItem(Config config, string indexId) { try { var item = LazyConfig.Instance.GetProfileItem(indexId); if (item == null) { return 0; } if (item.configType == EConfigType.Custom) { File.Delete(Utils.GetConfigPath(item.address)); } SqliteHelper.Instance.Delete(item); } catch (Exception ex) { Utils.SaveLog("Remove Item", ex); } return 0; } #endregion Server #region Batch add servers /// /// 批量添加服务器 /// /// /// /// /// 成功导入的数量 private static int AddBatchServers(ref Config config, string clipboardData, string subid, bool isSub, List lstOriSub) { if (Utils.IsNullOrEmpty(clipboardData)) { return -1; } string subFilter = string.Empty; //remove sub items if (isSub && !Utils.IsNullOrEmpty(subid)) { RemoveServerViaSubid(ref config, subid, isSub); subFilter = LazyConfig.Instance.GetSubItem(subid)?.filter ?? ""; var subitem = LazyConfig.Instance.GetSubItem(subid); } int countServers = 0; //Check for duplicate indexId List? lstDbIndexId = null; List lstAdd = new(); var arrData = clipboardData.Split(Environment.NewLine.ToCharArray()).Where(t => !t.IsNullOrEmpty()); if (isSub) { arrData = arrData.Distinct(); } foreach (string str in arrData) { //maybe sub if (!isSub && (str.StartsWith(Global.httpsProtocol) || str.StartsWith(Global.httpProtocol))) { //// It's a custom feature for this app (probably none of your business) //string? panelAddress = Utils.GetHostAndFirstTwoPathInUri(str); //// If we can't get panel address we just put host address in there //if (panelAddress == null) //{ // panelAddress = new Uri(str).Host; //} // WE SAVE THIS INFORMATION IN SubItem ITSELF (NOT AS ROW/SERVER) //var usageItem = new ProfileItem() //{ // configType = EConfigType.Usage, // remarks = $"{userSubInfo.DownloadAndUploadTotalGigaBytes()}GB/{userSubInfo.TotalGigaBytes()}GB ", // security = $"Expire in {userSubInfo.DaysLeftToExpire()} days", // // Direct panel address // address = panelAddress, // coreType = ECoreType.Xray, // subid = subid //}; //AddServerCommon(ref config, usageItem, false); var LowestPingItem = new ProfileItem() { configType = EConfigType.LowestPing, remarks = "Lowest Ping", address = "All", coreType = ECoreType.Xray, subid = subid }; AddServerCommon(ref config, LowestPingItem, false); var loadBalanceItem = new ProfileItem() { configType = EConfigType.LoadBalance, remarks = "Load Balance", address = "All", coreType = ECoreType.Xray, subid = subid }; AddServerCommon(ref config, loadBalanceItem, false); var subName = Utils.ExtractNameParameterFromUri(str); // If it's sub, We get remaining day to expire & used data & total remained data & profile web page url // We add this information as a Server but these's just for display to user for their information // Get user subscription info (like donwloaded/uploaded/total usage and expire date) // Get expire epoch date var headers = Utils.GetUrlResponseHeader(str,false); var subInfo = Utils.GetSubscriptionInfoFromHeaders(headers); //if (subInfo == null) //{ // // Handle error //} SubItem subscriptionItem = new SubItem(); subscriptionItem.id = Utils.GetGUID(false); subscriptionItem.remarks = subName; if (subInfo != null) { subscriptionItem.upload = subInfo.Upload; subscriptionItem.download = subInfo.Download; subscriptionItem.total = subInfo.Total; subscriptionItem.expireDate = subInfo.ExpireDate; subscriptionItem.remaningExpireDays = subscriptionItem.DaysLeftToExpire(); subscriptionItem.UsedDataGB = subscriptionItem.UsedDataGigaBytes(); subscriptionItem.TotalDataGB = subscriptionItem.TotalDataGigaBytes(); subscriptionItem.profileWebPageUrl = subInfo.ProfileWebPageUrl; if (!subInfo.ProfileTitle.IsNullOrWhiteSpace()) { subscriptionItem.remarks = subInfo.ProfileTitle ?? ""; if (subscriptionItem.remarks.StartsWith("base64:")){ subscriptionItem.remarks = Utils.Base64Decode(subscriptionItem.remarks.Substring("base64:".Length)); } } } if (subscriptionItem.remarks != null) { if (AddSubItem(ref config, subscriptionItem) == 0) { countServers++; } } continue; } // Add server(s) ProfileItem profileItem = ShareHandler.ImportFromClipboardConfig(str, out string msg); if (profileItem == null) { continue; } //exist sub items if (isSub && !Utils.IsNullOrEmpty(subid)) { var existItem = lstOriSub?.FirstOrDefault(t => t.isSub == isSub && CompareProfileItem(t, profileItem, true)); if (existItem != null) { //Check for duplicate indexId if (lstDbIndexId is null) { lstDbIndexId = LazyConfig.Instance.ProfileItemIndexs(""); } if (lstAdd.Any(t => t.indexId == existItem.indexId) || lstDbIndexId.Any(t => t == existItem.indexId)) { profileItem.indexId = string.Empty; } else { profileItem.indexId = existItem.indexId; } } //filter if (!Utils.IsNullOrEmpty(subFilter)) { if (!Regex.IsMatch(profileItem.remarks, subFilter)) { continue; } } } profileItem.subid = subid; profileItem.isSub = isSub; var addStatus = -1; if (profileItem.configType == EConfigType.VMess) { addStatus = AddServer(ref config, profileItem, false); } else if (profileItem.configType == EConfigType.Shadowsocks) { addStatus = AddShadowsocksServer(ref config, profileItem, false); } else if (profileItem.configType == EConfigType.Socks) { addStatus = AddSocksServer(ref config, profileItem, false); } else if (profileItem.configType == EConfigType.Trojan) { addStatus = AddTrojanServer(ref config, profileItem, false); } else if (profileItem.configType == EConfigType.VLESS) { addStatus = AddVlessServer(ref config, profileItem, false); } if (addStatus == 0 && profileItem.port > 0) { if (countServers == 0) { // lstAdd.Add(usageItem); var LowestPingItem = new ProfileItem() { configType = EConfigType.LowestPing, remarks = "Lowest Ping", address = "All", coreType = ECoreType.Xray, subid = subid, indexId = "0" + new Random().Next(0, 10000000) }; AddServerCommon(ref config, LowestPingItem, false); var loadBalanceItem = new ProfileItem() { configType = EConfigType.LoadBalance, remarks = "Load Balance", address = "All", coreType = ECoreType.Xray, subid = subid, indexId = "1" + new Random().Next(0, 10000000) }; AddServerCommon(ref config, loadBalanceItem, false); lstAdd.Add(LowestPingItem); lstAdd.Add(loadBalanceItem); } countServers++; lstAdd.Add(profileItem); } } if (lstAdd.Count > 0) { SqliteHelper.Instance.InsertAll(lstAdd); } ToJsonFile(config); return countServers; } public static (int,List) HomeAddBatchServers(ref Config config, string clipboardData, string subid, bool isSub, List lstOriSub) { List addedSubIds = new(); if (Utils.IsNullOrEmpty(clipboardData)) { return (-1, addedSubIds); } string subFilter = string.Empty; //remove sub items if (isSub && !Utils.IsNullOrEmpty(subid)) { RemoveServerViaSubid(ref config, subid, isSub); subFilter = LazyConfig.Instance.GetSubItem(subid)?.filter ?? ""; var subitem = LazyConfig.Instance.GetSubItem(subid); } int countServers = 0; // We keep servers in this variable to add and join them to new sub List servers = new(); string[] arrData = clipboardData.Split(Environment.NewLine.ToCharArray()); foreach (string str in arrData) { if (Utils.IsNullOrEmpty(str)) { continue; } // If it's sub we just add a sub //maybe sub if (str.StartsWith(Global.httpsProtocol) || str.StartsWith(Global.httpProtocol)) { // Get user subscription info (like donwloaded/uploaded/total usage and expire date) // Get expire epoch date var headers = Utils.GetUrlResponseHeader(str,false); var subInfo = Utils.GetSubscriptionInfoFromHeaders(headers); //if (subInfo == null) //{ // // Handle error //} SubItem subscriptionItem = new SubItem(); subscriptionItem.id = Utils.GetGUID(false); subscriptionItem.url = str; var LowestPingItem = new ProfileItem() { configType = EConfigType.LowestPing, remarks = "Lowest Ping", address = "All", coreType = ECoreType.Xray, subid = subscriptionItem.id }; AddServerCommon(ref config, LowestPingItem, false); var loadBalanceItem = new ProfileItem() { configType = EConfigType.LoadBalance, remarks = "Load Balance", address = "All", coreType = ECoreType.Xray, subid = subscriptionItem.id }; AddServerCommon(ref config, loadBalanceItem, false); var subName = Utils.ExtractNameParameterFromUri(str); int lastSsdortNumber = LazyConfig.Instance.GetLastSubItemSortNumber(); if (subName == null) { int lastSortNumber = LazyConfig.Instance.GetLastSubItemSortNumber(); subscriptionItem.remarks = $"Subscription {lastSortNumber + 1}"; } else { subscriptionItem.remarks = subName; } if (subInfo != null) { subscriptionItem.upload = subInfo.Upload; subscriptionItem.download = subInfo.Download; subscriptionItem.total = subInfo.Total; subscriptionItem.expireDate = subInfo.ExpireDate; subscriptionItem.remaningExpireDays = subscriptionItem.DaysLeftToExpire(); subscriptionItem.UsedDataGB = subscriptionItem.UsedDataGigaBytes(); subscriptionItem.TotalDataGB = subscriptionItem.TotalDataGigaBytes(); subscriptionItem.profileWebPageUrl = subInfo.ProfileWebPageUrl; } if (subscriptionItem.remarks != null) { if (AddSubItem(ref config, subscriptionItem) == 0) { countServers++; } } addedSubIds.Add(subscriptionItem.id); continue; } // It's server, So we collect all servers and create a new sub and we'll make the servers the subscription member ProfileItem profileItem = ShareHandler.ImportFromClipboardConfig(str, out string msg); if (profileItem == null) { continue; } //exist sub items if (isSub && !Utils.IsNullOrEmpty(subid)) { var existItem = lstOriSub?.FirstOrDefault(t => t.isSub == isSub && CompareProfileItem(t, profileItem, true)); if (existItem != null) { profileItem.indexId = existItem.indexId; } //filter if (!Utils.IsNullOrEmpty(subFilter)) { if (!Regex.IsMatch(profileItem.remarks, subFilter)) { continue; } } } profileItem.subid = subid; profileItem.isSub = isSub; servers.Add(profileItem); } if (servers.Count < 1) { return (0,addedSubIds); } // We create a sub and add the servers to it SubItem subItem = new SubItem(); subItem.id = Utils.GetGUID(false); subItem.remarks = $"Profile {subItem.sort}"; // Add sub if (AddSubItem(ref config, subItem) != 0) { // Handle error } // Add servers to the sub int addStatus = -1; foreach (ProfileItem item in servers) { item.subid = subItem.id; if (item.configType == EConfigType.VMess) { addStatus = AddServer(ref config, item, false); } else if (item.configType == EConfigType.Shadowsocks) { addStatus = AddShadowsocksServer(ref config, item, false); } else if (item.configType == EConfigType.Socks) { addStatus = AddSocksServer(ref config, item, false); } else if (item.configType == EConfigType.Trojan) { addStatus = AddTrojanServer(ref config, item, false); } else if (item.configType == EConfigType.VLESS) { addStatus = AddVlessServer(ref config, item, false); } if (addStatus == 0) { countServers++; } } if (countServers != 0) { // lstAdd.Add(usageItem); var LowestPingItem = new ProfileItem() { configType = EConfigType.LowestPing, remarks = "Lowest Ping", address = "All", coreType = ECoreType.Xray, subid = subItem.id, indexId = "0" + new Random().Next(0, 10000000) }; AddServerCommon(ref config, LowestPingItem, false); countServers++; var loadBalanceItem = new ProfileItem() { configType = EConfigType.LoadBalance, remarks = "Load Balance", address = "All", coreType = ECoreType.Xray, subid = subItem.id, indexId = "1" + new Random().Next(0, 10000000) }; AddServerCommon(ref config, loadBalanceItem, false); countServers++; servers.Add(LowestPingItem); servers.Add(loadBalanceItem); } if (servers.Count > 0) { SqliteHelper.Instance.InsertAll(servers); } ToJsonFile(config); return (countServers,addedSubIds); } private static int AddBatchServers4Custom(ref Config config, string clipboardData, string subid, bool isSub, List lstOriSub) { if (Utils.IsNullOrEmpty(clipboardData)) { return -1; } //判断str是否包含s的任意一个字符串 static bool Containss(string str, params string[] s) { foreach (var item in s) { if (str.Contains(item, StringComparison.OrdinalIgnoreCase)) return true; } return false; } ProfileItem profileItem = new(); //Is v2ray configuration V2rayConfig? v2rayConfig = Utils.FromJson(clipboardData); if (v2rayConfig?.inbounds?.Count > 0 && v2rayConfig.outbounds?.Count > 0) { var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json"); File.WriteAllText(fileName, clipboardData); profileItem.coreType = ECoreType.Xray; profileItem.address = fileName; profileItem.remarks = "v2ray_custom"; } //Is Clash configuration else if (Containss(clipboardData, "port", "socks-port", "proxies")) { var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.yaml"); File.WriteAllText(fileName, clipboardData); profileItem.coreType = ECoreType.clash; profileItem.address = fileName; profileItem.remarks = "clash_custom"; } //Is hysteria configuration else if (Containss(clipboardData, "server", "up", "down", "listen", "", "")) { var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json"); File.WriteAllText(fileName, clipboardData); profileItem.coreType = ECoreType.hysteria; profileItem.address = fileName; profileItem.remarks = "hysteria_custom"; } //Is naiveproxy configuration else if (Containss(clipboardData, "listen", "proxy", "", "")) { var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json"); File.WriteAllText(fileName, clipboardData); profileItem.coreType = ECoreType.naiveproxy; profileItem.address = fileName; profileItem.remarks = "naiveproxy_custom"; } //Is Other configuration else { return -1; //var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.txt"); //File.WriteAllText(fileName, clipboardData); //profileItem.address = fileName; //profileItem.remarks = "other_custom"; } if (isSub && !Utils.IsNullOrEmpty(subid)) { RemoveServerViaSubid(ref config, subid, isSub); } if (isSub && lstOriSub?.Count == 1) { profileItem.indexId = lstOriSub[0].indexId; } profileItem.subid = subid; profileItem.isSub = isSub; if (Utils.IsNullOrEmpty(profileItem.address)) { return -1; } if (AddCustomServer(ref config, profileItem, true) == 0) { return 1; } else { return -1; } } private static int AddBatchServers4SsSIP008(ref Config config, string clipboardData, string subid, bool isSub, List lstOriSub) { if (Utils.IsNullOrEmpty(clipboardData)) { return -1; } if (isSub && !Utils.IsNullOrEmpty(subid)) { RemoveServerViaSubid(ref config, subid, isSub); } //SsSIP008 var lstSsServer = Utils.FromJson>(clipboardData); if (lstSsServer?.Count <= 0) { var ssSIP008 = Utils.FromJson(clipboardData); if (ssSIP008?.servers?.Count > 0) { lstSsServer = ssSIP008.servers; } } if (lstSsServer?.Count > 0) { int counter = 0; foreach (var it in lstSsServer) { var ssItem = new ProfileItem() { subid = subid, remarks = it.remarks, security = it.method, id = it.password, address = it.server, port = Utils.ToInt(it.server_port) }; ssItem.subid = subid; ssItem.isSub = isSub; if (AddShadowsocksServer(ref config, ssItem) == 0) { counter++; } } ToJsonFile(config); return counter; } return -1; } public static int AddBatchServers(ref Config config, string clipboardData, string subid, bool isSub) { List? lstOriSub = null; if (isSub && !Utils.IsNullOrEmpty(subid)) { lstOriSub = LazyConfig.Instance.ProfileItems(subid); } var counter = 0; if (Utils.IsBase64String(clipboardData)) { counter = AddBatchServers(ref config, Utils.Base64Decode(clipboardData), subid, isSub, lstOriSub); } if (counter < 1) { counter = AddBatchServers(ref config, clipboardData, subid, isSub, lstOriSub); } if (counter < 1) { counter = AddBatchServers(ref config, Utils.Base64Decode(clipboardData), subid, isSub, lstOriSub); } if (counter < 1) { counter = AddBatchServers4SsSIP008(ref config, clipboardData, subid, isSub, lstOriSub); } //maybe other sub if (counter < 1) { counter = AddBatchServers4Custom(ref config, clipboardData, subid, isSub, lstOriSub); } return counter; } #endregion Batch add servers #region Sub & Group /// /// add sub /// /// /// /// public static int AddSubItem(ref Config config, string url, string? subName, SubscriptionInfo? subInfo) { //already exists if (SqliteHelper.Instance.Table().Where(e => e.url == url).Count() > 0) { return 0; } if (subName == null) { subName = "Imported Sub"; } SubItem subItem = new() { id = string.Empty, remarks = subName, url = url }; if (subInfo != null) { subItem.upload = subInfo.Upload; subItem.download = subInfo.Download; subItem.total = subInfo.Total; subItem.expireDate = subInfo.ExpireDate; subItem.profileWebPageUrl = subInfo.ProfileWebPageUrl; } return AddSubItem(ref config, subItem); } public static int AddSubItem(ref Config config, SubItem subItem,bool doNotFocusOnWindowAfterAdd = false) { if (Utils.IsNullOrEmpty(subItem.id)) { subItem.id = Utils.GetGUID(false); if (subItem.sort <= 0) { var maxSort = 0; if (SqliteHelper.Instance.Table().Count() > 0) { maxSort = SqliteHelper.Instance.Table().Max(t => t == null ? 0 : t.sort); } subItem.sort = maxSort + 1; } } if (subItem.sort <= 0) { var maxSort = 0; if (SqliteHelper.Instance.Table().Count() > 0) { maxSort = SqliteHelper.Instance.Table().Max(t => t == null ? 0 : t.sort); } subItem.sort = maxSort + 1; } var subs = LazyConfig.Instance.SubItems(); // Do not add the sub if it's already exist foreach (SubItem item in subs) { if (subItem.url == item.url) return 0; } if (SqliteHelper.Instance.Replace(subItem) > 0) { if (!doNotFocusOnWindowAfterAdd) Utils.SetMainPageReload(); return 0; } else { return -1; } } /// /// 移除服务器 /// /// /// /// public static int RemoveServerViaSubid(ref Config config, string subid, bool isSub) { if (Utils.IsNullOrEmpty(subid)) { return -1; } var customProfile = SqliteHelper.Instance.Table().Where(t => t.subid == subid && t.configType == EConfigType.Custom).ToList(); if (isSub) { SqliteHelper.Instance.Execute($"delete from ProfileItem where isSub = 1 and subid = '{subid}'"); } else { SqliteHelper.Instance.Execute($"delete from ProfileItem where subid = '{subid}'"); } foreach (var item in customProfile) { File.Delete(Utils.GetConfigPath(item.address)); } return 0; } public static int DeleteSubItem(ref Config config, string id) { var item = LazyConfig.Instance.GetSubItem(id); if (item is null) { return 0; } SqliteHelper.Instance.Delete(item); RemoveServerViaSubid(ref config, id, false); return 0; } public static int MoveToGroup(Config config, List lstProfile, string subid) { foreach (var item in lstProfile) { item.subid = subid; } SqliteHelper.Instance.UpdateAll(lstProfile); return 0; } #endregion Sub & Group #region Routing public static int SaveRoutingItem(ref Config config, RoutingItem item) { if (Utils.IsNullOrEmpty(item.id)) { item.id = Utils.GetGUID(false); } if (SqliteHelper.Instance.Replace(item) > 0) { return 0; } else { return -1; } } /// /// AddBatchRoutingRules /// /// /// /// public static int AddBatchRoutingRules(ref RoutingItem routingItem, string clipboardData) { if (Utils.IsNullOrEmpty(clipboardData)) { return -1; } var lstRules = Utils.FromJson>(clipboardData); if (lstRules == null) { return -1; } foreach (var item in lstRules) { item.id = Utils.GetGUID(false); } routingItem.ruleNum = lstRules.Count; routingItem.ruleSet = Utils.ToJson(lstRules, false); if (Utils.IsNullOrEmpty(routingItem.id)) { routingItem.id = Utils.GetGUID(false); } if (SqliteHelper.Instance.Replace(routingItem) > 0) { return 0; } else { return -1; } } /// /// MoveRoutingRule /// /// /// /// /// public static int MoveRoutingRule(List rules, int index, EMove eMove, int pos = -1) { int count = rules.Count; if (index < 0 || index > rules.Count - 1) { return -1; } switch (eMove) { case EMove.Top: { if (index == 0) { return 0; } var item = Utils.DeepCopy(rules[index]); rules.RemoveAt(index); rules.Insert(0, item); break; } case EMove.Up: { if (index == 0) { return 0; } var item = Utils.DeepCopy(rules[index]); rules.RemoveAt(index); rules.Insert(index - 1, item); break; } case EMove.Down: { if (index == count - 1) { return 0; } var item = Utils.DeepCopy(rules[index]); rules.RemoveAt(index); rules.Insert(index + 1, item); break; } case EMove.Bottom: { if (index == count - 1) { return 0; } var item = Utils.DeepCopy(rules[index]); rules.RemoveAt(index); rules.Add(item); break; } case EMove.Position: { var removeItem = rules[index]; var item = Utils.DeepCopy(rules[index]); rules.Insert(pos, item); rules.Remove(removeItem); break; } } return 0; } public static int SetDefaultRouting(ref Config config, RoutingItem routingItem) { if (SqliteHelper.Instance.Table().Where(t => t.id == routingItem.id).Count() > 0) { config.routingBasicItem.routingIndexId = routingItem.id; } ToJsonFile(config); return 0; } public static RoutingItem GetDefaultRouting(ref Config config) { var item = LazyConfig.Instance.GetRoutingItem(config.routingBasicItem.routingIndexId); if (item is null) { var item2 = SqliteHelper.Instance.Table().FirstOrDefault(t => t.locked == false); SetDefaultRouting(ref config, item2); return item2; } return item; } public static int InitBuiltinRouting(ref Config config, bool blImportAdvancedRules = false) { var items = LazyConfig.Instance.RoutingItems(); if (blImportAdvancedRules || items.Count <= 0) { var maxSort = items.Count; //Bypass the mainland var item2 = new RoutingItem() { remarks = "All Foreign Sites سایتهای خارجی", url = string.Empty, sort = maxSort + 1, }; AddBatchRoutingRules(ref item2, Utils.GetEmbedText(Global.CustomRoutingFileName + "white")); //Blacklist var item3 = new RoutingItem() { remarks = "Only blocked sites فقط سایت های فیلتر", url = string.Empty, sort = maxSort + 2, }; AddBatchRoutingRules(ref item3, Utils.GetEmbedText(Global.CustomRoutingFileName + "black")); //Global var item1 = new RoutingItem() { remarks = "Global", url = string.Empty, sort = maxSort + 3, }; AddBatchRoutingRules(ref item1, Utils.GetEmbedText(Global.CustomRoutingFileName + "global")); if (!blImportAdvancedRules) { SetDefaultRouting(ref config, item2); } } if (GetLockedRoutingItem(ref config) == null) { var item1 = new RoutingItem() { remarks = "locked", url = string.Empty, locked = true, }; AddBatchRoutingRules(ref item1, Utils.GetEmbedText(Global.CustomRoutingFileName + "locked")); } return 0; } public static RoutingItem GetLockedRoutingItem(ref Config config) { return SqliteHelper.Instance.Table().FirstOrDefault(it => it.locked == true); } public static void RemoveRoutingItem(RoutingItem routingItem) { SqliteHelper.Instance.Delete(routingItem); } #endregion Routing #region DNS public static int InitBuiltinDNS(Config config) { var items = LazyConfig.Instance.DNSItems(); if (items.Count <= 0) { var item = new DNSItem() { remarks = "V2ray", coreType = ECoreType.Xray, }; SaveDNSItems(config, item); var item2 = new DNSItem() { remarks = "sing-box", coreType = ECoreType.sing_box, }; SaveDNSItems(config, item2); } return 0; } public static int SaveDNSItems(Config config, DNSItem item) { if (Utils.IsNullOrEmpty(item.id)) { item.id = Utils.GetGUID(false); } if (SqliteHelper.Instance.Replace(item) > 0) { return 0; } else { return -1; } } #endregion DNS } } ================================================ FILE: v2rayN/v2rayN/Handler/CoreConfigHandler.cs ================================================ using System.IO; using v2rayN.Mode; using v2rayN.Resx; namespace v2rayN.Handler { /// /// Core configuration file processing class /// internal class CoreConfigHandler { public static int GenerateClientConfig(ProfileItem node, string? fileName, out string msg, out string content) { content = string.Empty; try { if (node == null) { msg = ResUI.CheckServerSettings; return -1; } msg = ResUI.InitialConfiguration; if (node.configType == EConfigType.Custom) { return GenerateClientCustomConfig(node, fileName, out msg); } /*hiddify{*/ else if (node.configType == EConfigType.LowestPing || node.configType == EConfigType.LoadBalance) { var coreConfigV2ray = new CoreConfigV2ray(LazyConfig.Instance.GetConfig()); if (coreConfigV2ray.HiddifyGenerateSubConfigContent(node, out V2rayConfig? v2rayConfig, out msg) != 0) { return -1; } if (Utils.IsNullOrEmpty(fileName)) { content = Utils.ToJson(v2rayConfig); } else { Utils.ToJsonFile(v2rayConfig, fileName, false); } } /*hiddify}*/ else if (LazyConfig.Instance.GetCoreType(node, node.configType) == ECoreType.sing_box) { var configGenSingbox = new CoreConfigSingbox(LazyConfig.Instance.GetConfig()); if (configGenSingbox.GenerateClientConfigContent(node, out SingboxConfig? singboxConfig, out msg) != 0) { return -1; } if (Utils.IsNullOrEmpty(fileName)) { content = Utils.ToJson(singboxConfig); } else { Utils.ToJsonFile(singboxConfig, fileName, false); } } else { var coreConfigV2ray = new CoreConfigV2ray(LazyConfig.Instance.GetConfig()); if (coreConfigV2ray.GenerateClientConfigContent(node, out V2rayConfig? v2rayConfig, out msg) != 0) { return -1; } if (Utils.IsNullOrEmpty(fileName)) { content = Utils.ToJson(v2rayConfig); } else { Utils.ToJsonFile(v2rayConfig, fileName, false); } } } catch (Exception ex) { Utils.SaveLog("GenerateClientConfig", ex); msg = ResUI.FailedGenDefaultConfiguration; return -1; } return 0; } private static int GenerateClientCustomConfig(ProfileItem node, string? fileName, out string msg) { try { if (node == null || fileName is null) { msg = ResUI.CheckServerSettings; return -1; } if (File.Exists(fileName)) { File.Delete(fileName); } string addressFileName = node.address; if (!File.Exists(addressFileName)) { addressFileName = Utils.GetConfigPath(addressFileName); } if (!File.Exists(addressFileName)) { msg = ResUI.FailedGenDefaultConfiguration; return -1; } File.Copy(addressFileName, fileName); //check again if (!File.Exists(fileName)) { msg = ResUI.FailedGenDefaultConfiguration; return -1; } //overwrite port if (node.preSocksPort <= 0) { var fileContent = File.ReadAllLines(fileName).ToList(); var coreType = LazyConfig.Instance.GetCoreType(node, node.configType); switch (coreType) { case ECoreType.v2fly: case ECoreType.SagerNet: case ECoreType.Xray: case ECoreType.v2fly_v5: break; case ECoreType.clash: case ECoreType.clash_meta: //remove the original var indexPort = fileContent.FindIndex(t => t.Contains("port:")); if (indexPort >= 0) { fileContent.RemoveAt(indexPort); } indexPort = fileContent.FindIndex(t => t.Contains("socks-port:")); if (indexPort >= 0) { fileContent.RemoveAt(indexPort); } fileContent.Add($"port: {LazyConfig.Instance.GetLocalPort(Global.InboundHttp)}"); fileContent.Add($"socks-port: {LazyConfig.Instance.GetLocalPort(Global.InboundSocks)}"); break; } File.WriteAllLines(fileName, fileContent); } msg = string.Format(ResUI.SuccessfulConfiguration, ""); } catch (Exception ex) { Utils.SaveLog("GenerateClientCustomConfig", ex); msg = ResUI.FailedGenDefaultConfiguration; return -1; } return 0; } public static string GenerateClientSpeedtestConfigString(Config config, List selecteds, out string msg) { var coreConfigV2ray = new CoreConfigV2ray(config); return coreConfigV2ray.GenerateClientSpeedtestConfigString(selecteds, out msg); } } } ================================================ FILE: v2rayN/v2rayN/Handler/CoreConfigSingbox.cs ================================================ using v2rayN.Base; using v2rayN.Mode; using v2rayN.Resx; namespace v2rayN.Handler { internal class CoreConfigSingbox { private string SampleClient = Global.SingboxSampleClient; private Config _config; public CoreConfigSingbox(Config config) { _config = config; } public int GenerateClientConfigContent(ProfileItem node, out SingboxConfig? singboxConfig, out string msg) { singboxConfig = null; try { if (node == null || node.port <= 0) { msg = ResUI.CheckServerSettings; return -1; } msg = ResUI.InitialConfiguration; string result = Utils.GetEmbedText(SampleClient); if (Utils.IsNullOrEmpty(result)) { msg = ResUI.FailedGetDefaultConfiguration; return -1; } singboxConfig = Utils.FromJson(result); if (singboxConfig == null) { msg = ResUI.FailedGenDefaultConfiguration; return -1; } log(singboxConfig); inbound(singboxConfig); outbound(node, singboxConfig); routing(singboxConfig); dns(node, singboxConfig); //statistic(singboxConfig); msg = string.Format(ResUI.SuccessfulConfiguration, ""); } catch (Exception ex) { Utils.SaveLog("GenerateClientConfig4Singbox", ex); msg = ResUI.FailedGenDefaultConfiguration; return -1; } return 0; } private int log(SingboxConfig singboxConfig) { try { switch (_config.coreBasicItem.loglevel) { case "debug": case "info": case "error": singboxConfig.log.level = _config.coreBasicItem.loglevel; break; case "warning": singboxConfig.log.level = "warn"; break; default: break; } if (_config.coreBasicItem.loglevel == "none") { singboxConfig.log.disabled = true; } if (_config.coreBasicItem.logEnabled) { var dtNow = DateTime.Now; singboxConfig.log.output = Utils.GetLogPath($"sbox_{dtNow:yyyy-MM-dd}.txt"); } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } return 0; } #region inbound private private int inbound(SingboxConfig singboxConfig) { try { if (_config.tunModeItem.enableTun) { singboxConfig.inbounds.Clear(); if (_config.tunModeItem.mtu <= 0) { _config.tunModeItem.mtu = Convert.ToInt32(Global.TunMtus[0]); } if (Utils.IsNullOrEmpty(_config.tunModeItem.stack)) { _config.tunModeItem.stack = Global.TunStacks[0]; } var tunInbound = Utils.FromJson(Utils.GetEmbedText(Global.TunSingboxInboundFileName)); tunInbound.mtu = _config.tunModeItem.mtu; tunInbound.strict_route = _config.tunModeItem.strictRoute; tunInbound.stack = _config.tunModeItem.stack; singboxConfig.inbounds.Add(tunInbound); } else { var inbound = singboxConfig.inbounds[0]; inbound.listen_port = LazyConfig.Instance.GetLocalPort(Global.InboundSocks); inbound.sniff = _config.inbound[0].sniffingEnabled; inbound.sniff_override_destination = _config.inbound[0].routeOnly ? false : _config.inbound[0].sniffingEnabled; inbound.domain_strategy = Utils.IsNullOrEmpty(_config.routingBasicItem.domainStrategy4Singbox) ? null : _config.routingBasicItem.domainStrategy4Singbox; if (_config.routingBasicItem.enableRoutingAdvanced) { var routing = ConfigHandler.GetDefaultRouting(ref _config); if (!Utils.IsNullOrEmpty(routing.domainStrategy4Singbox)) { inbound.domain_strategy = routing.domainStrategy4Singbox; } } //http var inbound2 = GetInbound(inbound, Global.InboundHttp, 1, false); singboxConfig.inbounds.Add(inbound2); if (_config.inbound[0].allowLANConn) { if (_config.inbound[0].newPort4LAN) { var inbound3 = GetInbound(inbound, Global.InboundSocks2, 2, true); inbound3.listen = "::"; singboxConfig.inbounds.Add(inbound3); var inbound4 = GetInbound(inbound, Global.InboundHttp2, 3, false); inbound4.listen = "::"; singboxConfig.inbounds.Add(inbound4); //auth if (!Utils.IsNullOrEmpty(_config.inbound[0].user) && !Utils.IsNullOrEmpty(_config.inbound[0].pass)) { inbound3.users = new() { new() { username = _config.inbound[0].user, password = _config.inbound[0].pass } }; inbound4.users = new() { new() { username = _config.inbound[0].user, password = _config.inbound[0].pass } }; } } else { inbound.listen = "::"; inbound2.listen = "::"; } } } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } return 0; } private Inbound4Sbox? GetInbound(Inbound4Sbox inItem, string tag, int offset, bool bSocks) { var inbound = Utils.DeepCopy(inItem); inbound.tag = tag; inbound.listen_port = inItem.listen_port + offset; inbound.type = bSocks ? Global.InboundSocks : Global.InboundHttp; return inbound; } #endregion inbound private #region outbound private private int outbound(ProfileItem node, SingboxConfig singboxConfig) { try { if (_config.tunModeItem.enableTun) { singboxConfig.outbounds.Add(new() { type = "dns", tag = "dns_out" }); } var outbound = singboxConfig.outbounds[0]; outbound.server = node.address; outbound.server_port = node.port; if (node.configType == EConfigType.VMess) { outbound.type = Global.vmessProtocolLite; outbound.uuid = node.id; outbound.alter_id = node.alterId; if (Global.vmessSecuritys.Contains(node.security)) { outbound.security = node.security; } else { outbound.security = Global.DefaultSecurity; } outboundMux(node, outbound); } else if (node.configType == EConfigType.Shadowsocks) { outbound.type = Global.ssProtocolLite; outbound.method = LazyConfig.Instance.GetShadowsocksSecuritys(node).Contains(node.security) ? node.security : "none"; outbound.password = node.id; outboundMux(node, outbound); } else if (node.configType == EConfigType.Socks) { outbound.type = Global.socksProtocolLite; outbound.version = "5"; if (!Utils.IsNullOrEmpty(node.security) && !Utils.IsNullOrEmpty(node.id)) { outbound.username = node.security; outbound.password = node.id; } } else if (node.configType == EConfigType.VLESS) { outbound.type = Global.vlessProtocolLite; outbound.uuid = node.id; outbound.flow = node.flow; outbound.packet_encoding = "xudp"; } else if (node.configType == EConfigType.Trojan) { outbound.type = Global.trojanProtocolLite; outbound.password = node.id; outboundMux(node, outbound); } outboundTls(node, outbound); outboundTransport(node, outbound); } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } return 0; } private int outboundMux(ProfileItem node, Outbound4Sbox outbound) { try { if (_config.coreBasicItem.muxEnabled) { var mux = new Multiplex4Sbox() { enabled = true, protocol = "smux", max_connections = 4, min_streams = 4, max_streams = 0, }; outbound.multiplex = mux; } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } return 0; } private int outboundTls(ProfileItem node, Outbound4Sbox outbound) { try { if (node.streamSecurity == Global.StreamSecurityReality || node.streamSecurity == Global.StreamSecurity) { var tls = new Tls4Sbox() { enabled = true, server_name = node.sni, insecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? _config.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure), alpn = node.GetAlpn(), }; if (!Utils.IsNullOrEmpty(node.fingerprint)) { tls.utls = new Utls4Sbox() { enabled = true, fingerprint = node.fingerprint.IsNullOrEmpty() ? _config.coreBasicItem.defFingerprint : node.fingerprint }; } if (node.streamSecurity == Global.StreamSecurityReality) { tls.reality = new Reality4Sbox() { enabled = true, public_key = node.publicKey, short_id = node.shortId }; tls.insecure = false; } outbound.tls = tls; } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } return 0; } private int outboundTransport(ProfileItem node, Outbound4Sbox outbound) { try { var transport = new Transport4Sbox(); switch (node.GetNetwork()) { case "h2": transport.type = "http"; transport.host = Utils.IsNullOrEmpty(node.requestHost) ? null : Utils.String2List(node.requestHost); transport.path = Utils.IsNullOrEmpty(node.path) ? null : node.path; break; case "ws": transport.type = "ws"; transport.path = Utils.IsNullOrEmpty(node.path) ? null : node.path; break; case "quic": transport.type = "quic"; break; case "grpc": transport.type = "grpc"; transport.service_name = node.path; transport.idle_timeout = _config.grpcItem.idle_timeout.ToString("##s"); transport.ping_timeout = _config.grpcItem.health_check_timeout.ToString("##s"); transport.permit_without_stream = _config.grpcItem.permit_without_stream; break; default: transport = null; break; } outbound.transport = transport; } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } return 0; } #endregion outbound private #region routing rule private private int routing(SingboxConfig singboxConfig) { try { if (_config.tunModeItem.enableTun) { singboxConfig.route.auto_detect_interface = true; var tunRules = Utils.FromJson>(Utils.GetEmbedText(Global.TunSingboxRulesFileName)); singboxConfig.route.rules.AddRange(tunRules); routingDirectExe(out List lstDnsExe, out List lstDirectExe); singboxConfig.route.rules.Add(new() { port = new() { 53 }, outbound = "dns_out", process_name = lstDnsExe }); singboxConfig.route.rules.Add(new() { outbound = "direct", process_name = lstDirectExe }); } if (_config.routingBasicItem.enableRoutingAdvanced) { var routing = ConfigHandler.GetDefaultRouting(ref _config); if (routing != null) { var rules = Utils.FromJson>(routing.ruleSet); foreach (var item in rules!) { if (item.enabled) { routingUserRule(item, singboxConfig.route.rules); } } } } else { var lockedItem = ConfigHandler.GetLockedRoutingItem(ref _config); if (lockedItem != null) { var rules = Utils.FromJson>(lockedItem.ruleSet); foreach (var item in rules!) { routingUserRule(item, singboxConfig.route.rules); } } } if (_config.tunModeItem.enableTun) { if (_config.tunModeItem.bypassMode) { //direct ips if (_config.tunModeItem.directIP != null && _config.tunModeItem.directIP.Count > 0) { singboxConfig.route.rules.Add(new() { outbound = "direct", ip_cidr = _config.tunModeItem.directIP }); } //direct process if (_config.tunModeItem.directProcess != null && _config.tunModeItem.directProcess.Count > 0) { singboxConfig.route.rules.Add(new() { outbound = "direct", process_name = _config.tunModeItem.directProcess }); } } else { //proxy ips if (_config.tunModeItem.proxyIP != null && _config.tunModeItem.proxyIP.Count > 0) { singboxConfig.route.rules.Add(new() { outbound = "proxy", ip_cidr = _config.tunModeItem.proxyIP }); } //proxy process if (_config.tunModeItem.proxyProcess != null && _config.tunModeItem.proxyProcess.Count > 0) { singboxConfig.route.rules.Add(new() { outbound = "proxy", process_name = _config.tunModeItem.proxyProcess }); } singboxConfig.route.rules.Add(new() { outbound = "direct", inbound = new() { "tun-in" } }); } } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } return 0; } private void routingDirectExe(out List lstDnsExe, out List lstDirectExe) { lstDnsExe = new(); lstDirectExe = new(); var coreInfos = LazyConfig.Instance.GetCoreInfos(); foreach (var it in coreInfos) { if (it.coreType == ECoreType.v2rayN) { continue; } foreach (var it2 in it.coreExes) { if (!lstDnsExe.Contains(it2) && it.coreType != ECoreType.sing_box) { lstDnsExe.Add($"{it2}.exe"); } if (!lstDirectExe.Contains(it2)) { lstDirectExe.Add($"{it2}.exe"); } } } } private int routingUserRule(RulesItem item, List rules) { try { if (item == null) { return 0; } var rule = new Rule4Sbox() { outbound = item.outboundTag, }; if (!Utils.IsNullOrEmpty(item.port)) { if (item.port.Contains("-")) { rule.port_range = new List { item.port.Replace("-", ":") }; } else { rule.port = new List { Utils.ToInt(item.port) }; } } if (item.protocol?.Count > 0) { rule.protocol = item.protocol; } if (item.inboundTag?.Count >= 0) { rule.inbound = item.inboundTag; } var rule2 = Utils.DeepCopy(rule); var hasDomainIp = false; if (item.domain?.Count > 0) { foreach (var it in item.domain) { parseV2Domain(it, rule); } rules.Add(rule); hasDomainIp = true; } if (item.ip?.Count > 0) { foreach (var it in item.ip) { parseV2Address(it, rule2); } rules.Add(rule2); hasDomainIp = true; } if (!hasDomainIp) { rules.Add(rule); } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } return 0; } private void parseV2Domain(string domain, Rule4Sbox rule) { if (domain.StartsWith("ext:") || domain.StartsWith("ext-domain:")) { return; } else if (domain.StartsWith("geosite:")) { if (rule.geosite is null) { rule.geosite = new(); } rule.geosite?.Add(domain.Substring(8)); } else if (domain.StartsWith("regexp:")) { if (rule.domain_regex is null) { rule.domain_regex = new(); } rule.domain_regex?.Add(domain.Replace(Global.RoutingRuleComma, ",").Substring(7)); } else if (domain.StartsWith("domain:")) { if (rule.domain is null) { rule.domain = new(); } if (rule.domain_suffix is null) { rule.domain_suffix = new(); } rule.domain?.Add(domain.Substring(7)); rule.domain_suffix?.Add("." + domain.Substring(7)); } else if (domain.StartsWith("full:")) { if (rule.domain is null) { rule.domain = new(); } rule.domain?.Add(domain.Substring(5)); } else if (domain.StartsWith("keyword:")) { if (rule.domain_keyword is null) { rule.domain_keyword = new(); } rule.domain_keyword?.Add(domain.Substring(8)); } else { if (rule.domain_keyword is null) { rule.domain_keyword = new(); } rule.domain_keyword?.Add(domain); } } private void parseV2Address(string address, Rule4Sbox rule) { if (address.StartsWith("ext:") || address.StartsWith("ext-ip:")) { return; } else if (address.StartsWith("geoip:!")) { return; } else if (address.StartsWith("geoip:")) { if (rule.geoip is null) { rule.geoip = new(); } rule.geoip?.Add(address.Substring(6)); } else { if (rule.ip_cidr is null) { rule.ip_cidr = new(); } rule.ip_cidr?.Add(address); } } #endregion routing rule private #region dns private private int dns(ProfileItem node, SingboxConfig singboxConfig) { try { Dns4Sbox? dns4Sbox; if (_config.tunModeItem.enableTun) { string tunDNS = String.Empty; if (_config.tunModeItem.bypassMode) { tunDNS = _config.tunModeItem.directDNS; } else { tunDNS = _config.tunModeItem.proxyDNS; } if (tunDNS.IsNullOrEmpty() || Utils.FromJson(tunDNS) is null) { tunDNS = Utils.GetEmbedText(Global.TunSingboxDNSFileName); } dns4Sbox = Utils.FromJson(tunDNS); } else { var item = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box); var normalDNS = item?.normalDNS; if (string.IsNullOrWhiteSpace(normalDNS)) { normalDNS = "{\"servers\":[{\"address\":\"tcp://8.8.8.8\"}]}"; } dns4Sbox = Utils.FromJson(normalDNS); } if (dns4Sbox is null) { return 0; } //Add the dns of the remote server domain if (Utils.IsDomain(node.address)) { if (dns4Sbox.rules is null) { dns4Sbox.rules = new(); } dns4Sbox.servers.Add(new() { tag = "local_local", address = "223.5.5.5", detour = "direct" }); dns4Sbox.rules.Add(new() { server = "local_local", domain = new List() { node.address } }); } singboxConfig.dns = dns4Sbox; } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } return 0; } #endregion dns private private int statistic(SingboxConfig singboxConfig) { if (_config.guiItem.enableStatistics) { singboxConfig.experimental = new Experimental4Sbox() { v2ray_api = new V2ray_Api4Sbox() { listen = $"{Global.Loopback}:{Global.statePort}", stats = new Stats4Sbox() { enabled = true, } } }; } return 0; } } } ================================================ FILE: v2rayN/v2rayN/Handler/CoreConfigV2ray.cs ================================================ using System.Net; using System.Net.NetworkInformation; using v2rayN.Base; using v2rayN.Mode; using v2rayN.Resx; namespace v2rayN.Handler { internal class CoreConfigV2ray { private string SampleClient = Global.v2raySampleClient; private Config _config; public CoreConfigV2ray(Config config) { _config = config; } /*Hiddify*/ public int HiddifyGenerateSubConfigContent(ProfileItem node, out V2rayConfig? v2rayConfig, out string msg) { v2rayConfig = null; try { if (node == null) { msg = ResUI.CheckServerSettings; return -1; } msg = ResUI.InitialConfiguration; string result = Utils.GetEmbedText(SampleClient); if (Utils.IsNullOrEmpty(result)) { msg = ResUI.FailedGetDefaultConfiguration; return -1; } v2rayConfig = Utils.FromJson(result); if (v2rayConfig == null) { msg = ResUI.FailedGenDefaultConfiguration; return -1; } log(v2rayConfig); inbound(v2rayConfig); BalancerItem balancer = new BalancerItem(); balancer.tag = "balancer"; balancer.strategy = new BalancerStrategyItem(); if (node.configType == EConfigType.LowestPing || node.configType == EConfigType.LoadBalance) { balancer.strategy.type = "optimal"; var balancerSettings = new OptimalBalancerStrategySetting(); balancerSettings.load_balancing = node.configType == EConfigType.LoadBalance; balancer.strategy.settings = balancerSettings; balancer.selector = LazyConfig.Instance.ProfileItems(node.subid).Where(p => ((int)p.configType) < 100).Select(p => "p" + p.indexId).ToArray(); } routing(v2rayConfig, balancer); foreach (var p in LazyConfig.Instance.ProfileItems(node.subid)) { outbound(p, v2rayConfig, "p" + p.indexId, true); } dns(v2rayConfig); statistic(v2rayConfig); msg = string.Format(ResUI.SuccessfulConfiguration, ""); } catch (Exception ex) { Utils.SaveLog("GenerateClientConfig", ex); msg = ResUI.FailedGenDefaultConfiguration; return -1; } return 0; } public int GenerateClientConfigContent(ProfileItem node, out V2rayConfig? v2rayConfig, out string msg) { v2rayConfig = null; try { if (node == null || node.port <= 0) { msg = ResUI.CheckServerSettings; return -1; } msg = ResUI.InitialConfiguration; string result = Utils.GetEmbedText(SampleClient); if (Utils.IsNullOrEmpty(result)) { msg = ResUI.FailedGetDefaultConfiguration; return -1; } v2rayConfig = Utils.FromJson(result); if (v2rayConfig == null) { msg = ResUI.FailedGenDefaultConfiguration; return -1; } log(v2rayConfig); inbound(v2rayConfig); routing(v2rayConfig); outbound(node, v2rayConfig); dns(v2rayConfig); statistic(v2rayConfig); msg = string.Format(ResUI.SuccessfulConfiguration, ""); } catch (Exception ex) { Utils.SaveLog("GenerateClientConfig4V2ray", ex); msg = ResUI.FailedGenDefaultConfiguration; return -1; } return 0; } private int log(V2rayConfig v2rayConfig) { try { if (_config.coreBasicItem.logEnabled) { var dtNow = DateTime.Now; v2rayConfig.log.loglevel = _config.coreBasicItem.loglevel; v2rayConfig.log.access = Utils.GetLogPath($"Vaccess_{dtNow:yyyy-MM-dd}.txt"); v2rayConfig.log.error = Utils.GetLogPath($"Verror_{dtNow:yyyy-MM-dd}.txt"); } else { v2rayConfig.log.loglevel = _config.coreBasicItem.loglevel; v2rayConfig.log.access = ""; v2rayConfig.log.error = ""; } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } return 0; } private int inbound(V2rayConfig v2rayConfig) { try { v2rayConfig.inbounds = new List(); Inbounds? inbound = GetInbound(_config.inbound[0], Global.InboundSocks, 0, true); v2rayConfig.inbounds.Add(inbound); //http Inbounds? inbound2 = GetInbound(_config.inbound[0], Global.InboundHttp, 1, false); v2rayConfig.inbounds.Add(inbound2); if (_config.inbound[0].allowLANConn) { if (_config.inbound[0].newPort4LAN) { Inbounds inbound3 = GetInbound(_config.inbound[0], Global.InboundSocks2, 2, true); inbound3.listen = "0.0.0.0"; v2rayConfig.inbounds.Add(inbound3); Inbounds inbound4 = GetInbound(_config.inbound[0], Global.InboundHttp2, 3, false); inbound4.listen = "0.0.0.0"; v2rayConfig.inbounds.Add(inbound4); //auth if (!Utils.IsNullOrEmpty(_config.inbound[0].user) && !Utils.IsNullOrEmpty(_config.inbound[0].pass)) { inbound3.settings.auth = "password"; inbound3.settings.accounts = new List { new AccountsItem() { user = _config.inbound[0].user, pass = _config.inbound[0].pass } }; inbound4.settings.auth = "password"; inbound4.settings.accounts = new List { new AccountsItem() { user = _config.inbound[0].user, pass = _config.inbound[0].pass } }; } } else { inbound.listen = "0.0.0.0"; inbound2.listen = "0.0.0.0"; } } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } return 0; } private Inbounds? GetInbound(InItem inItem, string tag, int offset, bool bSocks) { string result = Utils.GetEmbedText(Global.v2raySampleInbound); if (Utils.IsNullOrEmpty(result)) { return null; } var inbound = Utils.FromJson(result); if (inbound == null) { return null; } inbound.tag = tag; inbound.port = inItem.localPort + offset; inbound.protocol = bSocks ? Global.InboundSocks : Global.InboundHttp; inbound.settings.udp = inItem.udpEnabled; inbound.sniffing.enabled = inItem.sniffingEnabled; inbound.sniffing.routeOnly = inItem.routeOnly; return inbound; } private int routing(V2rayConfig v2rayConfig, BalancerItem balancer = null) { try { if (v2rayConfig.routing?.rules != null) { if (balancer != null) { v2rayConfig.routing.balancers = new[] { balancer }.ToList(); } v2rayConfig.routing.domainStrategy = _config.routingBasicItem.domainStrategy; v2rayConfig.routing.domainMatcher = Utils.IsNullOrEmpty(_config.routingBasicItem.domainMatcher) ? null : _config.routingBasicItem.domainMatcher; if (_config.routingBasicItem.enableRoutingAdvanced) { var routing = ConfigHandler.GetDefaultRouting(ref _config); if (routing != null) { if (!Utils.IsNullOrEmpty(routing.domainStrategy)) { v2rayConfig.routing.domainStrategy = routing.domainStrategy; } var rules = Utils.FromJson>(routing.ruleSet); foreach (var item in rules) { if (item.enabled) { routingUserRule(item, v2rayConfig, balancer); } } } } else { var lockedItem = ConfigHandler.GetLockedRoutingItem(ref _config); if (lockedItem != null) { var rules = Utils.FromJson>(lockedItem.ruleSet); foreach (var item in rules) { routingUserRule(item, v2rayConfig); } } } } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } return 0; } private int routingUserRule(RulesItem rules, V2rayConfig v2rayConfig, BalancerItem? balancer = null) { try { if (rules == null) { return 0; } if (Utils.IsNullOrEmpty(rules.port)) { rules.port = null; } if (rules.domain?.Count == 0) { rules.domain = null; } if (rules.ip?.Count == 0) { rules.ip = null; } if (rules.protocol?.Count == 0) { rules.protocol = null; } if (rules.inboundTag?.Count == 0) { rules.inboundTag = null; } var hasDomainIp = false; if (rules.domain?.Count > 0) { var it = Utils.DeepCopy(rules); it.ip = null; it.type = "field"; for (int k = it.domain.Count - 1; k >= 0; k--) { if (it.domain[k].StartsWith("#")) { it.domain.RemoveAt(k); } it.domain[k] = it.domain[k].Replace(Global.RoutingRuleComma, ","); } if (it.outboundTag == "proxy" && balancer != null) { it.outboundTag = null; it.balancerTag = balancer.tag; } v2rayConfig.routing.rules.Add(it); hasDomainIp = true; } if (rules.ip?.Count > 0) { var it = Utils.DeepCopy(rules); it.domain = null; it.type = "field"; if (it.outboundTag == "proxy" && balancer != null) { it.outboundTag = null; it.balancerTag = balancer.tag; } v2rayConfig.routing.rules.Add(it); hasDomainIp = true; } if (!hasDomainIp) { if (!Utils.IsNullOrEmpty(rules.port) || (rules.protocol?.Count > 0) || (rules.inboundTag?.Count > 0) ) { var it = Utils.DeepCopy(rules); it.type = "field"; if (it.outboundTag == "proxy" && balancer != null) { it.outboundTag = null; it.balancerTag = balancer.tag; } v2rayConfig.routing.rules.Add(it); } } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } return 0; } private int outbound(ProfileItem node, V2rayConfig v2rayConfig, String h_tag = "proxy", bool h_add = false) { try { Outbounds outbound = v2rayConfig.outbounds[0]; if (h_add) { outbound = Utils.FromJson(Utils.ToJson(outbound)); v2rayConfig.outbounds.Add(outbound); } outbound.tag = h_tag; if (node.configType == EConfigType.VMess) { VnextItem vnextItem; if (outbound.settings.vnext.Count <= 0) { vnextItem = new VnextItem(); outbound.settings.vnext.Add(vnextItem); } else { vnextItem = outbound.settings.vnext[0]; } vnextItem.address = node.address; vnextItem.port = node.port; UsersItem usersItem; if (vnextItem.users.Count <= 0) { usersItem = new UsersItem(); vnextItem.users.Add(usersItem); } else { usersItem = vnextItem.users[0]; } //远程服务器用户ID usersItem.id = node.id; usersItem.alterId = node.alterId; usersItem.email = Global.userEMail; if (Global.vmessSecuritys.Contains(node.security)) { usersItem.security = node.security; } else { usersItem.security = Global.DefaultSecurity; } //Mux outbound.mux.enabled = _config.coreBasicItem.muxEnabled; outbound.mux.concurrency = _config.coreBasicItem.muxEnabled ? 8 : -1; outbound.protocol = Global.vmessProtocolLite; outbound.settings.servers = null; } else if (node.configType == EConfigType.Shadowsocks) { ServersItem serversItem; if (outbound.settings.servers.Count <= 0) { serversItem = new ServersItem(); outbound.settings.servers.Add(serversItem); } else { serversItem = outbound.settings.servers[0]; } serversItem.address = node.address; serversItem.port = node.port; serversItem.password = node.id; serversItem.method = LazyConfig.Instance.GetShadowsocksSecuritys(node).Contains(node.security) ? node.security : "none"; serversItem.ota = false; serversItem.level = 1; outbound.mux.enabled = false; outbound.mux.concurrency = -1; outbound.protocol = Global.ssProtocolLite; outbound.settings.vnext = null; } else if (node.configType == EConfigType.Socks) { ServersItem serversItem; if (outbound.settings.servers.Count <= 0) { serversItem = new ServersItem(); outbound.settings.servers.Add(serversItem); } else { serversItem = outbound.settings.servers[0]; } serversItem.address = node.address; serversItem.port = node.port; serversItem.method = null; serversItem.password = null; if (!Utils.IsNullOrEmpty(node.security) && !Utils.IsNullOrEmpty(node.id)) { SocksUsersItem socksUsersItem = new() { user = node.security, pass = node.id, level = 1 }; serversItem.users = new List() { socksUsersItem }; } outbound.mux.enabled = false; outbound.mux.concurrency = -1; outbound.protocol = Global.socksProtocolLite; outbound.settings.vnext = null; } else if (node.configType == EConfigType.VLESS) { VnextItem vnextItem; if (outbound.settings.vnext.Count <= 0) { vnextItem = new VnextItem(); outbound.settings.vnext.Add(vnextItem); } else { vnextItem = outbound.settings.vnext[0]; } vnextItem.address = node.address; vnextItem.port = node.port; UsersItem usersItem; if (vnextItem.users.Count <= 0) { usersItem = new UsersItem(); vnextItem.users.Add(usersItem); } else { usersItem = vnextItem.users[0]; } usersItem.id = node.id; usersItem.flow = string.Empty; usersItem.email = Global.userEMail; usersItem.encryption = node.security; //Mux outbound.mux.enabled = _config.coreBasicItem.muxEnabled; outbound.mux.concurrency = _config.coreBasicItem.muxEnabled ? 8 : -1; if (node.streamSecurity == Global.StreamSecurityReality || node.streamSecurity == Global.StreamSecurity) { if (!Utils.IsNullOrEmpty(node.flow)) { usersItem.flow = node.flow; outbound.mux.enabled = false; outbound.mux.concurrency = -1; } } outbound.protocol = Global.vlessProtocolLite; outbound.settings.servers = null; } else if (node.configType == EConfigType.Trojan) { ServersItem serversItem; if (outbound.settings.servers.Count <= 0) { serversItem = new ServersItem(); outbound.settings.servers.Add(serversItem); } else { serversItem = outbound.settings.servers[0]; } serversItem.address = node.address; serversItem.port = node.port; serversItem.password = node.id; serversItem.flow = string.Empty; serversItem.ota = false; serversItem.level = 1; outbound.mux.enabled = false; outbound.mux.concurrency = -1; outbound.protocol = Global.trojanProtocolLite; outbound.settings.vnext = null; } boundStreamSettings(node, outbound.streamSettings); } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } return 0; } private int boundStreamSettings(ProfileItem node, StreamSettings streamSettings) { try { streamSettings.network = node.GetNetwork(); string host = node.requestHost.TrimEx(); string sni = node.sni; string useragent = ""; if (!_config.coreBasicItem.defUserAgent.IsNullOrEmpty()) { try { useragent = Global.userAgentTxt[_config.coreBasicItem.defUserAgent]; } catch (KeyNotFoundException) { useragent = _config.coreBasicItem.defUserAgent; } } //if tls if (node.streamSecurity == Global.StreamSecurity) { streamSettings.security = node.streamSecurity; TlsSettings tlsSettings = new() { allowInsecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? _config.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure), alpn = node.GetAlpn(), fingerprint = node.fingerprint.IsNullOrEmpty() ? _config.coreBasicItem.defFingerprint : node.fingerprint }; if (!string.IsNullOrWhiteSpace(sni)) { tlsSettings.serverName = sni; } else if (!string.IsNullOrWhiteSpace(host)) { tlsSettings.serverName = Utils.String2List(host)[0]; } streamSettings.tlsSettings = tlsSettings; } //if Reality if (node.streamSecurity == Global.StreamSecurityReality) { streamSettings.security = node.streamSecurity; TlsSettings realitySettings = new() { fingerprint = node.fingerprint.IsNullOrEmpty() ? _config.coreBasicItem.defFingerprint : node.fingerprint, serverName = sni, publicKey = node.publicKey, shortId = node.shortId, spiderX = node.spiderX, }; streamSettings.realitySettings = realitySettings; } //streamSettings switch (node.GetNetwork()) { case "kcp": KcpSettings kcpSettings = new() { mtu = _config.kcpItem.mtu, tti = _config.kcpItem.tti }; kcpSettings.uplinkCapacity = _config.kcpItem.uplinkCapacity; kcpSettings.downlinkCapacity = _config.kcpItem.downlinkCapacity; kcpSettings.congestion = _config.kcpItem.congestion; kcpSettings.readBufferSize = _config.kcpItem.readBufferSize; kcpSettings.writeBufferSize = _config.kcpItem.writeBufferSize; kcpSettings.header = new Header { type = node.headerType }; if (!Utils.IsNullOrEmpty(node.path)) { kcpSettings.seed = node.path; } streamSettings.kcpSettings = kcpSettings; break; //ws case "ws": WsSettings wsSettings = new(); wsSettings.headers = new Headers(); string path = node.path; if (!string.IsNullOrWhiteSpace(host)) { wsSettings.headers.Host = host; } if (!string.IsNullOrWhiteSpace(path)) { wsSettings.path = path; } if (!string.IsNullOrWhiteSpace(useragent)) { wsSettings.headers.UserAgent = useragent; } if (!node.fragment.IsNullOrEmpty()) { wsSettings.fragmentation = new FragmentationConfig(); wsSettings.fragmentation.strategy = node.fragment; } streamSettings.wsSettings = wsSettings; break; //h2 case "h2": HttpSettings httpSettings = new(); if (!string.IsNullOrWhiteSpace(host)) { httpSettings.host = Utils.String2List(host); } httpSettings.path = node.path; streamSettings.httpSettings = httpSettings; break; //quic case "quic": QuicSettings quicsettings = new() { security = host, key = node.path, header = new Header { type = node.headerType } }; streamSettings.quicSettings = quicsettings; if (node.streamSecurity == Global.StreamSecurity) { if (!string.IsNullOrWhiteSpace(sni)) { streamSettings.tlsSettings.serverName = sni; } else { streamSettings.tlsSettings.serverName = node.address; } } break; case "grpc": GrpcSettings grpcSettings = new() { serviceName = node.path, multiMode = (node.headerType == Global.GrpcmultiMode), idle_timeout = _config.grpcItem.idle_timeout, health_check_timeout = _config.grpcItem.health_check_timeout, permit_without_stream = _config.grpcItem.permit_without_stream, initial_windows_size = _config.grpcItem.initial_windows_size, }; streamSettings.grpcSettings = grpcSettings; break; default: //tcp if (node.headerType == Global.TcpHeaderHttp) { TcpSettings tcpSettings = new() { header = new Header { type = node.headerType } }; //request Host string request = Utils.GetEmbedText(Global.v2raySampleHttprequestFileName); string[] arrHost = host.Split(','); string host2 = string.Join("\",\"", arrHost); request = request.Replace("$requestHost$", $"\"{host2}\""); //request = request.Replace("$requestHost$", string.Format("\"{0}\"", config.requestHost())); request = request.Replace("$requestUserAgent$", $"\"{useragent}\""); //Path string pathHttp = @"/"; if (!Utils.IsNullOrEmpty(node.path)) { string[] arrPath = node.path.Split(','); pathHttp = string.Join("\",\"", arrPath); } request = request.Replace("$requestPath$", $"\"{pathHttp}\""); tcpSettings.header.request = Utils.FromJson(request); streamSettings.tcpSettings = tcpSettings; } break; } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } return 0; } private int dns(V2rayConfig v2rayConfig) { try { var item = LazyConfig.Instance.GetDNSItem(ECoreType.Xray); var normalDNS = item?.normalDNS; var domainStrategy4Freedom = item?.domainStrategy4Freedom; if (string.IsNullOrWhiteSpace(normalDNS)) { normalDNS = "1.1.1.1,8.8.8.8"; } //Outbound Freedom domainStrategy if (!string.IsNullOrWhiteSpace(domainStrategy4Freedom)) { var outbound = v2rayConfig.outbounds[1]; outbound.settings.domainStrategy = domainStrategy4Freedom; outbound.settings.userLevel = 0; } var obj = Utils.ParseJson(normalDNS); if (obj?.ContainsKey("servers") == true) { v2rayConfig.dns = obj; } else { List servers = new(); string[] arrDNS = normalDNS.Split(','); foreach (string str in arrDNS) { //if (Utils.IsIP(str)) //{ servers.Add(str); //} } //servers.Add("localhost"); v2rayConfig.dns = new Mode.Dns { servers = servers }; } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } return 0; } private int statistic(V2rayConfig v2rayConfig) { if (_config.guiItem.enableStatistics) { string tag = Global.InboundAPITagName; API apiObj = new(); Policy policyObj = new(); SystemPolicy policySystemSetting = new(); string[] services = { "StatsService" }; v2rayConfig.stats = new Stats(); apiObj.tag = tag; apiObj.services = services.ToList(); v2rayConfig.api = apiObj; policySystemSetting.statsOutboundDownlink = true; policySystemSetting.statsOutboundUplink = true; policyObj.system = policySystemSetting; v2rayConfig.policy = policyObj; if (!v2rayConfig.inbounds.Exists(item => item.tag == tag)) { Inbounds apiInbound = new(); Inboundsettings apiInboundSettings = new(); apiInbound.tag = tag; apiInbound.listen = Global.Loopback; apiInbound.port = Global.statePort; apiInbound.protocol = Global.InboundAPIProtocal; apiInboundSettings.address = Global.Loopback; apiInbound.settings = apiInboundSettings; v2rayConfig.inbounds.Add(apiInbound); } if (!v2rayConfig.routing.rules.Exists(item => item.outboundTag == tag)) { RulesItem apiRoutingRule = new() { inboundTag = new List { tag }, outboundTag = tag, type = "field" }; v2rayConfig.routing.rules.Add(apiRoutingRule); } } return 0; } #region Gen speedtest config public string GenerateClientSpeedtestConfigString(List selecteds, out string msg) { try { if (_config == null) { msg = ResUI.CheckServerSettings; return ""; } msg = ResUI.InitialConfiguration; Config configCopy = Utils.DeepCopy(_config); string result = Utils.GetEmbedText(SampleClient); if (Utils.IsNullOrEmpty(result)) { msg = ResUI.FailedGetDefaultConfiguration; return ""; } V2rayConfig? v2rayConfig = Utils.FromJson(result); if (v2rayConfig == null) { msg = ResUI.FailedGenDefaultConfiguration; return ""; } List lstIpEndPoints = new(); List lstTcpConns = new(); try { lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners()); lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners()); lstTcpConns.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections()); } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } log(v2rayConfig); v2rayConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts. int httpPort = LazyConfig.Instance.GetLocalPort("speedtest"); foreach (var it in selecteds) { if (it.configType == EConfigType.Custom) { continue; } if (it.port <= 0 && (int)it.configType < 100) { continue; } if (it.configType is EConfigType.VMess or EConfigType.VLESS) { var item2 = LazyConfig.Instance.GetProfileItem(it.indexId); if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id)) { continue; } } //find unuse port var port = httpPort; for (int k = httpPort; k < Global.MaxPort; k++) { if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0) { continue; } if (lstTcpConns?.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0) { continue; } //found port = k; httpPort = port + 1; break; } //Port In Used if (lstIpEndPoints?.FindIndex(_it => _it.Port == port) >= 0) { continue; } it.port = port; it.allowTest = true; //inbound Inbounds inbound = new() { listen = Global.Loopback, port = port, protocol = Global.InboundHttp }; inbound.tag = Global.InboundHttp + inbound.port.ToString(); v2rayConfig.inbounds.Add(inbound); //outbound V2rayConfig? v2rayConfigCopy = Utils.FromJson(result); var item = LazyConfig.Instance.GetProfileItem(it.indexId); if (item is null) { continue; } if (item.configType == EConfigType.Shadowsocks && !Global.ssSecuritysInXray.Contains(item.security)) { continue; } if (item.configType == EConfigType.VLESS && !Global.flows.Contains(item.flow)) { continue; } if (item.configType == EConfigType.LowestPing || item.configType == EConfigType.LoadBalance) { var balancer = new BalancerItem(); balancer.tag = "balancer" + inbound.port.ToString(); balancer.strategy = new BalancerStrategyItem(); if (item.configType == EConfigType.LowestPing || item.configType == EConfigType.LoadBalance) { balancer.strategy.type = "optimal"; var balancerSettings = new OptimalBalancerStrategySetting(); balancerSettings.load_balancing = item.configType == EConfigType.LoadBalance; balancer.strategy.settings = balancerSettings; balancer.selector = LazyConfig.Instance.ProfileItems(item.subid).Where(p => ((int)p.configType) < 100).Select(p => "p" + p.indexId).ToArray(); } v2rayConfig.routing.balancers.Add(balancer); if (v2rayConfig.routing.balancers.Count == 1) { foreach (var p in LazyConfig.Instance.ProfileItems(item.subid)) { outbound(p, v2rayConfig, "p" + p.indexId, true); } } //rule RulesItem rule = new() { inboundTag = new List { inbound.tag }, balancerTag = balancer.tag, type = "field" }; v2rayConfig.routing.rules.Add(rule); } else { outbound(item, v2rayConfigCopy); v2rayConfigCopy.outbounds[0].tag = Global.agentTag + inbound.port.ToString(); v2rayConfig.outbounds.Add(v2rayConfigCopy.outbounds[0]); //rule RulesItem rule = new() { inboundTag = new List { inbound.tag }, outboundTag = v2rayConfigCopy.outbounds[0].tag, type = "field" }; v2rayConfig.routing.rules.Add(rule); } } //msg = string.Format(ResUI.SuccessfulConfiguration"), node.getSummary()); return Utils.ToJson(v2rayConfig); } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); msg = ResUI.FailedGenDefaultConfiguration; return ""; } } #endregion Gen speedtest config } } ================================================ FILE: v2rayN/v2rayN/Handler/CoreHandler.cs ================================================ using System.Diagnostics; using System.IO; using System.Text; using v2rayN.Mode; using v2rayN.Resx; namespace v2rayN.Handler { /// /// Core process processing class /// internal class CoreHandler { private Config _config; private CoreInfo? _coreInfo; private Process? _process; private Process? _processPre; private Action _updateFunc; public CoreHandler(Config config, Action update) { _config = config; _updateFunc = update; Environment.SetEnvironmentVariable("v2ray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable("xray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process); } public void LoadCore() { var node = ConfigHandler.GetDefaultServer(ref _config); if (node == null) { ShowMsg(false, ResUI.CheckServerSettings); return; } if (SetCore(node) != 0) { ShowMsg(false, ResUI.CheckServerSettings); return; } string fileName = Utils.GetConfigPath(Global.coreConfigFileName); if (CoreConfigHandler.GenerateClientConfig(node, fileName, out string msg, out string content) != 0) { ShowMsg(false, msg); } else { ShowMsg(false, msg); ShowMsg(true, $"{node.GetSummary()}"); CoreStop(); CoreStart(node); } } public int LoadCoreConfigString(List _selecteds) { int pid = -1; string configStr = CoreConfigHandler.GenerateClientSpeedtestConfigString(_config, _selecteds, out string msg); if (configStr == "") { ShowMsg(false, msg); } else { ShowMsg(false, msg); pid = CoreStartViaString(configStr); } return pid; } public void CoreStop() { try { if (_process != null) { KillProcess(_process); _process.Dispose(); _process = null; } else { if (_coreInfo == null || _coreInfo.coreExes == null) { return; } foreach (string vName in _coreInfo.coreExes) { Process[] existing = Process.GetProcessesByName(vName); foreach (Process p in existing) { string? path = p.MainModule?.FileName; if (path == $"{Utils.GetBinPath(vName, _coreInfo.coreType)}.exe") { KillProcess(p); } } } } if (_processPre != null) { KillProcess(_processPre); _processPre.Dispose(); _processPre = null; } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } } public void CoreStopPid(int pid) { try { Process _p = Process.GetProcessById(pid); KillProcess(_p); } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } } private string CoreFindexe(CoreInfo coreInfo) { string fileName = string.Empty; foreach (string name in coreInfo.coreExes) { string vName = $"{name}.exe"; vName = Utils.GetBinPath(vName, coreInfo.coreType); if (File.Exists(vName)) { fileName = vName; break; } } if (Utils.IsNullOrEmpty(fileName)) { string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.coreType), string.Join(", ", coreInfo.coreExes.ToArray()), coreInfo.coreUrl); Utils.SaveLog(msg); ShowMsg(false, msg); } return fileName; } private void CoreStart(ProfileItem node) { ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString())); var proc = RunProcess(node, _coreInfo, "", ShowMsg); if (proc is null) { return; } _process = proc; //start a socks service if (_process != null && !_process.HasExited) { if ((node.configType == EConfigType.Custom && node.preSocksPort > 0) || (node.configType != EConfigType.Custom && _coreInfo.coreType != ECoreType.sing_box && _config.tunModeItem.enableTun)) { var itemSocks = new ProfileItem() { coreType = ECoreType.sing_box, configType = EConfigType.Socks, address = Global.Loopback, port = node.preSocksPort > 0 ? node.preSocksPort : LazyConfig.Instance.GetLocalPort(Global.InboundSocks) }; string fileName2 = Utils.GetConfigPath(Global.corePreConfigFileName); if (CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2, out string msg2, out string configStr) == 0) { var coreInfo = LazyConfig.Instance.GetCoreInfo(ECoreType.sing_box); var proc2 = RunProcess(node, coreInfo, $" -c {Global.corePreConfigFileName}", ShowMsg); if (proc2 is not null) { _processPre = proc2; } } } } } private int CoreStartViaString(string configStr) { ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString())); try { var coreInfo = LazyConfig.Instance.GetCoreInfo(ECoreType.Xray); string fileName = CoreFindexe(coreInfo); if (fileName == "") return -1; Process p = new() { StartInfo = new ProcessStartInfo { FileName = fileName, Arguments = "-config stdin:", WorkingDirectory = Utils.GetConfigPath(), UseShellExecute = false, RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true, StandardOutputEncoding = Encoding.UTF8, StandardErrorEncoding = Encoding.UTF8 } }; p.OutputDataReceived += (sender, e) => { if (!String.IsNullOrEmpty(e.Data)) { string msg = e.Data + Environment.NewLine; ShowMsg(false, msg); } }; p.ErrorDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) { string msg = e.Data + Environment.NewLine; ShowMsg(false, msg); } }; p.Start(); p.BeginOutputReadLine(); p.BeginErrorReadLine(); p.StandardInput.Write(configStr); p.StandardInput.Close(); if (p.WaitForExit(1000)) { throw new Exception(p.StandardError.ReadToEnd()); } Global.processJob.AddProcess(p.Handle); return p.Id; } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); string msg = ex.Message; ShowMsg(false, msg); return -1; } } private void ShowMsg(bool updateToTrayTooltip, string msg) { _updateFunc(updateToTrayTooltip, msg); } private int SetCore(ProfileItem node) { if (node == null) { return -1; } var coreType = LazyConfig.Instance.GetCoreType(node, node.configType); _coreInfo = LazyConfig.Instance.GetCoreInfo(coreType); if (_coreInfo == null) { return -1; } return 0; } #region Process private Process? RunProcess(ProfileItem node, CoreInfo coreInfo, string configPath, Action update) { try { string fileName = CoreFindexe(coreInfo); if (Utils.IsNullOrEmpty(fileName)) { return null; } var displayLog = node.configType != EConfigType.Custom || node.displayLog; Process proc = new() { StartInfo = new ProcessStartInfo { FileName = fileName, Arguments = string.Format(coreInfo.arguments, configPath), WorkingDirectory = Utils.GetConfigPath(), UseShellExecute = false, RedirectStandardOutput = displayLog, RedirectStandardError = displayLog, CreateNoWindow = true, StandardOutputEncoding = displayLog ? Encoding.UTF8 : null, StandardErrorEncoding = displayLog ? Encoding.UTF8 : null, } }; if (displayLog) { proc.OutputDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) { string msg = e.Data + Environment.NewLine; update(false, msg); } }; proc.ErrorDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) { string msg = e.Data + Environment.NewLine; update(false, msg); } }; } proc.Start(); if (displayLog) { proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); } if (proc.WaitForExit(1000)) { throw new Exception(displayLog ? proc.StandardError.ReadToEnd() : "启动进程失败并退出 (Failed to start the process and exited)"); } Global.processJob.AddProcess(proc.Handle); return proc; } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); string msg = ex.Message; update(true, msg); return null; } } private void KillProcess(Process p) { try { p.CloseMainWindow(); p.WaitForExit(100); if (!p.HasExited) { p.Kill(); p.WaitForExit(100); } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } } #endregion Process } } ================================================ FILE: v2rayN/v2rayN/Handler/DownloadHandle.cs ================================================ using System.Diagnostics; using System.IO; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Net.Sockets; using v2rayN.Base; using v2rayN.Resx; namespace v2rayN.Handler { /// ///Download /// internal class DownloadHandle { public event EventHandler? UpdateCompleted; public event ErrorEventHandler? Error; public class ResultEventArgs : EventArgs { public bool Success; public string Msg; public ResultEventArgs(bool success, string msg) { Success = success; Msg = msg; } } public async Task DownloadDataAsync(string url, WebProxy webProxy, int downloadTimeout, Action update) { try { Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13); var progress = new Progress(); progress.ProgressChanged += (sender, value) => { if (update != null) { string msg = $"{value}"; update(false, msg); } }; await DownloaderHelper.Instance.DownloadDataAsync4Speed(webProxy, url, progress, downloadTimeout); } catch (Exception ex) { update(false, ex.Message); if (ex.InnerException != null) { update(false, ex.InnerException.Message); } } return 0; } public async Task DownloadFileAsync(string url, bool blProxy, int downloadTimeout) { try { Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13); UpdateCompleted?.Invoke(this, new ResultEventArgs(false, $"{ResUI.Downloading} {url}")); var progress = new Progress(); progress.ProgressChanged += (sender, value) => { UpdateCompleted?.Invoke(this, new ResultEventArgs(value > 100, $"...{value}%")); }; var webProxy = GetWebProxy(blProxy); await DownloaderHelper.Instance.DownloadFileAsync(webProxy, url, Utils.GetTempPath(Utils.GetDownloadFileName(url)), progress, downloadTimeout); } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); Error?.Invoke(this, new ErrorEventArgs(ex)); if (ex.InnerException != null) { Error?.Invoke(this, new ErrorEventArgs(ex.InnerException)); } } } public async Task UrlRedirectAsync(string url, bool blProxy) { Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13); var webRequestHandler = new SocketsHttpHandler { AllowAutoRedirect = false, Proxy = GetWebProxy(blProxy) }; HttpClient client = new(webRequestHandler); HttpResponseMessage response = await client.GetAsync(url); if (response.StatusCode == HttpStatusCode.Redirect && response.Headers.Location is not null) { return response.Headers.Location.ToString(); } else { Utils.SaveLog("StatusCode error: " + url); return null; } } public async Task TryDownloadString(string url, bool blProxy, string userAgent) { try { var result1 = await DownloadStringAsync(url, blProxy, userAgent); if (!Utils.IsNullOrEmpty(result1)) { return result1; } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); Error?.Invoke(this, new ErrorEventArgs(ex)); if (ex.InnerException != null) { Error?.Invoke(this, new ErrorEventArgs(ex.InnerException)); } } try { var result2 = await DownloadStringViaDownloader(url, blProxy, userAgent); if (!Utils.IsNullOrEmpty(result2)) { return result2; } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); Error?.Invoke(this, new ErrorEventArgs(ex)); if (ex.InnerException != null) { Error?.Invoke(this, new ErrorEventArgs(ex.InnerException)); } } try { using var wc = new WebClient(); wc.Proxy = GetWebProxy(blProxy); var result3 = await wc.DownloadStringTaskAsync(url); if (!Utils.IsNullOrEmpty(result3)) { return result3; } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); Error?.Invoke(this, new ErrorEventArgs(ex)); if (ex.InnerException != null) { Error?.Invoke(this, new ErrorEventArgs(ex.InnerException)); } } return null; } /// /// DownloadString /// /// public async Task DownloadStringAsync(string url, bool blProxy, string userAgent) { try { Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13); var webProxy = GetWebProxy(blProxy); var client = new HttpClient(new SocketsHttpHandler() { Proxy = webProxy, UseProxy = webProxy != null }); if (Utils.IsNullOrEmpty(userAgent)) { userAgent = Utils.GetVersion(false); } client.DefaultRequestHeaders.UserAgent.TryParseAdd(userAgent); Uri uri = new(url); //Authorization Header if (!Utils.IsNullOrEmpty(uri.UserInfo)) { client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Utils.Base64Encode(uri.UserInfo)); } using var cts = new CancellationTokenSource(); var result = await HttpClientHelper.Instance.GetAsync(client, url, cts.Token).WaitAsync(TimeSpan.FromSeconds(30), cts.Token); return result; } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); Error?.Invoke(this, new ErrorEventArgs(ex)); if (ex.InnerException != null) { Error?.Invoke(this, new ErrorEventArgs(ex.InnerException)); } } return null; } /// /// DownloadString /// /// public async Task DownloadStringViaDownloader(string url, bool blProxy, string userAgent) { try { Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13); var webProxy = GetWebProxy(blProxy); if (Utils.IsNullOrEmpty(userAgent)) { userAgent = Utils.GetVersion(false); } var result = await DownloaderHelper.Instance.DownloadStringAsync(webProxy, url, userAgent, 30); return result; } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); Error?.Invoke(this, new ErrorEventArgs(ex)); if (ex.InnerException != null) { Error?.Invoke(this, new ErrorEventArgs(ex.InnerException)); } } return null; } public async Task RunAvailabilityCheck(IWebProxy? webProxy,int count=3) { int responseTime = -1; try { if (webProxy == null) { webProxy = GetWebProxy(true); } var config = LazyConfig.Instance.GetConfig(); responseTime = await GetRealPingTime(config.speedTestItem.speedPingTestUrl, webProxy, 10); if (count == 3) responseTime = -1; } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); responseTime = -1; } if (responseTime < 0 && count > 0) { await Task.Delay(500); await RunAvailabilityCheck(webProxy, count - 1); } return responseTime; } public async Task GetRealPingTime(string url, IWebProxy? webProxy, int downloadTimeout) { int responseTime = -1; try { Stopwatch timer = Stopwatch.StartNew(); using var cts = new CancellationTokenSource(); cts.CancelAfter(TimeSpan.FromSeconds(downloadTimeout)); using var client = new HttpClient(new SocketsHttpHandler() { Proxy = webProxy, UseProxy = webProxy != null }); await client.GetAsync(url, cts.Token); responseTime = timer.Elapsed.Milliseconds; } catch (Exception ex) { //Utils.SaveLog(ex.Message, ex); } return responseTime; } private WebProxy? GetWebProxy(bool blProxy) { if (!blProxy) { return null; } var httpPort = LazyConfig.Instance.GetLocalPort(Global.InboundHttp); if (!SocketCheck(Global.Loopback, httpPort)) { return null; } return new WebProxy(Global.Loopback, httpPort); } private bool SocketCheck(string ip, int port) { try { IPEndPoint point = new(IPAddress.Parse(ip), port); using Socket? sock = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); sock.Connect(point); return true; } catch (Exception) { return false; } } } } ================================================ FILE: v2rayN/v2rayN/Handler/HotkeyHandler.cs ================================================ using System.ComponentModel; using System.Runtime.InteropServices; using System.Text; using System.Windows; using System.Windows.Input; using System.Windows.Interop; using v2rayN.Mode; using v2rayN.Resx; namespace v2rayN.Handler { public sealed class HotkeyHandler { private static readonly Lazy _instance = new(() => new()); public static HotkeyHandler Instance = _instance.Value; private const int WmHotkey = 0x0312; private Config _config { get => LazyConfig.Instance.GetConfig(); } private Dictionary> _hotkeyTriggerDic; public bool IsPause { get; set; } = false; public event Action? UpdateViewEvent; public event Action? HotkeyTriggerEvent; public HotkeyHandler() { _hotkeyTriggerDic = new(); ComponentDispatcher.ThreadPreprocessMessage += OnThreadPreProcessMessage; Init(); } private void Init() { _hotkeyTriggerDic.Clear(); if (_config.globalHotkeys == null) return; foreach (var item in _config.globalHotkeys) { if (item.KeyCode != null && item.KeyCode != Key.None) { int key = KeyInterop.VirtualKeyFromKey((Key)item.KeyCode); KeyModifiers modifiers = KeyModifiers.None; if (item.Control) modifiers |= KeyModifiers.Ctrl; if (item.Shift) modifiers |= KeyModifiers.Shift; if (item.Alt) modifiers |= KeyModifiers.Alt; key = (key << 16) | (int)modifiers; if (!_hotkeyTriggerDic.ContainsKey(key)) { _hotkeyTriggerDic.Add(key, new() { item.eGlobalHotkey }); } else { if (!_hotkeyTriggerDic[key].Contains(item.eGlobalHotkey)) _hotkeyTriggerDic[key].Add(item.eGlobalHotkey); } } } } public void Load() { foreach (var _hotkeyCode in _hotkeyTriggerDic.Keys) { var hotkeyInfo = GetHotkeyInfo(_hotkeyCode); bool isSuccess = false; string msg; Application.Current.Dispatcher.Invoke(() => { isSuccess = RegisterHotKey(IntPtr.Zero, _hotkeyCode, hotkeyInfo.fsModifiers, hotkeyInfo.vKey); }); foreach (var name in hotkeyInfo.Names) { if (isSuccess) { msg = string.Format(ResUI.RegisterGlobalHotkeySuccessfully, $"{name}({hotkeyInfo.hotkeyStr})"); } else { var errInfo = new Win32Exception(Marshal.GetLastWin32Error()).Message; msg = string.Format(ResUI.RegisterGlobalHotkeyFailed, $"{name}({hotkeyInfo.hotkeyStr})", errInfo); } UpdateViewEvent?.Invoke(false, msg); } } } public void ReLoad() { foreach (var hotkey in _hotkeyTriggerDic.Keys) { Application.Current.Dispatcher.Invoke(() => { UnregisterHotKey(IntPtr.Zero, hotkey); }); } Init(); Load(); } private (int fsModifiers, int vKey, string hotkeyStr, List Names) GetHotkeyInfo(int hotkeycode) { var _fsModifiers = hotkeycode & 0xffff; var _vkey = (hotkeycode >> 16) & 0xffff; var _hotkeyStr = new StringBuilder(); var _names = new List(); var mdif = (KeyModifiers)_fsModifiers; var key = KeyInterop.KeyFromVirtualKey(_vkey); if ((mdif | KeyModifiers.Ctrl) == KeyModifiers.Ctrl) _hotkeyStr.Append($"{KeyModifiers.Ctrl}+"); if ((mdif | KeyModifiers.Alt) == KeyModifiers.Alt) _hotkeyStr.Append($"{KeyModifiers.Alt}+"); if ((mdif | KeyModifiers.Shift) == KeyModifiers.Shift) _hotkeyStr.Append($"{KeyModifiers.Shift}+"); _hotkeyStr.Append(key.ToString()); foreach (var name in _hotkeyTriggerDic[hotkeycode]) { _names.Add(name.ToString()); } return (_fsModifiers, _vkey, _hotkeyStr.ToString(), _names); } private void OnThreadPreProcessMessage(ref MSG msg, ref bool handled) { if (msg.message != WmHotkey || !_hotkeyTriggerDic.ContainsKey((int)msg.lParam)) { return; } handled = true; var _hotKeyCode = (int)msg.lParam; if (IsPause) { Application.Current.Dispatcher.Invoke(() => { UIElement? element = Keyboard.FocusedElement as UIElement; if (element != null) { var _keyEventArgs = new KeyEventArgs(Keyboard.PrimaryDevice, PresentationSource.FromVisual(element), 0, KeyInterop.KeyFromVirtualKey(GetHotkeyInfo(_hotKeyCode).vKey)) { RoutedEvent = UIElement.KeyDownEvent }; element.RaiseEvent(_keyEventArgs); } }); } else { foreach (var keyEvent in _hotkeyTriggerDic[(int)msg.lParam]) { HotkeyTriggerEvent?.Invoke(keyEvent); } } } [DllImport("user32.dll", SetLastError = true)] private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc); [DllImport("user32.dll", SetLastError = true)] private static extern bool UnregisterHotKey(IntPtr hWnd, int id); [Flags] private enum KeyModifiers { None = 0x0000, Alt = 0x0001, Ctrl = 0x0002, Shift = 0x0004, Win = 0x0008, NoRepeat = 0x4000 } } } ================================================ FILE: v2rayN/v2rayN/Handler/LazyConfig.cs ================================================ using v2rayN.Base; using v2rayN.Mode; namespace v2rayN.Handler { public sealed class LazyConfig { private static readonly Lazy _instance = new(() => new()); private Config _config; private List coreInfos; public static LazyConfig Instance => _instance.Value; public LazyConfig() { SqliteHelper.Instance.CreateTable(); SqliteHelper.Instance.CreateTable(); SqliteHelper.Instance.CreateTable(); SqliteHelper.Instance.CreateTable(); SqliteHelper.Instance.CreateTable(); SqliteHelper.Instance.CreateTable(); } #region Config public void SetConfig(Config config) { _config = config; } public Config GetConfig() { return _config; } public int GetLocalPort(string protocol) { int localPort = _config.inbound.FirstOrDefault(t => t.protocol == Global.InboundSocks).localPort; if (protocol == Global.InboundSocks) { return localPort; } else if (protocol == Global.InboundHttp) { return localPort + 1; } else if (protocol == Global.InboundSocks2) { return localPort + 2; } else if (protocol == Global.InboundHttp2) { return localPort + 3; } else if (protocol == ESysProxyType.Pac.ToString()) { return localPort + 4; } else if (protocol == "speedtest") { return localPort + 103; } return localPort; } public List SubItems() { return SqliteHelper.Instance.Table().ToList(); } public SubItem? GetLastSubItem() { IList subItems = SubItems(); if (subItems.Count > 0) { int latestSortNumber = subItems.Max(t => t == null ? 0 : t.sort); SubItem latestAddedSubItem = subItems.First(item => item.sort == latestSortNumber); return latestAddedSubItem; } return null; } public int GetLastSubItemSortNumber() { var lastSortNumber = 0; if (SqliteHelper.Instance.Table().Count() > 0) { lastSortNumber = SqliteHelper.Instance.Table().Max(t => t == null ? 0 : t.sort); } return lastSortNumber; } public SubItem GetSubItem(string subid) { return SqliteHelper.Instance.Table().FirstOrDefault(t => t.id == subid); } public List ProfileItems(string subid) { if (Utils.IsNullOrEmpty(subid)) { return SqliteHelper.Instance.Table().ToList(); } else { return SqliteHelper.Instance.Table().Where(t => t.subid == subid).ToList(); } } public List ProfileItemIndexs(string subid) { if (Utils.IsNullOrEmpty(subid)) { return SqliteHelper.Instance.Table().Select(t => t.indexId).ToList(); } else { return SqliteHelper.Instance.Table().Where(t => t.subid == subid).Select(t => t.indexId).ToList(); } } public List ProfileItems(string subid, string filter) { var sql = @$"select a.* ,b.remarks subRemarks from ProfileItem a left join SubItem b on a.subid = b.id where 1=1 "; if (!Utils.IsNullOrEmpty(subid)) { sql += $" and a.subid = '{subid}'"; } if (!Utils.IsNullOrEmpty(filter)) { if (filter.Contains('\'')) { filter = filter.Replace("'", ""); } sql += String.Format(" and (a.remarks like '%{0}%' or a.address like '%{0}%') ", filter); } return SqliteHelper.Instance.Query(sql).ToList(); } public ProfileItem? GetProfileItem(string indexId) { if (Utils.IsNullOrEmpty(indexId)) { return null; } return SqliteHelper.Instance.Table().FirstOrDefault(it => it.indexId == indexId); } public List RoutingItems() { return SqliteHelper.Instance.Table().Where(it => it.locked == false).OrderBy(t => t.sort).ToList(); } public RoutingItem GetRoutingItem(string id) { return SqliteHelper.Instance.Table().FirstOrDefault(it => it.locked == false && it.id == id); } public List DNSItems() { return SqliteHelper.Instance.Table().ToList(); } public DNSItem GetDNSItem(ECoreType eCoreType) { return SqliteHelper.Instance.Table().FirstOrDefault(it => it.coreType == eCoreType); } #endregion Config #region Core Type public List GetShadowsocksSecuritys(ProfileItem profileItem) { if (GetCoreType(profileItem, EConfigType.Shadowsocks) == ECoreType.v2fly) { return Global.ssSecuritys; } if (GetCoreType(profileItem, EConfigType.Shadowsocks) == ECoreType.Xray) { return Global.ssSecuritysInXray; } return Global.ssSecuritysInSagerNet; } public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType) { if (profileItem?.coreType != null) { return (ECoreType)profileItem.coreType; } if (_config.coreTypeItem == null) { return ECoreType.Xray; } var item = _config.coreTypeItem.FirstOrDefault(it => it.configType == eConfigType); if (item == null) { return ECoreType.Xray; } return item.coreType; } public CoreInfo? GetCoreInfo(ECoreType coreType) { if (coreInfos == null) { InitCoreInfo(); } return coreInfos!.FirstOrDefault(t => t.coreType == coreType); } public List? GetCoreInfos() { if (coreInfos == null) { InitCoreInfo(); } return coreInfos; } private void InitCoreInfo() { coreInfos = new(16); coreInfos.Add(new CoreInfo { coreType = ECoreType.v2rayN, coreUrl = Global.NUrl, coreReleaseApiUrl = Global.NUrl.Replace(Global.githubUrl, Global.githubApiUrl), coreDownloadUrl32 = Global.NUrl + "/download/{0}/v2rayN-32.zip", coreDownloadUrl64 = Global.NUrl + "/download/{0}/v2rayN.zip", coreDownloadUrlArm64 = Global.NUrl + "/download/{0}/v2rayN-arm64.zip" }); coreInfos.Add(new CoreInfo { coreType = ECoreType.v2fly, coreExes = new List { "wv2ray", "v2ray" }, arguments = "", coreUrl = Global.v2flyCoreUrl, coreReleaseApiUrl = Global.v2flyCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl), coreDownloadUrl32 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrlArm64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", match = "V2Ray", versionArg = "-version", redirectInfo = true, }); coreInfos.Add(new CoreInfo { coreType = ECoreType.SagerNet, coreExes = new List { "SagerNet", "v2ray" }, arguments = "run", coreUrl = Global.SagerNetCoreUrl, coreReleaseApiUrl = Global.SagerNetCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl), coreDownloadUrl32 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrl64 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrlArm64 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", match = "V2Ray", versionArg = "version", redirectInfo = true, }); coreInfos.Add(new CoreInfo { coreType = ECoreType.v2fly_v5, coreExes = new List { "v2ray" }, arguments = "run", coreUrl = Global.v2flyCoreUrl, coreReleaseApiUrl = Global.v2flyCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl), coreDownloadUrl32 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrlArm64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", match = "V2Ray", versionArg = "version", redirectInfo = true, }); coreInfos.Add(new CoreInfo { coreType = ECoreType.Xray, coreExes = new List { "xray", "wxray" }, arguments = "", coreUrl = Global.xrayCoreUrl, coreReleaseApiUrl = Global.xrayCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl), coreDownloadUrl32 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip", coreDownloadUrl64 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip", coreDownloadUrlArm64 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip", match = "Xray", versionArg = "-version", redirectInfo = true, }); coreInfos.Add(new CoreInfo { coreType = ECoreType.clash, coreExes = new List { "clash-windows-amd64-v3", "clash-windows-amd64", "clash-windows-386", "clash" }, arguments = "-f config.json", coreUrl = Global.clashCoreUrl, coreReleaseApiUrl = Global.clashCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl), coreDownloadUrl32 = Global.clashCoreUrl + "/download/{0}/clash-windows-386-{0}.zip", coreDownloadUrl64 = Global.clashCoreUrl + "/download/{0}/clash-windows-amd64-{0}.zip", coreDownloadUrlArm64 = Global.clashCoreUrl + "/download/{0}/clash-windows-arm64-{0}.zip", match = "v", versionArg = "-v", redirectInfo = true, }); coreInfos.Add(new CoreInfo { coreType = ECoreType.clash_meta, coreExes = new List { "Clash.Meta-windows-amd64-compatible", "Clash.Meta-windows-amd64", "Clash.Meta-windows-386", "Clash.Meta", "clash" }, arguments = "-f config.json", coreUrl = Global.clashMetaCoreUrl, coreReleaseApiUrl = Global.clashMetaCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl), coreDownloadUrl32 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-386-{0}.zip", coreDownloadUrl64 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-amd64-compatible-{0}.zip", coreDownloadUrlArm64 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-arm64-{0}.zip", match = "v", versionArg = "-v", redirectInfo = true, }); coreInfos.Add(new CoreInfo { coreType = ECoreType.hysteria, coreExes = new List { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" }, arguments = "", coreUrl = Global.hysteriaCoreUrl, coreReleaseApiUrl = Global.hysteriaCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl), coreDownloadUrl32 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-386.exe", coreDownloadUrl64 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-amd64.exe", coreDownloadUrlArm64 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-arm64.exe", redirectInfo = true, }); coreInfos.Add(new CoreInfo { coreType = ECoreType.naiveproxy, coreExes = new List { "naiveproxy", "naive" }, arguments = "config.json", coreUrl = Global.naiveproxyCoreUrl, redirectInfo = false, }); coreInfos.Add(new CoreInfo { coreType = ECoreType.tuic, coreExes = new List { "tuic-client", "tuic" }, arguments = "-c config.json", coreUrl = Global.tuicCoreUrl, redirectInfo = true, }); coreInfos.Add(new CoreInfo { coreType = ECoreType.sing_box, coreExes = new List { "sing-box-client", "sing-box" }, arguments = "run{0}", coreUrl = Global.singboxCoreUrl, redirectInfo = true, coreReleaseApiUrl = Global.singboxCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl), coreDownloadUrl32 = Global.singboxCoreUrl + "/download/{0}/sing-box-{1}-windows-386.zip", coreDownloadUrl64 = Global.singboxCoreUrl + "/download/{0}/sing-box-{1}-windows-amd64.zip", coreDownloadUrlArm64 = Global.singboxCoreUrl + "/download/{0}/sing-box-{1}-windows-arm64.zip", match = "sing-box", versionArg = "version", }); } #endregion Core Type } } ================================================ FILE: v2rayN/v2rayN/Handler/MainFormHandler.cs ================================================ using Microsoft.Win32; using System.Drawing; using System.IO; using System.Windows.Media.Imaging; using v2rayN.Mode; using v2rayN.Resx; namespace v2rayN.Handler { public sealed class MainFormHandler { private static readonly Lazy instance = new(() => new()); public static MainFormHandler Instance => instance.Value; public Icon GetNotifyIcon(Config config) { try { int index = (int)config.sysProxyType; //Load from routing setting var createdIcon = GetNotifyIcon4Routing(config); if (createdIcon != null) { return createdIcon; } //Load from local file var fileName = Utils.GetPath($"NotifyIcon{index + 1}.ico"); if (File.Exists(fileName)) { return new Icon(fileName); } return index switch { 0 => Properties.Resources.NotifyIcon1, 1 => Properties.Resources.NotifyIcon2, 2 => Properties.Resources.NotifyIcon3, 3 => Properties.Resources.NotifyIcon2, _ => Properties.Resources.NotifyIcon1, // default }; } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); return Properties.Resources.NotifyIcon1; } } public System.Windows.Media.ImageSource GetAppIcon(Config config) { int index = 1; switch ((int)config.sysProxyType) { case 0: index = 1; break; case 1: case 3: index = 2; break; case 2: index = 3; break; } return BitmapFrame.Create(new Uri($"pack://application:,,,/Resources/NotifyIcon{index}.ico", UriKind.RelativeOrAbsolute)); } private Icon? GetNotifyIcon4Routing(Config config) { try { if (!config.routingBasicItem.enableRoutingAdvanced) { return null; } var item = ConfigHandler.GetDefaultRouting(ref config); if (item == null || Utils.IsNullOrEmpty(item.customIcon) || !File.Exists(item.customIcon)) { return null; } Color color = ColorTranslator.FromHtml("#3399CC"); int index = (int)config.sysProxyType; if (index > 0) { color = (new[] { Color.Red, Color.Purple, Color.DarkGreen, Color.Orange, Color.DarkSlateBlue, Color.RoyalBlue })[index - 1]; } int width = 128; int height = 128; Bitmap bitmap = new(width, height); Graphics graphics = Graphics.FromImage(bitmap); SolidBrush drawBrush = new(color); graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; //graphics.FillRectangle(drawBrush, new Rectangle(0, 0, width, height)); graphics.DrawImage(new Bitmap(item.customIcon), 0, 0, width, height); graphics.FillEllipse(drawBrush, width / 2, width / 2, width / 2, width / 2); Icon createdIcon = Icon.FromHandle(bitmap.GetHicon()); drawBrush.Dispose(); graphics.Dispose(); bitmap.Dispose(); return createdIcon; } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); return null; } } public void Export2ClientConfig(ProfileItem item, Config config) { if (item == null) { return; } if (item.configType == EConfigType.Custom) { UI.Show(ResUI.NonVmessService); return; } SaveFileDialog fileDialog = new() { Filter = "Config|*.json", FilterIndex = 2, RestoreDirectory = true }; if (fileDialog.ShowDialog() != true) { return; } string fileName = fileDialog.FileName; if (Utils.IsNullOrEmpty(fileName)) { return; } if (CoreConfigHandler.GenerateClientConfig(item, fileName, out string msg, out string content) != 0) { UI.Show(msg); } else { UI.ShowWarning(string.Format(ResUI.SaveClientConfigurationIn, fileName)); } } public void UpdateTask(Config config, Action update) { // We don't want to update subscription manually in code, it'll be handled in another part of code (search Auto update sub) //Task.Run(() => UpdateTaskRunSubscription(config, update)); Task.Run(() => UpdateTaskRunGeo(config, update)); } private void UpdateTaskRunSubscription(Config config, Action update) { Thread.Sleep(60000); Utils.SaveLog("UpdateTaskRunSubscription"); var updateHandle = new UpdateHandle(); while (true) { var updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds(); var lstSubs = LazyConfig.Instance.SubItems() .Where(t => t.profileUpdateInterval > 0) .Where(t => updateTime - t.updateTime >= t.profileUpdateInterval * 60) .ToList(); foreach (var item in lstSubs) { updateHandle.UpdateSubscriptionProcess(config, item.id, true, (bool success, string msg) => { update(success, msg); if (success) Utils.SaveLog("subscription" + msg); }); item.updateTime = updateTime; ConfigHandler.AddSubItem(ref config, item); Thread.Sleep(5000); } Thread.Sleep(60000); } } private void UpdateTaskRunGeo(Config config, Action update) { var autoUpdateGeoTime = DateTime.Now; Thread.Sleep(1000 * 120); Utils.SaveLog("UpdateTaskRunGeo"); var updateHandle = new UpdateHandle(); while (true) { var dtNow = DateTime.Now; if (config.guiItem.autoUpdateInterval > 0) { if ((dtNow - autoUpdateGeoTime).Hours % config.guiItem.autoUpdateInterval == 0) { updateHandle.UpdateGeoFileAll(config, (bool success, string msg) => { update(false, msg); }); autoUpdateGeoTime = dtNow; } } Thread.Sleep(1000 * 3600); } } public void RegisterGlobalHotkey(Config config, Action handler, Action update) { HotkeyHandler.Instance.UpdateViewEvent += update; HotkeyHandler.Instance.HotkeyTriggerEvent += handler; HotkeyHandler.Instance.Load(); } } } ================================================ FILE: v2rayN/v2rayN/Handler/NoticeHandler.cs ================================================ using MaterialDesignThemes.Wpf; using ReactiveUI; namespace v2rayN.Handler { public class NoticeHandler { private readonly ISnackbarMessageQueue _snackbarMessageQueue; public NoticeHandler(ISnackbarMessageQueue snackbarMessageQueue) { _snackbarMessageQueue = snackbarMessageQueue ?? throw new ArgumentNullException(nameof(snackbarMessageQueue)); //_snackbarMessageQueue = snackbarMessageQueue; } public void Enqueue(object content) { _snackbarMessageQueue?.Enqueue(content); } public void SendMessage(string msg) { MessageBus.Current.SendMessage(msg, "MsgView"); } public void SendMessage(string msg, bool time) { msg = $"{DateTime.Now} {msg}"; MessageBus.Current.SendMessage(msg, "MsgView"); } } } ================================================ FILE: v2rayN/v2rayN/Handler/ProfileExHandler.cs ================================================ using System.Collections.Concurrent; using System.Reactive.Linq; using v2rayN.Base; using v2rayN.Mode; namespace v2rayN.Handler { internal class ProfileExHandler { private static readonly Lazy _instance = new(() => new()); private ConcurrentBag _lstProfileEx; private Queue _queIndexIds = new(); public ConcurrentBag ProfileExs => _lstProfileEx; public static ProfileExHandler Instance => _instance.Value; public ProfileExHandler() { Init(); } private void Init() { SqliteHelper.Instance.Execute($"delete from ProfileExItem where indexId not in ( select indexId from ProfileItem )"); _lstProfileEx = new(SqliteHelper.Instance.Table()); Task.Run(() => { while (true) { var cnt = _queIndexIds.Count; for (int i = 0; i < cnt; i++) { var id = _queIndexIds.Dequeue(); var item = _lstProfileEx.FirstOrDefault(t => t.indexId == id); if (item is not null) { SqliteHelper.Instance.Replace(item); } } Thread.Sleep(1000 * 60); } }); } private void IndexIdEnqueue(string indexId) { if (!Utils.IsNullOrEmpty(indexId) && !_queIndexIds.Contains(indexId)) { _queIndexIds.Enqueue(indexId); } } private void AddProfileEx(string indexId, ref ProfileExItem profileEx) { profileEx = new() { indexId = indexId, delay = 0, speed = 0, sort = 0 }; _lstProfileEx.Add(profileEx); IndexIdEnqueue(indexId); } public void ClearAll() { SqliteHelper.Instance.Execute($"delete from ProfileExItem "); _lstProfileEx = new(); } public void SaveTo() { try { //foreach (var item in _lstProfileEx) //{ // SqliteHelper.Instance.Replace(item); //} SqliteHelper.Instance.UpdateAll(_lstProfileEx); } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } } public void SetTestDelay(string indexId, string delayVal) { var profileEx = _lstProfileEx.FirstOrDefault(t => t.indexId == indexId); if (profileEx == null) { AddProfileEx(indexId, ref profileEx); } int.TryParse(delayVal, out int delay); profileEx.delay = delay; IndexIdEnqueue(indexId); } public void SetTestSpeed(string indexId, string speedVal) { var profileEx = _lstProfileEx.FirstOrDefault(t => t.indexId == indexId); if (profileEx == null) { AddProfileEx(indexId, ref profileEx); } decimal.TryParse(speedVal, out decimal speed); profileEx.speed = speed; IndexIdEnqueue(indexId); } public void SetSort(string indexId, int sort) { var profileEx = _lstProfileEx.FirstOrDefault(t => t.indexId == indexId); if (profileEx == null) { AddProfileEx(indexId, ref profileEx); } profileEx.sort = sort; IndexIdEnqueue(indexId); } public int GetSort(string indexId) { var profileEx = _lstProfileEx.FirstOrDefault(t => t.indexId == indexId); if (profileEx == null) { return 0; } return profileEx.sort; } public int GetMaxSort() { if (_lstProfileEx.Count <= 0) { return 0; } return _lstProfileEx.Max(t => t == null ? 0 : t.sort); } } } ================================================ FILE: v2rayN/v2rayN/Handler/ProxySetting.cs ================================================ using Microsoft.Win32; using System.Runtime.InteropServices; namespace v2rayN.Handler { internal class ProxySetting { public static bool UnsetProxy() { return SetProxy(null, null, 1); } public static bool SetProxy(string? strProxy, string? exceptions, int type) { InternetPerConnOptionList list = new(); int optionCount = 1; if (type == 1) { optionCount = 1; } else if (type is 2 or 4) { optionCount = Utils.IsNullOrEmpty(exceptions) ? 2 : 3; } int m_Int = (int)PerConnFlags.PROXY_TYPE_DIRECT; PerConnOption m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS; if (type == 2) { m_Int = (int)(PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_PROXY); m_Option = PerConnOption.INTERNET_PER_CONN_PROXY_SERVER; } else if (type == 4) { m_Int = (int)(PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_AUTO_PROXY_URL); m_Option = PerConnOption.INTERNET_PER_CONN_AUTOCONFIG_URL; } //int optionCount = Utils.IsNullOrEmpty(strProxy) ? 1 : (Utils.IsNullOrEmpty(exceptions) ? 2 : 3); InternetConnectionOption[] options = new InternetConnectionOption[optionCount]; // USE a proxy server ... options[0].m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS; //options[0].m_Value.m_Int = (int)((optionCount < 2) ? PerConnFlags.PROXY_TYPE_DIRECT : (PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_PROXY)); options[0].m_Value.m_Int = m_Int; // use THIS proxy server if (optionCount > 1) { options[1].m_Option = m_Option; options[1].m_Value.m_StringPtr = Marshal.StringToHGlobalAuto(strProxy); // except for these addresses ... if (optionCount > 2) { options[2].m_Option = PerConnOption.INTERNET_PER_CONN_PROXY_BYPASS; options[2].m_Value.m_StringPtr = Marshal.StringToHGlobalAuto(exceptions); } } // default stuff list.dwSize = Marshal.SizeOf(list); list.szConnection = IntPtr.Zero; list.dwOptionCount = options.Length; list.dwOptionError = 0; int optSize = Marshal.SizeOf(typeof(InternetConnectionOption)); // make a pointer out of all that ... IntPtr optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length); // copy the array over into that spot in memory ... for (int i = 0; i < options.Length; ++i) { if (Environment.Is64BitOperatingSystem) { IntPtr opt = new(optionsPtr.ToInt64() + (i * optSize)); Marshal.StructureToPtr(options[i], opt, false); } else { IntPtr opt = new(optionsPtr.ToInt32() + (i * optSize)); Marshal.StructureToPtr(options[i], opt, false); } } list.options = optionsPtr; // and then make a pointer out of the whole list IntPtr ipcoListPtr = Marshal.AllocCoTaskMem(list.dwSize); Marshal.StructureToPtr(list, ipcoListPtr, false); // and finally, call the API method! int returnvalue = NativeMethods.InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION, ipcoListPtr, list.dwSize) ? -1 : 0; if (returnvalue == 0) { // get the error codes, they might be helpful returnvalue = Marshal.GetLastWin32Error(); } // FREE the data ASAP Marshal.FreeCoTaskMem(optionsPtr); Marshal.FreeCoTaskMem(ipcoListPtr); if (returnvalue > 0) { // throw the error codes, they might be helpful //throw new Win32Exception(Marshal.GetLastWin32Error()); } return (returnvalue < 0); } #region WinInet structures [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct InternetPerConnOptionList { public int dwSize; // size of the INTERNET_PER_CONN_OPTION_LIST struct public IntPtr szConnection; // connection name to set/query options public int dwOptionCount; // number of options to set/query public int dwOptionError; // on error, which option failed //[MarshalAs(UnmanagedType.)] public IntPtr options; }; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct InternetConnectionOption { private static readonly int Size; public PerConnOption m_Option; public InternetConnectionOptionValue m_Value; static InternetConnectionOption() { Size = Marshal.SizeOf(typeof(InternetConnectionOption)); } // Nested Types [StructLayout(LayoutKind.Explicit)] public struct InternetConnectionOptionValue { // Fields [FieldOffset(0)] public System.Runtime.InteropServices.ComTypes.FILETIME m_FileTime; [FieldOffset(0)] public int m_Int; [FieldOffset(0)] public IntPtr m_StringPtr; } } #endregion WinInet structures #region WinInet enums // // options manifests for Internet{Query|Set}Option // public enum InternetOption : uint { INTERNET_OPTION_PER_CONNECTION_OPTION = 75 } // // Options used in INTERNET_PER_CONN_OPTON struct // public enum PerConnOption { INTERNET_PER_CONN_FLAGS = 1, // Sets or retrieves the connection type. The Value member will contain one or more of the values from PerConnFlags INTERNET_PER_CONN_PROXY_SERVER = 2, // Sets or retrieves a string containing the proxy servers. INTERNET_PER_CONN_PROXY_BYPASS = 3, // Sets or retrieves a string containing the URLs that do not use the proxy server. INTERNET_PER_CONN_AUTOCONFIG_URL = 4//, // Sets or retrieves a string containing the URL to the automatic configuration script. } // // PER_CONN_FLAGS // [Flags] public enum PerConnFlags { PROXY_TYPE_DIRECT = 0x00000001, // direct to net PROXY_TYPE_PROXY = 0x00000002, // via named proxy PROXY_TYPE_AUTO_PROXY_URL = 0x00000004, // autoproxy URL PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection } #endregion WinInet enums internal static class NativeMethods { [DllImport("WinInet.dll", SetLastError = true, CharSet = CharSet.Auto)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool InternetSetOption(IntPtr hInternet, InternetOption dwOption, IntPtr lpBuffer, int dwBufferLength); } //判断是否使用代理 public static bool UsedProxy() { using RegistryKey? rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true); if (rk?.GetValue("ProxyEnable")?.ToString() == "1") { return true; } else { return false; } } //获得代理的IP和端口 public static string? GetProxyProxyServer() { using RegistryKey? rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true); string ProxyServer = rk.GetValue("ProxyServer").ToString(); return ProxyServer; } } } ================================================ FILE: v2rayN/v2rayN/Handler/QRCodeHelper.cs ================================================ using QRCoder; using QRCoder.Xaml; using System.Windows.Media; namespace v2rayN.Handler { /// /// 含有QR码的描述类和包装编码和渲染 /// public class QRCodeHelper { public static DrawingImage? GetQRCode(string strContent) { try { QRCodeGenerator qrGenerator = new(); QRCodeData qrCodeData = qrGenerator.CreateQrCode(strContent, QRCodeGenerator.ECCLevel.H); XamlQRCode qrCode = new(qrCodeData); DrawingImage qrCodeAsXaml = qrCode.GetGraphic(40); return qrCodeAsXaml; } catch { return null; } } } } ================================================ FILE: v2rayN/v2rayN/Handler/ShareHandler.cs ================================================ using System.Collections.Specialized; using System.Text.RegularExpressions; using System.Web; using v2rayN.Base; using v2rayN.Mode; using v2rayN.Resx; namespace v2rayN.Handler { internal class ShareHandler { #region GetShareUrl /// /// GetShareUrl /// /// /// public static string? GetShareUrl(ProfileItem item) { try { string? url = string.Empty; url = item.configType switch { EConfigType.VMess => ShareVmess(item), EConfigType.Shadowsocks => ShareShadowsocks(item), EConfigType.Socks => ShareSocks(item), EConfigType.Trojan => ShareTrojan(item), EConfigType.VLESS => ShareVLESS(item), _ => null, }; return url; } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); return ""; } } private static string ShareVmess(ProfileItem item) { string url = string.Empty; VmessQRCode vmessQRCode = new() { v = item.configVersion.ToString(), ps = item.remarks.TrimEx(), add = item.address, port = item.port.ToString(), id = item.id, aid = item.alterId.ToString(), scy = item.security, net = item.network, type = item.headerType, host = item.requestHost, path = item.path, tls = item.streamSecurity, sni = item.sni, alpn = item.alpn, fp = item.fingerprint, allowInsecure = item.allowInsecure }; url = Utils.ToJson(vmessQRCode); url = Utils.Base64Encode(url); url = $"{Global.vmessProtocol}{url}"; return url; } private static string ShareShadowsocks(ProfileItem item) { string url = string.Empty; string remark = string.Empty; if (!Utils.IsNullOrEmpty(item.remarks)) { remark = "#" + Utils.UrlEncode(item.remarks); } //url = string.Format("{0}:{1}@{2}:{3}", // item.security, // item.id, // item.address, // item.port); //url = Utils.Base64Encode(url); //new Sip002 var pw = Utils.Base64Encode($"{item.security}:{item.id}"); url = $"{pw}@{GetIpv6(item.address)}:{item.port}"; url = $"{Global.ssProtocol}{url}{remark}"; return url; } private static string ShareSocks(ProfileItem item) { string url = string.Empty; string remark = string.Empty; if (!Utils.IsNullOrEmpty(item.remarks)) { remark = "#" + Utils.UrlEncode(item.remarks); } //url = string.Format("{0}:{1}@{2}:{3}", // item.security, // item.id, // item.address, // item.port); //url = Utils.Base64Encode(url); //new var pw = Utils.Base64Encode($"{item.security}:{item.id}"); url = $"{pw}@{GetIpv6(item.address)}:{item.port}"; url = $"{Global.socksProtocol}{url}{remark}"; return url; } private static string ShareTrojan(ProfileItem item) { string url = string.Empty; string remark = string.Empty; if (!Utils.IsNullOrEmpty(item.remarks)) { remark = "#" + Utils.UrlEncode(item.remarks); } var dicQuery = new Dictionary(); GetStdTransport(item, null, ref dicQuery); string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray()); url = string.Format("{0}@{1}:{2}", item.id, GetIpv6(item.address), item.port); url = $"{Global.trojanProtocol}{url}{query}{remark}"; return url; } private static string ShareVLESS(ProfileItem item) { string url = string.Empty; string remark = string.Empty; if (!Utils.IsNullOrEmpty(item.remarks)) { remark = "#" + Utils.UrlEncode(item.remarks); } var dicQuery = new Dictionary(); if (!Utils.IsNullOrEmpty(item.security)) { dicQuery.Add("encryption", item.security); } else { dicQuery.Add("encryption", "none"); } GetStdTransport(item, "none", ref dicQuery); string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray()); url = string.Format("{0}@{1}:{2}", item.id, GetIpv6(item.address), item.port); url = $"{Global.vlessProtocol}{url}{query}{remark}"; return url; } private static string GetIpv6(string address) { return Utils.IsIpv6(address) ? $"[{address}]" : address; } private static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary dicQuery) { if (!Utils.IsNullOrEmpty(item.flow)) { dicQuery.Add("flow", item.flow); } if (!Utils.IsNullOrEmpty(item.streamSecurity)) { dicQuery.Add("security", item.streamSecurity); } else { if (securityDef != null) { dicQuery.Add("security", securityDef); } } if (!Utils.IsNullOrEmpty(item.sni)) { dicQuery.Add("sni", item.sni); } if (!Utils.IsNullOrEmpty(item.alpn)) { dicQuery.Add("alpn", Utils.UrlEncode(item.alpn)); } if (!Utils.IsNullOrEmpty(item.fingerprint)) { dicQuery.Add("fp", Utils.UrlEncode(item.fingerprint)); } if (!Utils.IsNullOrEmpty(item.allowInsecure))//Hiddify { dicQuery.Add("allowInsecure", item.allowInsecure); } if (!Utils.IsNullOrEmpty(item.publicKey)) { dicQuery.Add("pbk", Utils.UrlEncode(item.publicKey)); } if (!Utils.IsNullOrEmpty(item.shortId)) { dicQuery.Add("sid", Utils.UrlEncode(item.shortId)); } if (!Utils.IsNullOrEmpty(item.spiderX)) { dicQuery.Add("spx", Utils.UrlEncode(item.spiderX)); } dicQuery.Add("type", !Utils.IsNullOrEmpty(item.network) ? item.network : "tcp"); switch (item.network) { case "tcp": dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : "none"); if (!Utils.IsNullOrEmpty(item.requestHost)) { dicQuery.Add("host", Utils.UrlEncode(item.requestHost)); } break; case "kcp": dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : "none"); if (!Utils.IsNullOrEmpty(item.path)) { dicQuery.Add("seed", Utils.UrlEncode(item.path)); } break; case "ws": if (!Utils.IsNullOrEmpty(item.requestHost)) { dicQuery.Add("host", Utils.UrlEncode(item.requestHost)); } if (!Utils.IsNullOrEmpty(item.path)) { dicQuery.Add("path", Utils.UrlEncode(item.path)); } break; case "http": case "h2": dicQuery["type"] = "http"; if (!Utils.IsNullOrEmpty(item.requestHost)) { dicQuery.Add("host", Utils.UrlEncode(item.requestHost)); } if (!Utils.IsNullOrEmpty(item.path)) { dicQuery.Add("path", Utils.UrlEncode(item.path)); } break; case "quic": dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : "none"); dicQuery.Add("quicSecurity", Utils.UrlEncode(item.requestHost)); dicQuery.Add("key", Utils.UrlEncode(item.path)); break; case "grpc": if (!Utils.IsNullOrEmpty(item.path)) { dicQuery.Add("serviceName", Utils.UrlEncode(item.path)); if (item.headerType is Global.GrpcgunMode or Global.GrpcmultiMode) { dicQuery.Add("mode", Utils.UrlEncode(item.headerType)); } } break; } return 0; } #endregion GetShareUrl #region ImportShareUrl /// /// 从剪贴板导入URL /// /// /// public static ProfileItem? ImportFromClipboardConfig(string clipboardData, out string msg) { msg = string.Empty; ProfileItem profileItem = new(); try { //载入配置文件 string result = clipboardData.TrimEx();// Utils.GetClipboardData(); if (Utils.IsNullOrEmpty(result)) { msg = ResUI.FailedReadConfiguration; return null; } if (result.StartsWith(Global.vmessProtocol)) { int indexSplit = result.IndexOf("?"); if (indexSplit > 0) { profileItem = ResolveStdVmess(result) ?? ResolveVmess4Kitsunebi(result); } else { profileItem = ResolveVmess(result, out msg); } } else if (result.StartsWith(Global.ssProtocol)) { msg = ResUI.ConfigurationFormatIncorrect; profileItem = ResolveSSLegacy(result) ?? ResolveSip002(result); if (profileItem == null) { return null; } if (profileItem.address.Length == 0 || profileItem.port == 0 || profileItem.security.Length == 0 || profileItem.id.Length == 0) { return null; } profileItem.configType = EConfigType.Shadowsocks; } else if (result.StartsWith(Global.socksProtocol)) { msg = ResUI.ConfigurationFormatIncorrect; profileItem = ResolveSocksNew(result) ?? ResolveSocks(result); if (profileItem == null) { return null; } if (profileItem.address.Length == 0 || profileItem.port == 0) { return null; } profileItem.configType = EConfigType.Socks; } else if (result.StartsWith(Global.trojanProtocol)) { msg = ResUI.ConfigurationFormatIncorrect; profileItem = ResolveTrojan(result); } else if (result.StartsWith(Global.vlessProtocol)) { profileItem = ResolveStdVLESS(result); } else { msg = ResUI.NonvmessOrssProtocol; return null; } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); msg = ResUI.Incorrectconfiguration; return null; } return profileItem; } private static ProfileItem? ResolveVmess(string result, out string msg) { msg = string.Empty; var profileItem = new ProfileItem { configType = EConfigType.VMess }; result = result[Global.vmessProtocol.Length..]; result = Utils.Base64Decode(result); //转成Json VmessQRCode? vmessQRCode = Utils.FromJson(result); if (vmessQRCode == null) { msg = ResUI.FailedConversionConfiguration; return null; } profileItem.network = Global.DefaultNetwork; profileItem.headerType = Global.None; profileItem.configVersion = Utils.ToInt(vmessQRCode.v); profileItem.remarks = Utils.ToString(vmessQRCode.ps); profileItem.address = Utils.ToString(vmessQRCode.add); profileItem.port = Utils.ToInt(vmessQRCode.port); profileItem.id = Utils.ToString(vmessQRCode.id); profileItem.alterId = Utils.ToInt(vmessQRCode.aid); profileItem.security = Utils.ToString(vmessQRCode.scy); profileItem.security = !Utils.IsNullOrEmpty(vmessQRCode.scy) ? vmessQRCode.scy : Global.DefaultSecurity; if (!Utils.IsNullOrEmpty(vmessQRCode.net)) { profileItem.network = vmessQRCode.net; } if (!Utils.IsNullOrEmpty(vmessQRCode.type)) { profileItem.headerType = vmessQRCode.type; } profileItem.requestHost = Utils.ToString(vmessQRCode.host); profileItem.path = Utils.ToString(vmessQRCode.path); profileItem.streamSecurity = Utils.ToString(vmessQRCode.tls); profileItem.sni = Utils.ToString(vmessQRCode.sni); profileItem.alpn = Utils.ToString(vmessQRCode.alpn); profileItem.fingerprint = Utils.ToString(vmessQRCode.fp); profileItem.allowInsecure = Utils.ToString(vmessQRCode.allowInsecure); return profileItem; } private static ProfileItem? ResolveVmess4Kitsunebi(string result) { ProfileItem profileItem = new() { configType = EConfigType.VMess }; result = result[Global.vmessProtocol.Length..]; int indexSplit = result.IndexOf("?"); if (indexSplit > 0) { result = result[..indexSplit]; } result = Utils.Base64Decode(result); string[] arr1 = result.Split('@'); if (arr1.Length != 2) { return null; } string[] arr21 = arr1[0].Split(':'); string[] arr22 = arr1[1].Split(':'); if (arr21.Length != 2 || arr22.Length != 2) { return null; } profileItem.address = arr22[0]; profileItem.port = Utils.ToInt(arr22[1]); profileItem.security = arr21[0]; profileItem.id = arr21[1]; profileItem.network = Global.DefaultNetwork; profileItem.headerType = Global.None; profileItem.remarks = "Alien"; return profileItem; } private static ProfileItem? ResolveStdVmess(string result) { ProfileItem i = new() { configType = EConfigType.VMess, security = "auto" }; Uri u = new(result); i.address = u.IdnHost; i.port = u.Port; i.remarks = u.GetComponents(UriComponents.Fragment, UriFormat.Unescaped); var q = HttpUtility.ParseQueryString(u.Query); var m = StdVmessUserInfo.Match(u.UserInfo); if (!m.Success) return null; i.id = m.Groups["id"].Value; if (m.Groups["streamSecurity"].Success) { i.streamSecurity = m.Groups["streamSecurity"].Value; } switch (i.streamSecurity) { case "tls": break; default: if (!string.IsNullOrWhiteSpace(i.streamSecurity)) return null; break; } i.network = m.Groups["network"].Value; switch (i.network) { case "tcp": string t1 = q["type"] ?? "none"; i.headerType = t1; break; case "kcp": i.headerType = q["type"] ?? "none"; break; case "ws": string p1 = q["path"] ?? "/"; string h1 = q["host"] ?? ""; i.requestHost = Utils.UrlDecode(h1); i.path = p1; break; case "http": case "h2": i.network = "h2"; string p2 = q["path"] ?? "/"; string h2 = q["host"] ?? ""; i.requestHost = Utils.UrlDecode(h2); i.path = p2; break; case "quic": string s = q["security"] ?? "none"; string k = q["key"] ?? ""; string t3 = q["type"] ?? "none"; i.headerType = t3; i.requestHost = Utils.UrlDecode(s); i.path = k; break; default: return null; } i.allowInsecure = q["allowInsecure"] ?? ""; return i; } private static ProfileItem? ResolveSip002(string result) { Uri parsedUrl; try { parsedUrl = new Uri(result); } catch (UriFormatException) { return null; } ProfileItem server = new() { remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped), address = parsedUrl.IdnHost, port = parsedUrl.Port, }; string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.UriEscaped); //2022-blake3 if (rawUserInfo.Contains(':')) { string[] userInfoParts = rawUserInfo.Split(new[] { ':' }, 2); if (userInfoParts.Length != 2) { return null; } server.security = userInfoParts[0]; server.id = Utils.UrlDecode(userInfoParts[1]); } else { // parse base64 UserInfo string userInfo = Utils.Base64Decode(rawUserInfo); string[] userInfoParts = userInfo.Split(new[] { ':' }, 2); if (userInfoParts.Length != 2) { return null; } server.security = userInfoParts[0]; server.id = userInfoParts[1]; } NameValueCollection queryParameters = HttpUtility.ParseQueryString(parsedUrl.Query); if (queryParameters["plugin"] != null) { //obfs-host exists var obfsHost = queryParameters["plugin"].Split(';').FirstOrDefault(t => t.Contains("obfs-host")); if (queryParameters["plugin"].Contains("obfs=http") && !Utils.IsNullOrEmpty(obfsHost)) { obfsHost = obfsHost.Replace("obfs-host=", ""); server.network = Global.DefaultNetwork; server.headerType = Global.TcpHeaderHttp; server.requestHost = obfsHost; } else { return null; } } server.allowInsecure = queryParameters["allowInsecure"] ?? ""; return server; } private static readonly Regex UrlFinder = new(@"ss://(?[A-Za-z0-9+-/=_]+)(?:#(?\S+))?", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex DetailsParser = new(@"^((?.+?):(?.*)@(?.+?):(?\d+?))$", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static ProfileItem? ResolveSSLegacy(string result) { var match = UrlFinder.Match(result); if (!match.Success) return null; ProfileItem server = new(); var base64 = match.Groups["base64"].Value.TrimEnd('/'); var tag = match.Groups["tag"].Value; if (!Utils.IsNullOrEmpty(tag)) { server.remarks = Utils.UrlDecode(tag); } Match details; try { details = DetailsParser.Match(Utils.Base64Decode(base64)); } catch (FormatException) { return null; } if (!details.Success) return null; server.security = details.Groups["method"].Value; server.id = details.Groups["password"].Value; server.address = details.Groups["hostname"].Value; server.port = int.Parse(details.Groups["port"].Value); return server; } private static readonly Regex StdVmessUserInfo = new( @"^(?[a-z]+)(\+(?[a-z]+))?:(?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$", RegexOptions.Compiled); private static ProfileItem? ResolveSocks(string result) { ProfileItem profileItem = new() { configType = EConfigType.Socks }; result = result[Global.socksProtocol.Length..]; //remark int indexRemark = result.IndexOf("#"); if (indexRemark > 0) { try { profileItem.remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1)); } catch { } result = result[..indexRemark]; } //part decode int indexS = result.IndexOf("@"); if (indexS > 0) { } else { result = Utils.Base64Decode(result); } string[] arr1 = result.Split('@'); if (arr1.Length != 2) { return null; } string[] arr21 = arr1[0].Split(':'); //string[] arr22 = arr1[1].Split(':'); int indexPort = arr1[1].LastIndexOf(":"); if (arr21.Length != 2 || indexPort < 0) { return null; } profileItem.address = arr1[1][..indexPort]; profileItem.port = Utils.ToInt(arr1[1][(indexPort + 1)..]); profileItem.security = arr21[0]; profileItem.id = arr21[1]; return profileItem; } private static ProfileItem? ResolveSocksNew(string result) { Uri parsedUrl; try { parsedUrl = new Uri(result); } catch (UriFormatException) { return null; } ProfileItem server = new() { remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped), address = parsedUrl.IdnHost, port = parsedUrl.Port, }; // parse base64 UserInfo string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.Unescaped); string userInfo = Utils.Base64Decode(rawUserInfo); string[] userInfoParts = userInfo.Split(new[] { ':' }, 2); if (userInfoParts.Length == 2) { server.security = userInfoParts[0]; server.id = userInfoParts[1]; } return server; } private static ProfileItem ResolveTrojan(string result) { ProfileItem item = new() { configType = EConfigType.Trojan }; Uri url = new(result); item.address = url.IdnHost; item.port = url.Port; item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped); item.id = url.UserInfo; var query = HttpUtility.ParseQueryString(url.Query); ResolveStdTransport(query, ref item); return item; } private static ProfileItem ResolveStdVLESS(string result) { ProfileItem item = new() { configType = EConfigType.VLESS, security = "none" }; Uri url = new(result); item.address = url.IdnHost; item.port = url.Port; item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped); item.id = url.UserInfo; var query = HttpUtility.ParseQueryString(url.Query); item.security = query["encryption"] ?? "none"; item.streamSecurity = query["security"] ?? ""; ResolveStdTransport(query, ref item); return item; } private static int ResolveStdTransport(NameValueCollection query, ref ProfileItem item) { item.flow = query["flow"] ?? ""; item.streamSecurity = query["security"] ?? ""; item.sni = query["sni"] ?? ""; item.alpn = Utils.UrlDecode(query["alpn"] ?? ""); item.allowInsecure= query["allowInsecure"] ?? ""; item.fingerprint = Utils.UrlDecode(query["fp"] ?? ""); item.fragment = Utils.UrlDecode(query["fragment"] ?? ""); item.publicKey = Utils.UrlDecode(query["pbk"] ?? ""); item.shortId = Utils.UrlDecode(query["sid"] ?? ""); item.spiderX = Utils.UrlDecode(query["spx"] ?? ""); item.network = query["type"] ?? "tcp"; switch (item.network) { case "tcp": item.headerType = query["headerType"] ?? "none"; item.requestHost = Utils.UrlDecode(query["host"] ?? ""); break; case "kcp": item.headerType = query["headerType"] ?? "none"; item.path = Utils.UrlDecode(query["seed"] ?? ""); break; case "ws": item.requestHost = Utils.UrlDecode(query["host"] ?? ""); item.path = Utils.UrlDecode(query["path"] ?? "/"); break; case "http": case "h2": item.network = "h2"; item.requestHost = Utils.UrlDecode(query["host"] ?? ""); item.path = Utils.UrlDecode(query["path"] ?? "/"); break; case "quic": item.headerType = query["headerType"] ?? "none"; item.requestHost = query["quicSecurity"] ?? "none"; item.path = Utils.UrlDecode(query["key"] ?? ""); break; case "grpc": item.path = Utils.UrlDecode(query["serviceName"] ?? ""); item.headerType = Utils.UrlDecode(query["mode"] ?? Global.GrpcgunMode); break; default: break; } return 0; } #endregion ImportShareUrl } } ================================================ FILE: v2rayN/v2rayN/Handler/SpeedtestHandler.cs ================================================ using System.Diagnostics; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using v2rayN.Mode; using v2rayN.Resx; namespace v2rayN.Handler { internal class SpeedtestHandler { private Config _config; private CoreHandler _coreHandler; private List _selecteds; private ESpeedActionType _actionType; private Action _updateFunc; public SpeedtestHandler(Config config) { _config = config; } public SpeedtestHandler(Config config, CoreHandler coreHandler, List selecteds, ESpeedActionType actionType, Action update) { _config = config; _coreHandler = coreHandler; _actionType = actionType; _updateFunc = update; _selecteds = new List(); foreach (var it in selecteds) { if (it.configType == EConfigType.Custom) { // continue; } if (it.port <= 0) { // continue; } _selecteds.Add(new ServerTestItem() { indexId = it.indexId, address = it.address, port = it.port, configType = it.configType }); } //clear test result foreach (var it in _selecteds) { switch (actionType) { case ESpeedActionType.Ping: case ESpeedActionType.Tcping: case ESpeedActionType.Realping: UpdateFunc(it.indexId, ResUI.Speedtesting, ""); ProfileExHandler.Instance.SetTestDelay(it.indexId, "0"); break; case ESpeedActionType.Speedtest: UpdateFunc(it.indexId, "", ResUI.SpeedtestingWait); ProfileExHandler.Instance.SetTestSpeed(it.indexId, "0"); break; case ESpeedActionType.Mixedtest: UpdateFunc(it.indexId, ResUI.Speedtesting, ResUI.SpeedtestingWait); ProfileExHandler.Instance.SetTestDelay(it.indexId, "0"); ProfileExHandler.Instance.SetTestSpeed(it.indexId, "0"); break; } } switch (actionType) { case ESpeedActionType.Ping: Task.Run(RunPing); break; case ESpeedActionType.Tcping: Task.Run(RunTcping); break; case ESpeedActionType.Realping: Task.Run(RunRealPing); break; case ESpeedActionType.Speedtest: Task.Run(RunSpeedTestAsync); break; case ESpeedActionType.Mixedtest: Task.Run(RunMixedtestAsync); break; } } private void RunPingSub(Action updateFun) { try { foreach (var it in _selecteds.Where(it => it.configType != EConfigType.Custom)) { try { Task.Run(() => updateFun(it)); } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } } Thread.Sleep(10); } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } } private void RunPing() { RunPingSub((ServerTestItem it) => { long time = Ping(it.address); var output = FormatOut(time, Global.DelayUnit); ProfileExHandler.Instance.SetTestDelay(it.indexId, output); UpdateFunc(it.indexId, output); }); } private void RunTcping() { RunPingSub((ServerTestItem it) => { int time = GetTcpingTime(it.address, it.port); var output = FormatOut(time, Global.DelayUnit); ProfileExHandler.Instance.SetTestDelay(it.indexId, output); UpdateFunc(it.indexId, output); }); } private Task RunRealPing() { int pid = -1; try { string msg = string.Empty; pid = _coreHandler.LoadCoreConfigString(_selecteds); if (pid < 0) { UpdateFunc("", ResUI.FailedToRunCore); return Task.CompletedTask; } DownloadHandle downloadHandle = new DownloadHandle(); //Thread.Sleep(5000); List tasks = new(); foreach (var it in _selecteds) { if (!it.allowTest) { continue; } if (it.configType == EConfigType.Custom) { continue; } tasks.Add(Task.Run(async () => { try { WebProxy webProxy = new(Global.Loopback, it.port); string output = await GetRealPingTime(downloadHandle, webProxy); ProfileExHandler.Instance.SetTestDelay(it.indexId, output); UpdateFunc(it.indexId, output); int.TryParse(output, out int delay); it.delay = delay; } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } })); //Thread.Sleep(100); } Task.WaitAll(tasks.ToArray()); } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } finally { if (pid > 0) _coreHandler.CoreStopPid(pid); ProfileExHandler.Instance.SaveTo(); } return Task.CompletedTask; } private async Task RunSpeedTestAsync() { int pid = -1; //if (_actionType == ESpeedActionType.Mixedtest) //{ // _selecteds = _selecteds.OrderBy(t => t.delay).ToList(); //} pid = _coreHandler.LoadCoreConfigString(_selecteds); if (pid < 0) { UpdateFunc("", ResUI.FailedToRunCore); return; } string url = _config.speedTestItem.speedTestUrl; var timeout = _config.speedTestItem.speedTestTimeout; DownloadHandle downloadHandle = new(); foreach (var it in _selecteds) { if (!it.allowTest) { continue; } if (it.configType == EConfigType.Custom) { continue; } //if (it.delay < 0) //{ // UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip); // continue; //} ProfileExHandler.Instance.SetTestSpeed(it.indexId, "-1"); UpdateFunc(it.indexId, "", ResUI.Speedtesting); var item = LazyConfig.Instance.GetProfileItem(it.indexId); if (item is null) continue; WebProxy webProxy = new(Global.Loopback, it.port); await downloadHandle.DownloadDataAsync(url, webProxy, timeout, (bool success, string msg) => { decimal.TryParse(msg, out decimal dec); if (dec > 0) { ProfileExHandler.Instance.SetTestSpeed(it.indexId, msg); } UpdateFunc(it.indexId, "", msg); }); } if (pid > 0) { _coreHandler.CoreStopPid(pid); } UpdateFunc("", ResUI.SpeedtestingCompleted); ProfileExHandler.Instance.SaveTo(); } private async Task RunSpeedTestMulti() { int pid = -1; pid = _coreHandler.LoadCoreConfigString(_selecteds); if (pid < 0) { UpdateFunc("", ResUI.FailedToRunCore); return; } string url = _config.speedTestItem.speedTestUrl; var timeout = _config.speedTestItem.speedTestTimeout; DownloadHandle downloadHandle = new(); foreach (var it in _selecteds) { if (!it.allowTest) { continue; } if (it.configType == EConfigType.Custom) { continue; } if (it.delay < 0) { UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip); continue; } ProfileExHandler.Instance.SetTestSpeed(it.indexId, "-1"); UpdateFunc(it.indexId, "", ResUI.Speedtesting); var item = LazyConfig.Instance.GetProfileItem(it.indexId); if (item is null) continue; WebProxy webProxy = new(Global.Loopback, it.port); _ = downloadHandle.DownloadDataAsync(url, webProxy, timeout, (bool success, string msg) => { decimal.TryParse(msg, out decimal dec); if (dec > 0) { ProfileExHandler.Instance.SetTestSpeed(it.indexId, msg); } UpdateFunc(it.indexId, "", msg); }); Thread.Sleep(2000); } Thread.Sleep((timeout + 2) * 1000); if (pid > 0) { _coreHandler.CoreStopPid(pid); } UpdateFunc("", ResUI.SpeedtestingCompleted); ProfileExHandler.Instance.SaveTo(); } private async Task RunMixedtestAsync() { await RunRealPing(); Thread.Sleep(1000); await RunSpeedTestMulti(); } public async Task GetRealPingTime(DownloadHandle downloadHandle, IWebProxy webProxy) { int responseTime = await downloadHandle.GetRealPingTime(_config.speedTestItem.speedPingTestUrl, webProxy, 10); responseTime = await downloadHandle.GetRealPingTime(_config.speedTestItem.speedPingTestUrl, webProxy, 10); if (responseTime<0) responseTime = await downloadHandle.GetRealPingTime(_config.speedTestItem.speedPingTestUrl, webProxy, 10); //string output = Utils.IsNullOrEmpty(status) ? FormatOut(responseTime, "ms") : status; return FormatOut(responseTime, Global.DelayUnit); } private int GetTcpingTime(string url, int port) { int responseTime = -1; try { if (!IPAddress.TryParse(url, out IPAddress ipAddress)) { IPHostEntry ipHostInfo = System.Net.Dns.GetHostEntry(url); ipAddress = ipHostInfo.AddressList[0]; } Stopwatch timer = new(); timer.Start(); IPEndPoint endPoint = new(ipAddress, port); using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); IAsyncResult result = clientSocket.BeginConnect(endPoint, null, null); if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5))) throw new TimeoutException("connect timeout (5s): " + url); clientSocket.EndConnect(result); timer.Stop(); responseTime = timer.Elapsed.Milliseconds; } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } return responseTime; } /// /// Ping /// /// /// public long Ping(string host) { long roundtripTime = -1; try { int timeout = 30; int echoNum = 2; using Ping pingSender = new(); for (int i = 0; i < echoNum; i++) { PingReply reply = pingSender.Send(host, timeout); if (reply.Status == IPStatus.Success) { if (reply.RoundtripTime < 0) { continue; } if (roundtripTime < 0 || reply.RoundtripTime < roundtripTime) { roundtripTime = reply.RoundtripTime; } } } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); return -1; } return roundtripTime; } private string FormatOut(object time, string unit) { //if (time.ToString().Equals("-1")) //{ // return "Timeout"; //} return $"{time}"; } private void UpdateFunc(string indexId, string delay, string speed = "") { _updateFunc(indexId, delay, speed); } } } ================================================ FILE: v2rayN/v2rayN/Handler/StatisticsHandler.cs ================================================ using Grpc.Core; using Grpc.Net.Client; using ProtosLib.Statistics; using System.Net; using System.Net.Sockets; using v2rayN.Base; using v2rayN.Mode; namespace v2rayN.Handler { internal class StatisticsHandler { private Mode.Config config_; private GrpcChannel _channel; private StatsService.StatsServiceClient _client; private bool _exitFlag; private ServerStatItem? _serverStatItem; private List _lstServerStat; public List ServerStat => _lstServerStat; private Action _updateFunc; public bool Enable { get; set; } public StatisticsHandler(Mode.Config config, Action update) { config_ = config; Enable = config.guiItem.enableStatistics; _updateFunc = update; _exitFlag = false; Init(); GrpcInit(); Task.Run(Run); } private void GrpcInit() { if (_channel == null) { Global.statePort = GetFreePort(); _channel = GrpcChannel.ForAddress($"{Global.httpProtocol}{Global.Loopback}:{Global.statePort}"); _client = new StatsService.StatsServiceClient(_channel); } } public void Close() { try { _exitFlag = true; //channel_.ShutdownAsync(); } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } } public async void Run() { while (!_exitFlag) { try { if (Enable && _channel.State == ConnectivityState.Ready) { QueryStatsResponse? res = null; try { res = await _client.QueryStatsAsync(new QueryStatsRequest() { Pattern = "", Reset = true }); } catch (Exception ex) { //Utils.SaveLog(ex.Message, ex); } if (res != null) { GetServerStatItem(config_.indexId); ParseOutput(res.Stat, out ServerSpeedItem server); if (server.proxyUp != 0 || server.proxyDown != 0) { _serverStatItem.todayUp += server.proxyUp; _serverStatItem.todayDown += server.proxyDown; _serverStatItem.totalUp += server.proxyUp; _serverStatItem.totalDown += server.proxyDown; } if (Global.ShowInTaskbar) { server.indexId = config_.indexId; server.todayUp = _serverStatItem.todayUp; server.todayDown = _serverStatItem.todayDown; server.totalUp = _serverStatItem.totalUp; server.totalDown = _serverStatItem.totalDown; _updateFunc(server); } } } var sleep = config_.guiItem.statisticsFreshRate < 1 ? 1 : config_.guiItem.statisticsFreshRate; Thread.Sleep(1000 * sleep); await _channel.ConnectAsync(); } catch { } } } public void ClearAllServerStatistics() { SqliteHelper.Instance.Execute($"delete from ServerStatItem "); _serverStatItem = null; _lstServerStat = new(); } public void SaveTo() { try { SqliteHelper.Instance.UpdateAll(_lstServerStat); } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } } private void Init() { SqliteHelper.Instance.Execute($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )"); long ticks = DateTime.Now.Date.Ticks; SqliteHelper.Instance.Execute($"update ServerStatItem set todayUp = 0,todayDown=0,dateNow={ticks} where dateNow<>{ticks}"); _lstServerStat = SqliteHelper.Instance.Table().ToList(); } private void GetServerStatItem(string indexId) { long ticks = DateTime.Now.Date.Ticks; if (_serverStatItem != null && _serverStatItem.indexId != indexId) { _serverStatItem = null; } if (_serverStatItem == null) { _serverStatItem = _lstServerStat.FirstOrDefault(t => t.indexId == indexId); if (_serverStatItem == null) { _serverStatItem = new ServerStatItem { indexId = indexId, totalUp = 0, totalDown = 0, todayUp = 0, todayDown = 0, dateNow = ticks }; SqliteHelper.Instance.Replace(_serverStatItem); _lstServerStat.Add(_serverStatItem); } } if (_serverStatItem.dateNow != ticks) { _serverStatItem.todayUp = 0; _serverStatItem.todayDown = 0; _serverStatItem.dateNow = ticks; } } private void ParseOutput(Google.Protobuf.Collections.RepeatedField source, out ServerSpeedItem server) { server = new(); try { foreach (Stat stat in source) { string name = stat.Name; long value = stat.Value / 1024; //KByte string[] nStr = name.Split(">>>".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); string type = ""; name = name.Trim(); name = nStr[1]; type = nStr[3]; if (name == Global.agentTag) { if (type == "uplink") { server.proxyUp = value; } else if (type == "downlink") { server.proxyDown = value; } } else if (name == Global.directTag) { if (type == "uplink") { server.directUp = value; } else if (type == "downlink") { server.directDown = value; } } } } catch (Exception ex) { //Utils.SaveLog(ex.Message, ex); } } private int GetFreePort() { int defaultPort = 28123; try { // TCP stack please do me a favor TcpListener l = new(IPAddress.Loopback, 0); l.Start(); int port = ((IPEndPoint)l.LocalEndpoint).Port; l.Stop(); return port; } catch (Exception ex) { // in case access denied Utils.SaveLog(ex.Message, ex); return defaultPort; } } } } ================================================ FILE: v2rayN/v2rayN/Handler/SysProxyHandle.cs ================================================ using PacLib; using System.Diagnostics; using System.IO; using System.Text; using v2rayN.Mode; using v2rayN.Properties; using v2rayN.Tool; namespace v2rayN.Handler { public static class SysProxyHandle { //private const string _userWininetConfigFile = "user-wininet.json"; //private static string _queryStr; // In general, this won't change // format: // // // // private static SysproxyConfig? _userSettings = null; private enum RET_ERRORS : int { RET_NO_ERROR = 0, INVALID_FORMAT = 1, NO_PERMISSION = 2, SYSCALL_FAILED = 3, NO_MEMORY = 4, INVAILD_OPTION_COUNT = 5, }; static SysProxyHandle() { try { FileManager.UncompressFile(Utils.GetTempPath("sysproxy.exe"), Environment.Is64BitOperatingSystem ? Resources.sysproxy64_exe : Resources.sysproxy_exe); } catch (IOException ex) { Utils.SaveLog(ex.Message, ex); } } public static bool UpdateSysProxy(Config config, bool forceDisable) { var type = config.sysProxyType; if (forceDisable && type != ESysProxyType.Unchanged) { type = ESysProxyType.ForcedClear; } try { int port = LazyConfig.Instance.GetLocalPort(Global.InboundHttp); int portSocks = LazyConfig.Instance.GetLocalPort(Global.InboundSocks); int portPac = LazyConfig.Instance.GetLocalPort(ESysProxyType.Pac.ToString()); if (port <= 0) { return false; } if (type == ESysProxyType.ForcedChange) { var strExceptions = $"{config.constItem.defIEProxyExceptions};{config.systemProxyExceptions}"; var strProxy = string.Empty; if (Utils.IsNullOrEmpty(config.systemProxyAdvancedProtocol)) { strProxy = $"{Global.Loopback}:{port}"; } else { strProxy = config.systemProxyAdvancedProtocol .Replace("{ip}", Global.Loopback) .Replace("{http_port}", port.ToString()) .Replace("{socks_port}", portSocks.ToString()); } ProxySetting.SetProxy(strProxy, strExceptions, 2); SetIEProxy(true, strProxy, strExceptions); } else if (type == ESysProxyType.ForcedClear) { ProxySetting.UnsetProxy(); ResetIEProxy(); } else if (type == ESysProxyType.Unchanged) { } else if (type == ESysProxyType.Pac) { PacHandler.Start(Utils.GetConfigPath(), port, portPac); var strProxy = $"{Global.httpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}"; ProxySetting.SetProxy(strProxy, "", 4); SetIEProxy(false, strProxy, ""); } if (type != ESysProxyType.Pac) { PacHandler.Stop(); } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } return true; } public static void ResetIEProxy4WindowsShutDown() { try { //TODO To be verified Utils.RegWriteValue(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", "ProxyEnable", 0); } catch { } } public static void SetIEProxy(bool global, string strProxy, string strExceptions) { string arguments = global ? $"global {strProxy} {strExceptions}" : $"pac {strProxy}"; ExecSysproxy(arguments); } // set system proxy to 1 (null) (null) (null) public static void ResetIEProxy() { ExecSysproxy("set 1 - - -"); } private static void ExecSysproxy(string arguments) { // using event to avoid hanging when redirect standard output/error // ref: https://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why // and http://blog.csdn.net/zhangweixing0/article/details/7356841 using AutoResetEvent outputWaitHandle = new(false); using AutoResetEvent errorWaitHandle = new(false); using Process process = new(); // Configure the process using the StartInfo properties. process.StartInfo.FileName = Utils.GetTempPath("sysproxy.exe"); process.StartInfo.Arguments = arguments; process.StartInfo.WorkingDirectory = Utils.GetTempPath(); process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardError = true; process.StartInfo.RedirectStandardOutput = true; // Need to provide encoding info, or output/error strings we got will be wrong. process.StartInfo.StandardOutputEncoding = Encoding.Unicode; process.StartInfo.StandardErrorEncoding = Encoding.Unicode; process.StartInfo.CreateNoWindow = true; StringBuilder output = new(1024); StringBuilder error = new(1024); process.OutputDataReceived += (sender, e) => { if (e.Data == null) { outputWaitHandle.Set(); } else { output.AppendLine(e.Data); } }; process.ErrorDataReceived += (sender, e) => { if (e.Data == null) { errorWaitHandle.Set(); } else { error.AppendLine(e.Data); } }; try { process.Start(); process.BeginErrorReadLine(); process.BeginOutputReadLine(); process.WaitForExit(); } catch (System.ComponentModel.Win32Exception e) { // log the arguments throw new Exception(process.StartInfo.Arguments); } string stderr = error.ToString(); string stdout = output.ToString(); int exitCode = process.ExitCode; if (exitCode != (int)RET_ERRORS.RET_NO_ERROR) { throw new Exception(stderr); } //if (arguments == "query") //{ // if (stdout.IsNullOrWhiteSpace() || stdout.IsNullOrEmpty()) // { // throw new Exception("failed to query wininet settings"); // } // _queryStr = stdout; //} } } } ================================================ FILE: v2rayN/v2rayN/Handler/TunHandler.cs ================================================ using System.Diagnostics; using System.IO; using System.Reactive.Linq; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; namespace v2rayN.Base { public sealed class TunHandler { private static readonly Lazy _instance = new(() => new()); public static TunHandler Instance => _instance.Value; private string _tunConfigName = "tunConfig.json"; private static Config _config; private CoreInfo coreInfo; private Process? _process; private static int _socksPort; private static bool _needRestart = true; private static bool _isRunning = false; public TunHandler() { _config = LazyConfig.Instance.GetConfig(); Observable.Interval(TimeSpan.FromSeconds(10)) .Subscribe(x => { if (_isRunning && _config.tunModeItem.enableTun) { if (_process == null || _process.HasExited) { if (Init() == false) { return; } CoreStart(); Utils.SaveLog("Tun mode monitors restart"); } } }); } public void Start() { var socksPort = LazyConfig.Instance.GetLocalPort(Global.InboundSocks); if (socksPort == _socksPort && _process != null && !_process.HasExited) { _needRestart = false; } _socksPort = socksPort; if (_needRestart) { CoreStop(); if (Init() == false) { return; } CoreStartTest(); CoreStart(); } } public void Stop() { CoreStop(); } private bool Init() { coreInfo = LazyConfig.Instance.GetCoreInfo(ECoreType.sing_box); //Template string configStr = Utils.GetEmbedText(Global.TunSingboxFileName); if (!Utils.IsNullOrEmpty(_config.tunModeItem.customTemplate) && File.Exists(_config.tunModeItem.customTemplate)) { var customTemplate = File.ReadAllText(_config.tunModeItem.customTemplate); if (!Utils.IsNullOrEmpty(customTemplate)) { configStr = customTemplate; } } if (Utils.IsNullOrEmpty(configStr)) { return false; } //settings if (_config.tunModeItem.mtu <= 0) { _config.tunModeItem.mtu = Convert.ToInt32(Global.TunMtus[0]); } if (Utils.IsNullOrEmpty(_config.tunModeItem.stack)) { _config.tunModeItem.stack = Global.TunStacks[0]; } configStr = configStr.Replace("$mtu$", $"{_config.tunModeItem.mtu}"); configStr = configStr.Replace("$strict_route$", $"{_config.tunModeItem.strictRoute.ToString().ToLower()}"); configStr = configStr.Replace("$stack$", $"{_config.tunModeItem.stack}"); //logs configStr = configStr.Replace("$log_disabled$", $"{(!_config.tunModeItem.enabledLog).ToString().ToLower()}"); if (_config.tunModeItem.showWindow) { configStr = configStr.Replace("$log_output$", $""); } else { var dtNow = DateTime.Now; var log_output = $"\"output\": \"{Utils.GetLogPath($"singbox_{dtNow:yyyy-MM-dd}.txt")}\", "; configStr = configStr.Replace("$log_output$", $"{log_output.Replace(@"\", @"\\")}"); } //port configStr = configStr.Replace("$socksPort$", $"{_socksPort}"); //dns string dnsObject = String.Empty; if (_config.tunModeItem.bypassMode) { dnsObject = _config.tunModeItem.directDNS; } else { dnsObject = _config.tunModeItem.proxyDNS; } if (dnsObject.IsNullOrEmpty() || Utils.ParseJson(dnsObject)?.ContainsKey("servers") == false) { dnsObject = Utils.GetEmbedText(Global.TunSingboxDNSFileName); } configStr = configStr.Replace("$dns_object$", dnsObject); //exe routingDirectExe(out List lstDnsExe, out List lstDirectExe); string strDns = string.Join("\",\"", lstDnsExe.ToArray()); configStr = configStr.Replace("$dnsProcessName$", $"\"{strDns}\""); string strDirect = string.Join("\",\"", lstDirectExe.ToArray()); configStr = configStr.Replace("$directProcessName$", $"\"{strDirect}\""); if (_config.tunModeItem.bypassMode) { //direct ips if (_config.tunModeItem.directIP != null && _config.tunModeItem.directIP.Count > 0) { var ips = new { outbound = "direct", ip_cidr = _config.tunModeItem.directIP }; configStr = configStr.Replace("$ruleDirectIPs$", "," + Utils.ToJson(ips)); } //direct process if (_config.tunModeItem.directProcess != null && _config.tunModeItem.directProcess.Count > 0) { var process = new { outbound = "direct", process_name = _config.tunModeItem.directProcess }; configStr = configStr.Replace("$ruleDirectProcess$", "," + Utils.ToJson(process)); } } else { //proxy ips if (_config.tunModeItem.proxyIP != null && _config.tunModeItem.proxyIP.Count > 0) { var ips = new { outbound = "proxy", ip_cidr = _config.tunModeItem.proxyIP }; configStr = configStr.Replace("$ruleProxyIPs$", "," + Utils.ToJson(ips)); } //proxy process if (_config.tunModeItem.proxyProcess != null && _config.tunModeItem.proxyProcess.Count > 0) { var process = new { outbound = "proxy", process_name = _config.tunModeItem.proxyProcess }; configStr = configStr.Replace("$ruleProxyProcess$", "," + Utils.ToJson(process)); } var final = new { outbound = "direct", inbound = "tun-in" }; configStr = configStr.Replace("$ruleFinally$", "," + Utils.ToJson(final)); } configStr = configStr.Replace("$ruleDirectIPs$", ""); configStr = configStr.Replace("$ruleDirectProcess$", ""); configStr = configStr.Replace("$ruleProxyIPs$", ""); configStr = configStr.Replace("$ruleProxyProcess$", ""); configStr = configStr.Replace("$ruleFinally$", ""); File.WriteAllText(Utils.GetConfigPath(_tunConfigName), configStr); return true; } private void routingDirectExe(out List lstDnsExe, out List lstDirectExe) { lstDnsExe = new(); lstDirectExe = new(); var coreInfos = LazyConfig.Instance.GetCoreInfos(); foreach (var it in coreInfos) { if (it.coreType == ECoreType.v2rayN) { continue; } foreach (var it2 in it.coreExes) { if (!lstDnsExe.Contains(it2) && it.coreType != ECoreType.sing_box) { lstDnsExe.Add($"{it2}.exe"); } if (!lstDirectExe.Contains(it2)) { lstDirectExe.Add($"{it2}.exe"); } } } } private void CoreStop() { try { _isRunning = false; if (_process != null) { KillProcess(_process); _process.Dispose(); _process = null; _needRestart = true; } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } } private string CoreFindexe() { string fileName = string.Empty; foreach (string name in coreInfo.coreExes) { string vName = $"{name}.exe"; vName = Utils.GetBinPath(vName, coreInfo.coreType); if (File.Exists(vName)) { fileName = vName; break; } } if (Utils.IsNullOrEmpty(fileName)) { string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.coreType), string.Join(", ", coreInfo.coreExes.ToArray()), coreInfo.coreUrl); Utils.SaveLog(msg); } return fileName; } private void CoreStart() { try { string fileName = CoreFindexe(); if (Utils.IsNullOrEmpty(fileName)) { return; } var showWindow = _config.tunModeItem.showWindow; Process p = new() { StartInfo = new ProcessStartInfo { FileName = fileName, Arguments = $"run -c \"{Utils.GetConfigPath(_tunConfigName)}\"", WorkingDirectory = Utils.GetConfigPath(), UseShellExecute = showWindow, CreateNoWindow = !showWindow, //RedirectStandardError = !showWindow, Verb = "runas", } }; p.Start(); _process = p; _isRunning = true; if (p.WaitForExit(1000)) { //if (showWindow) //{ throw new Exception("start tun mode fail"); //} //else //{ // throw new Exception(p.StandardError.ReadToEnd()); //} } Global.processJob.AddProcess(p.Handle); } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } } private void KillProcess(Process p) { try { p.CloseMainWindow(); p.WaitForExit(100); if (!p.HasExited) { p.Kill(); p.WaitForExit(100); } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } } private int CoreStartTest() { Utils.SaveLog("Tun mode configuration file test start"); try { string fileName = CoreFindexe(); if (fileName == "") { return -1; } Process p = new Process { StartInfo = new ProcessStartInfo { FileName = fileName, Arguments = $"run -c \"{Utils.GetConfigPath(_tunConfigName)}\"", WorkingDirectory = Utils.GetConfigPath(), UseShellExecute = false, CreateNoWindow = true, RedirectStandardError = true, Verb = "runas", } }; p.Start(); if (p.WaitForExit(2000)) { throw new Exception(p.StandardError.ReadToEnd()); } KillProcess(p); return 0; } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); return -1; } finally { Utils.SaveLog("Tun mode configuration file test end"); } } } } ================================================ FILE: v2rayN/v2rayN/Handler/UpdateHandle.cs ================================================ using DynamicData; using Splat; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using System.Windows; using v2rayN.Base; using v2rayN.Mode; using v2rayN.Resx; namespace v2rayN.Handler { internal class UpdateHandle { private Action _updateFunc; private Config _config; public event EventHandler AbsoluteCompleted; public class ResultEventArgs : EventArgs { public bool Success; public string Msg; public ResultEventArgs(bool success, string msg) { Success = success; Msg = msg; } } public void CheckUpdateGuiN(Config config, Action update, bool preRelease) { _config = config; _updateFunc = update; var url = string.Empty; DownloadHandle downloadHandle = new(); downloadHandle.UpdateCompleted += (sender2, args) => { if (args.Success) { _updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully); try { string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url)); fileName = Utils.UrlEncode(fileName); Process process = new() { StartInfo = new ProcessStartInfo { FileName = Global.UpgradeProgramExePath, Arguments = $"\"{fileName}\"", WorkingDirectory = Utils.StartupPath() } }; process.Start(); if (process.Id > 0) { _updateFunc(true, ""); } } catch (Exception ex) { _updateFunc(false, ex.Message); } } else { _updateFunc(false, args.Msg); } }; downloadHandle.Error += (sender2, args) => { _updateFunc(false, args.GetException().Message); }; AbsoluteCompleted += (sender2, args) => { if (args.Success) { _updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, "HiddifyN")); url = args.Msg; _ = askToDownload(downloadHandle, url, true); } else { Locator.Current.GetService()?.Enqueue(args.Msg); _updateFunc(false, args.Msg); } }; _updateFunc(false, string.Format(ResUI.MsgStartUpdating, "HiddifyN")); CheckUpdateAsync(ECoreType.v2rayN, preRelease); } public void CheckUpdateCore(ECoreType type, Config config, Action update, bool preRelease) { _config = config; _updateFunc = update; var url = string.Empty; DownloadHandle downloadHandle = new(); downloadHandle.UpdateCompleted += (sender2, args) => { if (args.Success) { _updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully); _updateFunc(false, ResUI.MsgUnpacking); try { _updateFunc(true, url); } catch (Exception ex) { _updateFunc(false, ex.Message); } } else { _updateFunc(false, args.Msg); } }; downloadHandle.Error += (sender2, args) => { _updateFunc(true, args.GetException().Message); }; AbsoluteCompleted += (sender2, args) => { if (args.Success) { _updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, "Core")); url = args.Msg; _ = askToDownload(downloadHandle, url, true); } else { Locator.Current.GetService()?.Enqueue(args.Msg); _updateFunc(false, args.Msg); } }; _updateFunc(false, string.Format(ResUI.MsgStartUpdating, "Core")); CheckUpdateAsync(type, preRelease); } public void UpdateSubscriptionProcess(Config config, string subId, bool blProxy, Action update) { _config = config; _updateFunc = update; _updateFunc(false, ResUI.MsgUpdateSubscriptionStart); var subItem = LazyConfig.Instance.SubItems(); if (subItem == null || subItem.Count <= 0) { _updateFunc(false, ResUI.MsgNoValidSubscription); return; } bool anySubUpdated = false; Task.Run(async () => { for (int i = 0; i< subItem.Count; i++) { var item = subItem[i]; if (item.enabled == false) { continue; } if (!Utils.IsNullOrEmpty(subId) && item.id != subId) { continue; } string id = item.id.TrimEx(); string url = item.url.TrimEx(); string userAgent = item.userAgent.TrimEx(); string hashCode = $"{item.remarks}->"; if (Utils.IsNullOrEmpty(id) || Utils.IsNullOrEmpty(url) || (!Utils.IsNullOrEmpty(subId) && item.id != subId)) { //_updateFunc(false, $"{hashCode}{ResUI.MsgNoValidSubscription}"); continue; } if (item.enabled == false) { _updateFunc(false, $"{hashCode}{ResUI.MsgSkipSubscriptionUpdate}"); continue; } var downloadHandle = new DownloadHandle(); downloadHandle.Error += (sender2, args) => { _updateFunc(false, $"{hashCode}{args.GetException().Message}"); }; _updateFunc(false, $"{hashCode}{ResUI.MsgStartGettingSubscriptions}"); //one url url = Utils.GetPunycode(url); //convert if (!Utils.IsNullOrEmpty(item.convertTarget)) { var subConvertUrl = string.IsNullOrEmpty(config.constItem.subConvertUrl) ? Global.SubConvertUrls.FirstOrDefault() : config.constItem.subConvertUrl; url = string.Format(subConvertUrl!, Utils.UrlEncode(url)); if (!url.Contains("target=")) { url += string.Format("&target={0}", item.convertTarget); } if (!url.Contains("config=")) { url += string.Format("&config={0}", Global.SubConvertConfig.FirstOrDefault()); } } var result = await downloadHandle.TryDownloadString(url, blProxy, userAgent); if (blProxy && Utils.IsNullOrEmpty(result)) { result = await downloadHandle.TryDownloadString(url, false, userAgent); } //more url if (Utils.IsNullOrEmpty(item.convertTarget) && !Utils.IsNullOrEmpty(item.moreUrl.TrimEx())) { if (!Utils.IsNullOrEmpty(result) && Utils.IsBase64String(result)) { result = Utils.Base64Decode(result); } var lstUrl = new List { item.moreUrl.TrimEx().Split(",") }; foreach (var it in lstUrl) { var url2 = Utils.GetPunycode(it); if (Utils.IsNullOrEmpty(url2)) { continue; } var result2 = await downloadHandle.TryDownloadString(url2, blProxy, userAgent); if (blProxy && Utils.IsNullOrEmpty(result2)) { result2 = await downloadHandle.TryDownloadString(url2, false, userAgent); } if (!Utils.IsNullOrEmpty(result2)) { if (Utils.IsBase64String(result2)) { result += Utils.Base64Decode(result2); } else { result += result2; } } } } if (Utils.IsNullOrEmpty(result)) { _updateFunc(false, $"{hashCode}{ResUI.MsgSubscriptionDecodingFailed}"); } else { _updateFunc(false, $"{hashCode}{ResUI.MsgGetSubscriptionSuccessfully}"); if (result!.Length < 99) { _updateFunc(false, $"{hashCode}{result}"); } int ret = ConfigHandler.AddBatchServers(ref config, result, id, true); if (ret <= 0) { Utils.SaveLog("FailedImportSubscription"); Utils.SaveLog(result); } else { ConfigHandler.SortServers(ref _config, id, "", true); anySubUpdated = true; } _updateFunc(false, ret > 0 ? $"{hashCode}{ResUI.MsgUpdateSubscriptionEnd}" : $"{hashCode}{ResUI.MsgFailedImportSubscription}"); } _updateFunc(false, "-------------------------------------------------------"); } if (!anySubUpdated) { _updateFunc(false, $"{ResUI.MsgNothingUpdated}"); } _updateFunc(true, $"{ResUI.MsgUpdateSubscriptionEnd}"); }); } public void UpdateGeoFileAll(Config config, Action update) { Task.Run(async () => { await UpdateGeoFile("geosite", _config, update); await UpdateGeoFile("geoip", _config, update); await UpdateGeoFile4Singbox("geosite", _config, update); await UpdateGeoFile4Singbox("geoip", _config, update); }); } public void RunAvailabilityCheck(Action update) { Task.Run(async () => { var time = await (new DownloadHandle()).RunAvailabilityCheck(null); update(false, string.Format(ResUI.TestMeOutput, time)); }); } #region private private async void CheckUpdateAsync(ECoreType type, bool preRelease) { try { var coreInfo = LazyConfig.Instance.GetCoreInfo(type); string url = coreInfo.coreReleaseApiUrl; var result = await (new DownloadHandle()).DownloadStringAsync(url, true, ""); if (!Utils.IsNullOrEmpty(result)) { responseHandler(type, result, preRelease); } else { Utils.SaveLog("StatusCode error: " + url); return; } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); _updateFunc(false, ex.Message); } } /// /// 获取V2RayCore版本 /// private string getCoreVersion(ECoreType type) { try { var coreInfo = LazyConfig.Instance.GetCoreInfo(type); string filePath = string.Empty; foreach (string name in coreInfo.coreExes) { string vName = $"{name}.exe"; vName = Utils.GetBinPath(vName, coreInfo.coreType); if (File.Exists(vName)) { filePath = vName; break; } } if (!File.Exists(filePath)) { string msg = string.Format(ResUI.NotFoundCore, @"", "", ""); //ShowMsg(true, msg); return ""; } using Process p = new(); p.StartInfo.FileName = filePath; p.StartInfo.Arguments = coreInfo.versionArg; p.StartInfo.WorkingDirectory = Utils.StartupPath(); p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.CreateNoWindow = true; p.StartInfo.StandardOutputEncoding = Encoding.UTF8; p.Start(); p.WaitForExit(5000); string echo = p.StandardOutput.ReadToEnd(); string version = string.Empty; switch (type) { case ECoreType.v2fly: case ECoreType.SagerNet: case ECoreType.Xray: case ECoreType.v2fly_v5: version = Regex.Match(echo, $"{coreInfo.match} ([0-9.]+) \\(").Groups[1].Value; break; case ECoreType.clash: case ECoreType.clash_meta: version = Regex.Match(echo, $"v[0-9.]+").Groups[0].Value; break; case ECoreType.sing_box: version = Regex.Match(echo, $"([0-9.]+)").Groups[1].Value; break; } return version; } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); _updateFunc(false, ex.Message); return ""; } } private void responseHandler(ECoreType type, string gitHubReleaseApi, bool preRelease) { try { var gitHubReleases = Utils.FromJson>(gitHubReleaseApi); string version; if (preRelease) { version = gitHubReleases!.First().TagName; } else { version = gitHubReleases!.First(r => r.Prerelease == false).TagName; } var coreInfo = LazyConfig.Instance.GetCoreInfo(type); string curVersion; string message; string url; switch (type) { case ECoreType.v2fly: case ECoreType.SagerNet: case ECoreType.Xray: case ECoreType.v2fly_v5: { curVersion = "v" + getCoreVersion(type); message = string.Format(ResUI.IsLatestCore, curVersion); string osBit = "64"; switch (RuntimeInformation.ProcessArchitecture) { case Architecture.Arm64: osBit = "arm64-v8a"; break; case Architecture.X86: osBit = "32"; break; default: osBit = "64"; break; } url = string.Format(coreInfo.coreDownloadUrl64, version, osBit); break; } case ECoreType.clash: case ECoreType.clash_meta: { curVersion = getCoreVersion(type); message = string.Format(ResUI.IsLatestCore, curVersion); switch (RuntimeInformation.ProcessArchitecture) { case Architecture.Arm64: url = coreInfo.coreDownloadUrlArm64; break; case Architecture.X86: url = coreInfo.coreDownloadUrl32; break; default: url = coreInfo.coreDownloadUrl64; break; } url = string.Format(url, version); break; } case ECoreType.sing_box: { curVersion = "v" + getCoreVersion(type); message = string.Format(ResUI.IsLatestCore, curVersion); switch (RuntimeInformation.ProcessArchitecture) { case Architecture.Arm64: url = coreInfo.coreDownloadUrlArm64; break; case Architecture.X86: url = coreInfo.coreDownloadUrl32; break; default: url = coreInfo.coreDownloadUrl64; break; } url = string.Format(url, version, version.Replace("v", "")); break; } case ECoreType.v2rayN: { curVersion = FileVersionInfo.GetVersionInfo(Utils.GetExePath()).FileVersion.ToString(); message = string.Format(ResUI.IsLatestN, curVersion); switch (RuntimeInformation.ProcessArchitecture) { case Architecture.Arm64: url = string.Format(coreInfo.coreDownloadUrlArm64, version); break; case Architecture.X86: url = string.Format(coreInfo.coreDownloadUrl32, version); break; default: url = string.Format(coreInfo.coreDownloadUrl64, version); break; } break; } default: throw new ArgumentException("Type"); } if (type == ECoreType.v2rayN) { decimal.TryParse(curVersion, out decimal decCur); decimal.TryParse(version, out decimal dec); if (decCur >= dec) { AbsoluteCompleted?.Invoke(this, new ResultEventArgs(false, message)); return; } } if (curVersion == version) { AbsoluteCompleted?.Invoke(this, new ResultEventArgs(false, message)); return; } AbsoluteCompleted?.Invoke(this, new ResultEventArgs(true, url)); } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); _updateFunc(false, ex.Message); } } private async Task askToDownload(DownloadHandle downloadHandle, string url, bool blAsk) { bool blDownload = false; if (blAsk) { if (UI.ShowYesNo(string.Format(ResUI.DownloadYesNo, url)) == MessageBoxResult.Yes) { blDownload = true; } } else { blDownload = true; } if (blDownload) { await downloadHandle.DownloadFileAsync(url, true, 600); } } private async Task UpdateGeoFile(string geoName, Config config, Action update) { _config = config; _updateFunc = update; var url = string.Format(Global.geoUrl, geoName); DownloadHandle downloadHandle = new(); downloadHandle.UpdateCompleted += (sender2, args) => { if (args.Success) { _updateFunc(false, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, geoName)); try { string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url)); if (File.Exists(fileName)) { //Global.coreTypes.ForEach(it => //{ // string targetPath = Utils.GetBinPath($"{geoName}.dat", (ECoreType)Enum.Parse(typeof(ECoreType), it)); // File.Copy(fileName, targetPath, true); //}); string targetPath = Utils.GetBinPath($"{geoName}.dat"); File.Copy(fileName, targetPath, true); File.Delete(fileName); //_updateFunc(true, ""); } } catch (Exception ex) { _updateFunc(false, ex.Message); } } else { _updateFunc(false, args.Msg); } }; downloadHandle.Error += (sender2, args) => { _updateFunc(false, args.GetException().Message); }; await askToDownload(downloadHandle, url, false); } private async Task UpdateGeoFile4Singbox(string geoName, Config config, Action update) { _config = config; _updateFunc = update; var url = string.Format(Global.singboxGeoUrl, geoName); DownloadHandle downloadHandle = new(); downloadHandle.UpdateCompleted += (sender2, args) => { if (args.Success) { _updateFunc(false, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, geoName)); try { string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url)); if (File.Exists(fileName)) { string targetPath = Utils.GetConfigPath($"{geoName}.db"); File.Copy(fileName, targetPath, true); File.Delete(fileName); } } catch (Exception ex) { _updateFunc(false, ex.Message); } } else { _updateFunc(false, args.Msg); } }; downloadHandle.Error += (sender2, args) => { _updateFunc(false, args.GetException().Message); }; await askToDownload(downloadHandle, url, false); } #endregion private } } ================================================ FILE: v2rayN/v2rayN/Mode/BalancerItem.cs ================================================ namespace v2rayN.Mode { [Serializable] public class BalancerItem { public string tag { get; set; } public string[] selector { get; set; } public BalancerStrategyItem strategy { get; set; } public BalancerStrategySettings optimalSettings { get; set; } } [Serializable] public class BalancerStrategyItem { public string type { get; set; } public BalancerStrategySettings settings { get; set; } } public interface BalancerStrategySettings{} [Serializable] public class OptimalBalancerStrategySetting: BalancerStrategySettings { public int timeout { get; set; } = 10000; public int interval { get; set; } = 30000; public string url { get; set; } = "https://about.google"; public int count { get; set; } = 3; public bool accept_little_diff { get; set; } = true; public bool load_balancing { get; set; } = false; public double diff_percent { get; set; } = 0.5; } } ================================================ FILE: v2rayN/v2rayN/Mode/ComboItem.cs ================================================ namespace v2rayN.Mode { public class ComboItem { public string ID { get; set; } public string Text { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/Config.cs ================================================ namespace v2rayN.Mode { /// /// 本软件配置文件实体类 /// [Serializable] public class Config { #region property public string indexId { get; set; } public string subIndexId { get; set; } public ESysProxyType sysProxyType { get; set; } public string systemProxyExceptions { get; set; } public string systemProxyAdvancedProtocol { get; set; } #endregion property #region other entities public CoreBasicItem coreBasicItem { get; set; } public TunModeItem tunModeItem { get; set; } public KcpItem kcpItem { get; set; } public GrpcItem grpcItem { get; set; } public RoutingBasicItem routingBasicItem { get; set; } public GUIItem guiItem { get; set; } public UIItem uiItem { get; set; } public ConstItem constItem { get; set; } public SpeedTestItem speedTestItem { get; set; } public List inbound { get; set; } public List globalHotkeys { get; set; } public List coreTypeItem { get; set; } #endregion other entities } } ================================================ FILE: v2rayN/v2rayN/Mode/ConfigItems.cs ================================================ using System.Windows.Input; namespace v2rayN.Mode { [Serializable] public class CoreBasicItem { /// /// 允许日志 /// public bool logEnabled { get; set; } /// /// 日志等级 /// public string loglevel { get; set; } /// /// 允许Mux多路复用 /// public bool muxEnabled { get; set; } /// /// 是否允许不安全连接 /// public bool defAllowInsecure { get; set; } public string defFingerprint { get; set; } /// /// 默认用户代理 /// public string defUserAgent { get; set; } } [Serializable] public class InItem { public int localPort { get; set; } public string protocol { get; set; } public bool udpEnabled { get; set; } public bool sniffingEnabled { get; set; } = true; public bool routeOnly { get; set; } public bool allowLANConn { get; set; } public bool newPort4LAN { get; set; } public string user { get; set; } public string pass { get; set; } } [Serializable] public class KcpItem { public int mtu { get; set; } public int tti { get; set; } public int uplinkCapacity { get; set; } public int downlinkCapacity { get; set; } public bool congestion { get; set; } public int readBufferSize { get; set; } public int writeBufferSize { get; set; } } [Serializable] public class GrpcItem { public int idle_timeout { get; set; } public int health_check_timeout { get; set; } public bool permit_without_stream { get; set; } public int initial_windows_size { get; set; } } [Serializable] public class GUIItem { public bool autoRun { get; set; } public bool enableStatistics { get; set; } public int statisticsFreshRate { get; set; } public bool keepOlderDedupl { get; set; } public bool ignoreGeoUpdateCore { get; set; } = true; public int autoUpdateInterval { get; set; } = 10; public bool checkPreReleaseUpdate { get; set; } = false; public bool enableSecurityProtocolTls13 { get; set; } = true; public int trayMenuServersLimit { get; set; } = 20; public bool enableHWA { get; set; } = false; public bool enableLog { get; set; } = true; } [Serializable] public class UIItem { public bool enableAutoAdjustMainLvColWidth { get; set; } public double mainWidth { get; set; } public double mainHeight { get; set; } public double mainGirdHeight1 { get; set; } public double mainGirdHeight2 { get; set; } public bool colorModeDark { get; set; } = true; public string? colorPrimaryName { get; set; } public string currentLanguage { get; set; } public string currentFontFamily { get; set; } public int currentFontSize { get; set; } = 14; public bool enableDragDropSort { get; set; } public bool doubleClick2Activate { get; set; } public bool autoHideStartup { get; set; } = false; public string mainMsgFilter { get; set; } public bool showTrayTip { get; set; } public List mainColumnItem { get; set; } } [Serializable] public class ConstItem { public string defIEProxyExceptions { get; set; } public string subConvertUrl { get; set; } = string.Empty; } [Serializable] public class KeyEventItem { public EGlobalHotkey eGlobalHotkey { get; set; } public bool Alt { get; set; } public bool Control { get; set; } public bool Shift { get; set; } public Key? KeyCode { get; set; } } [Serializable] public class CoreTypeItem { public EConfigType configType { get; set; } public ECoreType coreType { get; set; } } [Serializable] public class TunModeItem { public bool enableTun { get; set; } public bool showWindow { get; set; } public bool enabledLog { get; set; } public bool strictRoute { get; set; } public string stack { get; set; } public int mtu { get; set; } public string customTemplate { get; set; } public bool bypassMode { get; set; } = true; public List directIP { get; set; } public List directProcess { get; set; } public string directDNS { get; set; } public List proxyIP { get; set; } public List proxyProcess { get; set; } public string proxyDNS { get; set; } } [Serializable] public class SpeedTestItem { public int speedTestTimeout { get; set; } public string speedTestUrl { get; set; } public string speedPingTestUrl { get; set; } } [Serializable] public class RoutingBasicItem { /// /// 域名解析策略 /// public string domainStrategy { get; set; } public string domainStrategy4Singbox { get; set; } public string domainMatcher { get; set; } public string routingIndexId { get; set; } public bool enableRoutingAdvanced { get; set; } } [Serializable] public class ColumnItem { public string Name { get; set; } public int Width { get; set; } public int Index { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/ConfigOld.cs ================================================ namespace v2rayN.Mode { [Serializable] public class ConfigOld { #region property /// /// 允许日志 /// public bool logEnabled { get; set; } /// /// 日志等级 /// public string loglevel { get; set; } public string indexId { get; set; } /// /// 允许Mux多路复用 /// public bool muxEnabled { get; set; } /// /// /// public ESysProxyType sysProxyType { get; set; } /// /// 启用实时网速和流量统计 /// public bool enableStatistics { get; set; } /// /// 去重时优先保留较旧(顶部)节点 /// public bool keepOlderDedupl { get; set; } /// /// 视图刷新率 /// public int statisticsFreshRate { get; set; } /// /// 自定义远程DNS /// public string remoteDNS { get; set; } /// /// Outbound Freedom domainStrategy /// public string domainStrategy4Freedom { get; set; } /// /// 是否允许不安全连接 /// public bool defAllowInsecure { get; set; } /// /// 域名解析策略 /// public string domainStrategy { get; set; } public string domainMatcher { get; set; } public int routingIndex { get; set; } public bool enableRoutingAdvanced { get; set; } public bool ignoreGeoUpdateCore { get; set; } /// /// systemProxyExceptions /// public string systemProxyExceptions { get; set; } public string systemProxyAdvancedProtocol { get; set; } public int autoUpdateInterval { get; set; } = 0; public int autoUpdateSubInterval { get; set; } = 0; public bool checkPreReleaseUpdate { get; set; } = false; public bool enableSecurityProtocolTls13 { get; set; } = true; public int trayMenuServersLimit { get; set; } #endregion property #region other entities /// /// 本地监听 /// public List inbound { get; set; } /// /// vmess服务器信息 /// public List vmess { get; set; } /// /// KcpItem /// public KcpItem kcpItem { get; set; } /// /// 订阅 /// public List subItem { get; set; } /// /// UI /// public UIItem uiItem { get; set; } public List routings { get; set; } public ConstItem constItem { get; set; } public List globalHotkeys { get; set; } public List coreTypeItem { get; set; } #endregion other entities } [Serializable] public class VmessItem { public VmessItem() { indexId = string.Empty; configType = EConfigType.VMess; configVersion = 2; sort = 0; address = string.Empty; port = 0; id = string.Empty; alterId = 0; security = string.Empty; network = string.Empty; remarks = string.Empty; headerType = string.Empty; requestHost = string.Empty; path = string.Empty; streamSecurity = string.Empty; allowInsecure = string.Empty; testResult = string.Empty; subid = string.Empty; flow = string.Empty; groupId = string.Empty; } public string indexId { get; set; } /// /// config type(1=normal,2=custom) /// public EConfigType configType { get; set; } /// /// 版本(现在=2) /// public int configVersion { get; set; } public int sort { get; set; } /// /// 远程服务器地址 /// public string address { get; set; } /// /// 远程服务器端口 /// public int port { get; set; } /// /// 远程服务器ID /// public string id { get; set; } /// /// 远程服务器额外ID /// public int alterId { get; set; } /// /// 本地安全策略 /// public string security { get; set; } /// /// tcp,kcp,ws,h2,quic /// public string network { get; set; } /// /// /// public string remarks { get; set; } /// /// 伪装类型 /// public string headerType { get; set; } /// /// 伪装的域名 /// public string requestHost { get; set; } /// /// ws h2 path /// public string path { get; set; } /// /// 传输层安全 /// public string streamSecurity { get; set; } /// /// 是否允许不安全连接(用于客户端) /// public string allowInsecure { get; set; } /// /// /// public string testResult { get; set; } /// /// SubItem id /// public string subid { get; set; } /// /// VLESS flow /// public string flow { get; set; } /// /// tls sni /// public string sni { get; set; } public string groupId { get; set; } = string.Empty; public ECoreType? coreType { get; set; } public int preSocksPort { get; set; } public string fingerprint { get; set; } } [Serializable] public class RoutingItemOld { public string remarks { get; set; } public string url { get; set; } public List rules { get; set; } public bool enabled { get; set; } = true; public bool locked { get; set; } public string customIcon { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/CoreInfo.cs ================================================ namespace v2rayN.Mode { [Serializable] public class CoreInfo { public ECoreType coreType { get; set; } public List coreExes { get; set; } public string arguments { get; set; } public string coreUrl { get; set; } public string coreReleaseApiUrl { get; set; } public string coreDownloadUrl32 { get; set; } public string coreDownloadUrl64 { get; set; } public string coreDownloadUrlArm64 { get; set; } public string match { get; set; } public string versionArg { get; set; } public bool redirectInfo { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/DNSItem.cs ================================================ using SQLite; namespace v2rayN.Mode { [Serializable] public class DNSItem { [PrimaryKey] public string id { get; set; } public string remarks { get; set; } public bool enabled { get; set; } = true; public ECoreType coreType { get; set; } public string? normalDNS { get; set; } public string? directDNS { get; set; } public string? proxyDNS { get; set; } public string? domainStrategy4Freedom { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/EConfigType.cs ================================================ namespace v2rayN.Mode { public enum EConfigType { VMess = 1, Custom = 2, Shadowsocks = 3, Socks = 4, VLESS = 5, Trojan = 6, LowestPing = 101, LoadBalance=102, Usage = 103, } } ================================================ FILE: v2rayN/v2rayN/Mode/ECoreType.cs ================================================ namespace v2rayN.Mode { public enum ECoreType { v2fly = 1, Xray = 2, SagerNet = 3, v2fly_v5 = 4, clash = 11, clash_meta = 12, hysteria = 21, naiveproxy = 22, tuic = 23, sing_box = 24, v2rayN = 99 } } ================================================ FILE: v2rayN/v2rayN/Mode/EGlobalHotkey.cs ================================================ namespace v2rayN.Mode { public enum EGlobalHotkey { ShowForm = 0, SystemProxyClear = 1, SystemProxySet = 2, SystemProxyUnchanged = 3, SystemProxyPac = 4, } } ================================================ FILE: v2rayN/v2rayN/Mode/EMove.cs ================================================ namespace v2rayN.Mode { public enum EMove { Top = 1, Up = 2, Down = 3, Bottom = 4, Position = 5 } } ================================================ FILE: v2rayN/v2rayN/Mode/EServerColName.cs ================================================ namespace v2rayN.Mode { public enum EServerColName { def = 0, configType, remarks, address, port, security, network, streamSecurity, subRemarks, delayVal, speedVal, todayDown, todayUp, totalDown, totalUp } } ================================================ FILE: v2rayN/v2rayN/Mode/ESpeedActionType.cs ================================================ namespace v2rayN.Mode { public enum ESpeedActionType { Ping, Tcping, Realping, Speedtest, Mixedtest } } ================================================ FILE: v2rayN/v2rayN/Mode/ESysProxyType.cs ================================================ namespace v2rayN.Mode { public enum ESysProxyType { ForcedClear = 0, ForcedChange = 1, Unchanged = 2, Pac = 3 } } ================================================ FILE: v2rayN/v2rayN/Mode/EViewAction.cs ================================================ namespace v2rayN.Mode { public enum EViewAction { AdjustMainLvColWidth, ProfilesFocus } } ================================================ FILE: v2rayN/v2rayN/Mode/GitHubRelease.cs ================================================ using Newtonsoft.Json; namespace v2rayN.Mode { public class GitHubReleaseAsset { [JsonProperty("url")] public string Url { get; set; } [JsonProperty("id")] public int Id { get; set; } [JsonProperty("node_id")] public string NodeId { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("label")] public object Label { get; set; } [JsonProperty("content_type")] public string ContentType { get; set; } [JsonProperty("state")] public string State { get; set; } [JsonProperty("size")] public int Size { get; set; } [JsonProperty("download_count")] public int DownloadCount { get; set; } [JsonProperty("created_at")] public DateTime CreatedAt { get; set; } [JsonProperty("updated_at")] public DateTime UpdatedAt { get; set; } [JsonProperty("browser_download_url")] public string BrowserDownloadUrl { get; set; } } public class GitHubRelease { [JsonProperty("url")] public string Url { get; set; } [JsonProperty("assets_url")] public string AssetsUrl { get; set; } [JsonProperty("upload_url")] public string UploadUrl { get; set; } [JsonProperty("html_url")] public string HtmlUrl { get; set; } [JsonProperty("id")] public int Id { get; set; } [JsonProperty("node_id")] public string NodeId { get; set; } [JsonProperty("tag_name")] public string TagName { get; set; } [JsonProperty("target_commitish")] public string TargetCommitish { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("draft")] public bool Draft { get; set; } [JsonProperty("prerelease")] public bool Prerelease { get; set; } [JsonProperty("created_at")] public DateTime CreatedAt { get; set; } [JsonProperty("published_at")] public DateTime PublishedAt { get; set; } [JsonProperty("assets")] public List Assets { get; set; } [JsonProperty("tarball_url")] public string TarballUrl { get; set; } [JsonProperty("zipball_url")] public string ZipballUrl { get; set; } [JsonProperty("body")] public string Body { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/HiddifyEnums.cs ================================================ using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using v2rayN.Resx; using System.Resources; using v2rayN.Mode; namespace v2rayN.Mode { internal class HiddifyEnums { } public enum RoutingEnum { All, Blocked, BypassNotblocked } public enum ProxyModeEnum : int { [LocalizedDescription("HomeProxyAuto", typeof(ResUI))] Smart, [LocalizedDescription("HomeProxyLoadBalance", typeof(ResUI))] Loadbalance, [LocalizedDescription("HomeProxyManual", typeof(ResUI))] Manual } } public class LocalizedDescriptionAttribute : DescriptionAttribute { private readonly string _resourceName; private readonly Type _resourceType; public LocalizedDescriptionAttribute(string resourceName, Type resourceType) { _resourceName = resourceName; _resourceType = resourceType; } public override string Description { get { ResourceManager rm = new ResourceManager(_resourceType); return rm.GetString(_resourceName); } } } public static class ProxyModeEnumExtensions { public static string ToLocalizedDescriptionString(this ProxyModeEnum value) { var fieldInfo = value.GetType().GetField(value.ToString()); var attributes = fieldInfo.GetCustomAttributes(typeof(LocalizedDescriptionAttribute), false) as LocalizedDescriptionAttribute[]; return attributes?.Length > 0 ? attributes[0].Description : value.ToString(); } } ================================================ FILE: v2rayN/v2rayN/Mode/ProfileExItem.cs ================================================ using SQLite; namespace v2rayN.Mode { [Serializable] public class ProfileExItem { [PrimaryKey] public string indexId { get; set; } public int delay { get; set; } public decimal speed { get; set; } public int sort { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/ProfileItem.cs ================================================ using SQLite; using v2rayN.Base; namespace v2rayN.Mode { [Serializable] public class ProfileItem { public ProfileItem() { indexId = string.Empty; configType = EConfigType.VMess; configVersion = 2; address = string.Empty; port = 0; id = string.Empty; alterId = 0; security = string.Empty; network = string.Empty; remarks = string.Empty; headerType = string.Empty; requestHost = string.Empty; path = string.Empty; streamSecurity = string.Empty; allowInsecure = string.Empty; subid = string.Empty; flow = string.Empty; } #region function public string GetSummary() { string summary = string.Format("[{0}] ", (configType).ToString()); string[] arrAddr = address.Split('.'); string addr; if (arrAddr.Length > 2) { addr = $"{arrAddr[0]}***{arrAddr[arrAddr.Length - 1]}"; } else if (arrAddr.Length > 1) { addr = $"***{arrAddr[arrAddr.Length - 1]}"; } else { addr = address; } switch (configType) { case EConfigType.VMess: case EConfigType.Shadowsocks: case EConfigType.Socks: case EConfigType.VLESS: case EConfigType.Trojan: summary += string.Format("{0}({1}:{2})", remarks, addr, port); break; default: summary += string.Format("{0}", remarks); break; } return summary; } public List GetAlpn() { if (Utils.IsNullOrEmpty(alpn)) { return null; } else { return Utils.String2List(alpn); } } public string GetNetwork() { if (Utils.IsNullOrEmpty(network) || !Global.networks.Contains(network)) { return Global.DefaultNetwork; } return network.TrimEx(); } #endregion function [PrimaryKey] public string indexId { get; set; } /// /// config type(1=normal,2=custom) /// public EConfigType configType { get; set; } /// /// 版本(现在=2) /// public int configVersion { get; set; } /// /// 远程服务器地址 /// public string address { get; set; } /// /// 远程服务器端口 /// public int port { get; set; } /// /// 远程服务器ID /// public string id { get; set; } /// /// 远程服务器额外ID /// public int alterId { get; set; } /// /// 本地安全策略 /// public string security { get; set; } /// /// tcp,kcp,ws,h2,quic /// public string network { get; set; } /// /// /// public string remarks { get; set; } /// /// 伪装类型 /// public string headerType { get; set; } /// /// 伪装的域名 /// public string requestHost { get; set; } /// /// ws h2 path /// public string path { get; set; } public string fragment { get; set; }//hiddify /// /// 传输层安全 /// public string streamSecurity { get; set; } /// /// 是否允许不安全连接(用于客户端) /// public string allowInsecure { get; set; } /// /// SubItem id /// public string subid { get; set; } public bool isSub { get; set; } = true; /// /// VLESS flow /// public string flow { get; set; } /// /// tls sni /// public string sni { get; set; } /// /// tls alpn /// public string alpn { get; set; } = string.Empty; public ECoreType? coreType { get; set; } public int preSocksPort { get; set; } public string fingerprint { get; set; } public bool displayLog { get; set; } = true; public string publicKey { get; set; } public string shortId { get; set; } public string spiderX { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/ProfileItemModel.cs ================================================ namespace v2rayN.Mode { [Serializable] public class ProfileItemModel : ProfileItem { public bool isActive { get; set; } public string subRemarks { get; set; } public int delay { get; set; } public decimal speed { get; set; } public int sort { get; set; } public string delayVal { get; set; } public string speedVal { get; set; } public string todayUp { get; set; } public string todayDown { get; set; } public string totalUp { get; set; } public string totalDown { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/ProxyMode.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace v2rayN.Mode { public class ProxyMode { public int id { get; set; } public string remark { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/RoutingItem.cs ================================================ using SQLite; namespace v2rayN.Mode { [Serializable] public class RoutingItem { [PrimaryKey] public string id { get; set; } public string remarks { get; set; } public string url { get; set; } public string ruleSet { get; set; } public int ruleNum { get; set; } public bool enabled { get; set; } = true; public bool locked { get; set; } public string customIcon { get; set; } public string domainStrategy { get; set; } public string domainStrategy4Singbox { get; set; } public int sort { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/RoutingItemModel.cs ================================================ namespace v2rayN.Mode { [Serializable] public class RoutingItemModel : RoutingItem { public bool isActive { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/RulesItem.cs ================================================ namespace v2rayN.Mode { [Serializable] public class RulesItem { public string id { get; set; } public string type { get; set; } public string port { get; set; } public List inboundTag { get; set; } public string outboundTag { get; set; } public string balancerTag { get; set; } public List ip { get; set; } public List domain { get; set; } public List protocol { get; set; } public bool enabled { get; set; } = true; } } ================================================ FILE: v2rayN/v2rayN/Mode/RulesItemModel.cs ================================================ namespace v2rayN.Mode { [Serializable] public class RulesItemModel : RulesItem { public string inboundTags { get; set; } public string ips { get; set; } public string domains { get; set; } public string protocols { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/ServerSpeedItem.cs ================================================ namespace v2rayN.Mode { [Serializable] internal class ServerSpeedItem : ServerStatItem { public long proxyUp { get; set; } public long proxyDown { get; set; } public long directUp { get; set; } public long directDown { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/ServerStatItem.cs ================================================ using SQLite; namespace v2rayN.Mode { [Serializable] public class ServerStatItem { [PrimaryKey] public string indexId { get; set; } public long totalUp { get; set; } public long totalDown { get; set; } public long todayUp { get; set; } public long todayDown { get; set; } public long dateNow { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/ServerTestItem.cs ================================================ namespace v2rayN.Mode { [Serializable] internal class ServerTestItem { public string indexId { get; set; } public string address { get; set; } public int port { get; set; } public EConfigType configType { get; set; } public bool allowTest { get; set; } public int delay { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/SingboxConfig.cs ================================================ namespace v2rayN.Mode { public class SingboxConfig { public Log4Sbox log { get; set; } public object dns { get; set; } public List inbounds { get; set; } public List outbounds { get; set; } public Route4Sbox route { get; set; } public Experimental4Sbox experimental { get; set; } } public class Log4Sbox { public bool? disabled { get; set; } public string level { get; set; } public string output { get; set; } public bool timestamp { get; set; } } public class Dns4Sbox { public List servers { get; set; } public List rules { get; set; } } public class Route4Sbox { public bool? auto_detect_interface { get; set; } public List rules { get; set; } } [Serializable] public class Rule4Sbox { public string outbound { get; set; } public string server { get; set; } public bool? disable_cache { get; set; } public List? inbound { get; set; } public List? protocol { get; set; } public string type { get; set; } public string mode { get; set; } public string network { get; set; } public List? port { get; set; } public List? port_range { get; set; } public List? geosite { get; set; } public List? domain { get; set; } public List? domain_suffix { get; set; } public List? domain_keyword { get; set; } public List? domain_regex { get; set; } public List? geoip { get; set; } public List? ip_cidr { get; set; } public List? source_ip_cidr { get; set; } public List? process_name { get; set; } } [Serializable] public class Inbound4Sbox { public string type { get; set; } public string tag { get; set; } public string listen { get; set; } public int? listen_port { get; set; } public string? domain_strategy { get; set; } public string interface_name { get; set; } public string inet4_address { get; set; } public string inet6_address { get; set; } public int? mtu { get; set; } public bool? auto_route { get; set; } public bool? strict_route { get; set; } public bool? endpoint_independent_nat { get; set; } public string? stack { get; set; } public bool? sniff { get; set; } public bool? sniff_override_destination { get; set; } public List users { get; set; } } public class User4Sbox { public string username { get; set; } public string password { get; set; } } public class Outbound4Sbox { public string type { get; set; } public string tag { get; set; } public string server { get; set; } public int? server_port { get; set; } public string uuid { get; set; } public string security { get; set; } public int? alter_id { get; set; } public string flow { get; set; } public int? up_mbps { get; set; } public int? down_mbps { get; set; } public string auth_str { get; set; } public int? recv_window_conn { get; set; } public int? recv_window { get; set; } public bool? disable_mtu_discovery { get; set; } public string detour { get; set; } public string method { get; set; } public string username { get; set; } public string password { get; set; } public string? version { get; set; } public string? network { get; set; } public string packet_encoding { get; set; } public Tls4Sbox tls { get; set; } public Multiplex4Sbox multiplex { get; set; } public Transport4Sbox transport { get; set; } } public class Tls4Sbox { public bool enabled { get; set; } public string server_name { get; set; } public bool? insecure { get; set; } public List alpn { get; set; } public Utls4Sbox utls { get; set; } public Reality4Sbox reality { get; set; } } public class Multiplex4Sbox { public bool enabled { get; set; } public string protocol { get; set; } public int max_connections { get; set; } public int min_streams { get; set; } public int max_streams { get; set; } } public class Utls4Sbox { public bool enabled { get; set; } public string fingerprint { get; set; } } public class Reality4Sbox { public bool enabled { get; set; } public string public_key { get; set; } public string short_id { get; set; } } public class Transport4Sbox { public string type { get; set; } public List? host { get; set; } public string? path { get; set; } public string service_name { get; set; } public string idle_timeout { get; set; } public string ping_timeout { get; set; } public bool? permit_without_stream { get; set; } } public class Server4Sbox { public string tag { get; set; } public string address { get; set; } public string address_resolver { get; set; } public string strategy { get; set; } public string detour { get; set; } } public class Experimental4Sbox { public V2ray_Api4Sbox v2ray_api { get; set; } } public class V2ray_Api4Sbox { public string listen { get; set; } public Stats4Sbox stats { get; set; } } public class Stats4Sbox { public bool enabled { get; set; } public List? inbounds { get; set; } public List? outbounds { get; set; } public List? users { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/SsSIP008.cs ================================================ namespace v2rayN.Mode { public class SsSIP008 { public List servers { get; set; } } [Serializable] public class SsServer { public string remarks { get; set; } public string server { get; set; } public string server_port { get; set; } public string method { get; set; } public string password { get; set; } public string plugin { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/SubItem.cs ================================================  using SQLite; using System.Windows; namespace v2rayN.Mode { [Serializable] public class SubItem { [PrimaryKey] public string id { get; set; } public string remarks { get; set; } public string url { get; set; } public string moreUrl { get; set; } public bool enabled { get; set; } = true; public string userAgent { get; set; } = string.Empty; public int sort { get; set; } public string? filter { get; set; } public long upload { get; set; } public long download { get; set; } public long total { get; set; } public long usage { get { return (download + upload); } set { } } public long expireDate { get; set; } public int remaningExpireDays { get; set; } public int UsedDataGB { get; set; } public int TotalDataGB { get; set; } public string? profileWebPageUrl { get; set; } public int profileUpdateInterval { get; set; } public long updateTime { get; set; } public string? convertTarget { get; set; } public Visibility sub_info_visible { get { return TotalDataGB>0?Visibility.Visible:Visibility.Collapsed;} } //public Visibility sub_info_visible { get { return Visibility.Collapsed; } } public double UploadMegaBytes() { return GetJustThreeDigitOfaNumber(this.upload/1024/1024); } public double DownloadMegaBytes() { return GetJustThreeDigitOfaNumber(this.download/1024 / 1024); } public double TotalMegaBytes() { return GetJustThreeDigitOfaNumber(this.total/1024 / 1024); } public double UploadGigaBytes() { return GetJustThreeDigitOfaNumber(this.upload / 1024 / 1024/1024); } public double DownloadGigaBytes() { return GetJustThreeDigitOfaNumber(this.download / 1024 / 1024 / 1024); } public int TotalDataGigaBytes() { return (int)((this.total / 1024 / 1024 / 1024)); } public int UsedDataGigaBytes() { return (int)(this.download + this.upload) / 1024 / 1024 / 1024; } public double DownloadAndUploadTotalGigaBytes() { return GetJustThreeDigitOfaNumber((this.download + this.upload) / 1024 / 1024 / 1024); } public DateTime ExpireToDate() { return Utils.EpochToDate(this.expireDate); } public int DaysLeftToExpire() { return this.ExpireToDate().Subtract(DateTime.Now).Days; } private double GetJustThreeDigitOfaNumber(double num) { string strNum = ""; int counter = 0; foreach (var n in num.ToString().ToCharArray()) { if (counter == 3) { break; } strNum += n; counter++; } return double.Parse(strNum); } } } ================================================ FILE: v2rayN/v2rayN/Mode/SubscriptionInfo.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace v2rayN.Mode { public class SubscriptionInfo { public long Upload { get; set; } public long Download { get; set; } public long Total { get; set; } public long ExpireDate { get; set; } public string? ProfileWebPageUrl { get; set; } public string? ProfileTitle { get; set; } public int ProfileUpdateInterval { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/SysproxyConfig.cs ================================================ namespace v2rayN.Mode { internal class SysproxyConfig { public bool UserSettingsRecorded; public string Flags; public string ProxyServer; public string BypassList; public string PacUrl; public SysproxyConfig() { UserSettingsRecorded = false; Flags = "1"; ProxyServer = ""; BypassList = ""; PacUrl = ""; } } } ================================================ FILE: v2rayN/v2rayN/Mode/V2rayConfig.cs ================================================ using Newtonsoft.Json; using System.Windows.Documents; namespace v2rayN.Mode { /// /// v2ray配置文件实体类 /// 例子SampleConfig.txt /// public class V2rayConfig { /// /// 日志配置 /// public Log log { get; set; } /// /// 传入连接配置 /// public List inbounds { get; set; } /// /// 传出连接配置 /// public List outbounds { get; set; } /// /// 统计需要, 空对象 /// public Stats stats { get; set; } /// public API api { get; set; } /// public Policy policy; /// /// DNS 配置 /// public object dns { get; set; } /// /// 路由配置 /// public Routing routing { get; set; } public Observatory observatory { get; set; } } public class Observatory { public String[] subjectSelector { get; set; } public String probeURL { get; set; } public String probeInterval { get; set; } }; public class Stats { }; public class API { public string tag { get; set; } public List services { get; set; } } public class Policy { public SystemPolicy system; } public class SystemPolicy { public bool statsOutboundUplink; public bool statsOutboundDownlink; } public class Log { /// /// /// public string access { get; set; } /// /// /// public string error { get; set; } /// /// /// public string loglevel { get; set; } } public class Inbounds { public string tag { get; set; } /// /// /// public int port { get; set; } /// /// /// public string listen { get; set; } /// /// /// public string protocol { get; set; } /// /// /// public Sniffing sniffing { get; set; } /// /// /// public Inboundsettings settings { get; set; } /// /// /// public StreamSettings streamSettings { get; set; } } public class Inboundsettings { /// /// /// public string auth { get; set; } /// /// /// public bool udp { get; set; } /// /// /// public string ip { get; set; } /// /// api 使用 /// public string address { get; set; } /// /// /// public List clients { get; set; } /// /// VLESS /// public string decryption { get; set; } public bool allowTransparent { get; set; } public List accounts { get; set; } } public class UsersItem { /// /// /// public string id { get; set; } /// /// /// public int alterId { get; set; } /// /// /// public string email { get; set; } /// /// /// public string security { get; set; } /// /// VLESS /// public string encryption { get; set; } /// /// VLESS /// public string flow { get; set; } } public class Sniffing { public bool enabled { get; set; } public List destOverride { get; set; } public bool routeOnly { get; set; } } public class Outbounds { /// /// 默认值agentout /// public string tag { get; set; } /// /// /// public string protocol { get; set; } /// /// /// public Outboundsettings settings { get; set; } /// /// /// public StreamSettings streamSettings { get; set; } /// /// /// public Mux mux { get; set; } } public class Outboundsettings { /// /// /// public List vnext { get; set; } /// /// /// public List servers { get; set; } /// /// /// public Response response { get; set; } /// /// /// public string domainStrategy { get; set; } /// /// /// public int? userLevel { get; set; } } public class VnextItem { /// /// /// public string address { get; set; } /// /// /// public int port { get; set; } /// /// /// public List users { get; set; } } public class ServersItem { /// /// /// public string email { get; set; } /// /// /// public string address { get; set; } /// /// /// public string method { get; set; } /// /// /// public bool ota { get; set; } /// /// /// public string password { get; set; } /// /// /// public int port { get; set; } /// /// /// public int level { get; set; } /// /// trojan /// public string flow { get; set; } /// /// /// public List users { get; set; } } public class SocksUsersItem { /// /// /// public string user { get; set; } /// /// /// public string pass { get; set; } /// /// /// public int level { get; set; } } public class Mux { /// /// /// public bool enabled { get; set; } /// /// /// public int concurrency { get; set; } } public class Response { /// /// /// public string type { get; set; } } public class Dns { /// /// /// public List servers { get; set; } } public class Routing { /// /// /// public string domainStrategy { get; set; } /// /// /// public string domainMatcher { get; set; } /// /// /// public List rules { get; set; } /// /// /// public List balancers { get; set; }=new List(); } public class StreamSettings { /// /// /// public string network { get; set; } /// /// /// public string security { get; set; } /// /// /// public TlsSettings tlsSettings { get; set; } /// /// Tcp传输额外设置 /// public TcpSettings tcpSettings { get; set; } /// /// Kcp传输额外设置 /// public KcpSettings kcpSettings { get; set; } /// /// ws传输额外设置 /// public WsSettings wsSettings { get; set; } /// /// h2传输额外设置 /// public HttpSettings httpSettings { get; set; } /// /// QUIC /// public QuicSettings quicSettings { get; set; } /// /// VLESS only /// public TlsSettings realitySettings { get; set; } /// /// grpc /// public GrpcSettings grpcSettings { get; set; } } public class TlsSettings { /// /// 是否允许不安全连接(用于客户端) /// public bool? allowInsecure { get; set; } /// /// /// public string? serverName { get; set; } /// /// /// public List? alpn { get; set; } public string? fingerprint { get; set; } public bool? show { get; set; } = false; public string? publicKey { get; set; } public string? shortId { get; set; } public string? spiderX { get; set; } public string? minVersion { get; set; }//hiddify } public class TcpSettings { /// /// 数据包头部伪装设置 /// public Header header { get; set; } } public class Header { /// /// 伪装 /// public string type { get; set; } /// /// 结构复杂,直接存起来 /// public object request { get; set; } /// /// 结构复杂,直接存起来 /// public object response { get; set; } } public class KcpSettings { /// /// /// public int mtu { get; set; } /// /// /// public int tti { get; set; } /// /// /// public int uplinkCapacity { get; set; } /// /// /// public int downlinkCapacity { get; set; } /// /// /// public bool congestion { get; set; } /// /// /// public int readBufferSize { get; set; } /// /// /// public int writeBufferSize { get; set; } /// /// /// public Header header { get; set; } /// /// /// public string seed { get; set; } } public class WsSettings { /// /// /// public string path { get; set; } /// /// /// public Headers headers { get; set; } public FragmentationConfig fragmentation { get; set; } } public class FragmentationConfig { public bool enabled { get; set; }=false; public long fragmentationIntervalTimeout { get; set; } = 100; public string strategy { get; set; } = "random"; public int maxChunkSize { get; set; } = 100; public string sni { get; set; } = ""; } public class Headers { /// /// /// public string Host { get; set; } /// /// 用户代理 /// [JsonProperty("User-Agent")] public string UserAgent { get; set; } } public class HttpSettings { /// /// /// public string path { get; set; } /// /// /// public List host { get; set; } } public class QuicSettings { /// /// /// public string security { get; set; } /// /// /// public string key { get; set; } /// /// /// public Header header { get; set; } } public class GrpcSettings { public string serviceName { get; set; } public bool multiMode { get; set; } public int idle_timeout { get; set; } public int health_check_timeout { get; set; } public bool permit_without_stream { get; set; } public int initial_windows_size { get; set; } } public class AccountsItem { /// /// /// public string user { get; set; } /// /// /// public string pass { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/V2rayTcpRequest.cs ================================================ namespace v2rayN.Mode { /// /// Tcp伪装http的Request,只要Host /// public class V2rayTcpRequest { /// /// /// public RequestHeaders headers { get; set; } } public class RequestHeaders { /// /// /// public List Host { get; set; } } } ================================================ FILE: v2rayN/v2rayN/Mode/VmessQRCode.cs ================================================ namespace v2rayN.Mode { /// /// https://github.com/2dust/v2rayN/wiki/ /// [Serializable] internal class VmessQRCode { /// /// /// public string v { get; set; } = string.Empty; /// /// /// public string ps { get; set; } = string.Empty; /// /// /// public string add { get; set; } = string.Empty; /// /// /// public string port { get; set; } = string.Empty; /// /// /// public string id { get; set; } = string.Empty; /// /// /// public string aid { get; set; } = string.Empty; /// /// /// public string scy { get; set; } = string.Empty; /// /// /// public string net { get; set; } = string.Empty; /// /// /// public string type { get; set; } = string.Empty; /// /// /// public string host { get; set; } = string.Empty; /// /// /// public string path { get; set; } = string.Empty; /// /// TLS /// public string tls { get; set; } = string.Empty; /// /// TLS SNI /// public string sni { get; set; } = string.Empty; /// /// TLS alpn /// public string alpn { get; set; } = string.Empty; /// /// TLS fingerprint /// public string fp { get; set; } = string.Empty; public string allowInsecure { get; set; } = string.Empty; } } ================================================ FILE: v2rayN/v2rayN/Resx/Hiddify.Designer.cs ================================================ //------------------------------------------------------------------------------ // // 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 v2rayN.Resx { 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", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Hiddify { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Hiddify() { } /// /// Returns the cached ResourceManager instance used by this class. /// [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("v2rayN.Resx.Hiddify", typeof(Hiddify).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)] public static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } /// /// Looks up a localized string similar to Fragment. /// public static string Fragment { get { return ResourceManager.GetString("Fragment", resourceCulture); } } } } ================================================ FILE: v2rayN/v2rayN/Resx/Hiddify.resx ================================================  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 Fragment ================================================ FILE: v2rayN/v2rayN/Resx/ResUI.Designer.cs ================================================ //------------------------------------------------------------------------------ // // 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 v2rayN.Resx { 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", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class ResUI { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal ResUI() { } /// /// Returns the cached ResourceManager instance used by this class. /// [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("v2rayN.Resx.ResUI", typeof(ResUI).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)] public static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } /// /// Looks up a localized string similar to Do you want to append rules? Choose yes to append, choose otherwise to replace. /// public static string AddBatchRoutingRulesYesNo { get { return ResourceManager.GetString("AddBatchRoutingRulesYesNo", resourceCulture); } } /// /// Looks up a localized string similar to All. /// public static string AllGroupServers { get { return ResourceManager.GetString("AllGroupServers", resourceCulture); } } /// /// Looks up a localized string similar to Batch export subscription to clipboard successfully. /// public static string BatchExportSubscriptionSuccessfully { get { return ResourceManager.GetString("BatchExportSubscriptionSuccessfully", resourceCulture); } } /// /// Looks up a localized string similar to Batch export share URL to clipboard successfully. /// public static string BatchExportURLSuccessfully { get { return ResourceManager.GetString("BatchExportURLSuccessfully", resourceCulture); } } /// /// Looks up a localized string similar to Please check the server settings first. /// public static string CheckServerSettings { get { return ResourceManager.GetString("CheckServerSettings", resourceCulture); } } /// /// Looks up a localized string similar to Invalid configuration format. /// public static string ConfigurationFormatIncorrect { get { return ResourceManager.GetString("ConfigurationFormatIncorrect", resourceCulture); } } /// /// Looks up a localized string similar to Note that custom configuration relies entirely on your own configuration and does not work with all settings. If you want to use the system proxy, please modify the listening port manually.. /// public static string CustomServerTips { get { return ResourceManager.GetString("CustomServerTips", resourceCulture); } } /// /// Looks up a localized string similar to Downloading.... /// public static string Downloading { get { return ResourceManager.GetString("Downloading", resourceCulture); } } /// /// Looks up a localized string similar to Download. /// public static string downloadSpeed { get { return ResourceManager.GetString("downloadSpeed", resourceCulture); } } /// /// Looks up a localized string similar to Whether to download? {0}. /// public static string DownloadYesNo { get { return ResourceManager.GetString("DownloadYesNo", resourceCulture); } } /// /// Looks up a localized string similar to Failed to convert configuration file. /// public static string FailedConversionConfiguration { get { return ResourceManager.GetString("FailedConversionConfiguration", resourceCulture); } } /// /// Looks up a localized string similar to Failed to generate default configuration file. /// public static string FailedGenDefaultConfiguration { get { return ResourceManager.GetString("FailedGenDefaultConfiguration", resourceCulture); } } /// /// Looks up a localized string similar to Failed to get the default configuration. /// public static string FailedGetDefaultConfiguration { get { return ResourceManager.GetString("FailedGetDefaultConfiguration", resourceCulture); } } /// /// Looks up a localized string similar to Failed to import custom configuration server. /// public static string FailedImportedCustomServer { get { return ResourceManager.GetString("FailedImportedCustomServer", resourceCulture); } } /// /// Looks up a localized string similar to Failed to read configuration file. /// public static string FailedReadConfiguration { get { return ResourceManager.GetString("FailedReadConfiguration", resourceCulture); } } /// /// Looks up a localized string similar to Failed to run Core, please see the log. /// public static string FailedToRunCore { get { return ResourceManager.GetString("FailedToRunCore", resourceCulture); } } /// /// Looks up a localized string similar to Please fill in the correct custom DNS. /// public static string FillCorrectDNSText { get { return ResourceManager.GetString("FillCorrectDNSText", resourceCulture); } } /// /// Looks up a localized string similar to Please fill in the correct format server port. /// public static string FillCorrectServerPort { get { return ResourceManager.GetString("FillCorrectServerPort", resourceCulture); } } /// /// Looks up a localized string similar to Please fill in the KCP parameters correctly. /// public static string FillKcpParameters { get { return ResourceManager.GetString("FillKcpParameters", resourceCulture); } } /// /// Looks up a localized string similar to Please fill in the local listening port. /// public static string FillLocalListeningPort { get { return ResourceManager.GetString("FillLocalListeningPort", resourceCulture); } } /// /// Looks up a localized string similar to Please fill in the password. /// public static string FillPassword { get { return ResourceManager.GetString("FillPassword", resourceCulture); } } /// /// Looks up a localized string similar to Please fill in the server address. /// public static string FillServerAddress { get { return ResourceManager.GetString("FillServerAddress", resourceCulture); } } /// /// Looks up a localized string similar to Please browse to import server configuration. /// public static string FillServerAddressCustom { get { return ResourceManager.GetString("FillServerAddressCustom", resourceCulture); } } /// /// Looks up a localized string similar to Please fill in the user ID. /// public static string FillUUID { get { return ResourceManager.GetString("FillUUID", resourceCulture); } } /// /// Looks up a localized string similar to Transport. /// public static string GbTransport { get { return ResourceManager.GetString("GbTransport", resourceCulture); } } /// /// Looks up a localized string similar to is not the correct client configuration file, please check. /// public static string IncorrectClientConfiguration { get { return ResourceManager.GetString("IncorrectClientConfiguration", resourceCulture); } } /// /// Looks up a localized string similar to is not the correct configuration, please check. /// public static string Incorrectconfiguration { get { return ResourceManager.GetString("Incorrectconfiguration", resourceCulture); } } /// /// Looks up a localized string similar to is not the correct server configuration file, please check. /// public static string IncorrectServerConfiguration { get { return ResourceManager.GetString("IncorrectServerConfiguration", resourceCulture); } } /// /// Looks up a localized string similar to Initial Configuration. /// public static string InitialConfiguration { get { return ResourceManager.GetString("InitialConfiguration", resourceCulture); } } /// /// Looks up a localized string similar to {0} already up to date.. /// public static string IsLatestCore { get { return ResourceManager.GetString("IsLatestCore", resourceCulture); } } /// /// Looks up a localized string similar to {0} already up to date.. /// public static string IsLatestN { get { return ResourceManager.GetString("IsLatestN", resourceCulture); } } /// /// Looks up a localized string similar to LAN. /// public static string LabLAN { get { return ResourceManager.GetString("LabLAN", resourceCulture); } } /// /// Looks up a localized string similar to Local. /// public static string LabLocal { get { return ResourceManager.GetString("LabLocal", resourceCulture); } } /// /// Looks up a localized string similar to Address. /// public static string LvAddress { get { return ResourceManager.GetString("LvAddress", resourceCulture); } } /// /// 查找类似 Automatic update interval(minutes) 的本地化字符串。 /// public static string LvAutoUpdateInterval { get { return ResourceManager.GetString("LvAutoUpdateInterval", resourceCulture); } } /// /// 查找类似 Convert target type 的本地化字符串。 /// public static string LvConvertTarget { get { return ResourceManager.GetString("LvConvertTarget", resourceCulture); } } /// /// 查找类似 Please leave blank if no conversion is required 的本地化字符串。 /// public static string LvConvertTargetTip { get { return ResourceManager.GetString("LvConvertTargetTip", resourceCulture); } } /// /// 查找类似 Count 的本地化字符串。 /// public static string LvCount { get { return ResourceManager.GetString("LvCount", resourceCulture); } } /// /// Looks up a localized string similar to Custom Icon. /// public static string LvCustomIcon { get { return ResourceManager.GetString("LvCustomIcon", resourceCulture); } } /// /// Looks up a localized string similar to Enabled Update. /// public static string LvEnabled { get { return ResourceManager.GetString("LvEnabled", resourceCulture); } } /// /// Looks up a localized string similar to Security. /// public static string LvEncryptionMethod { get { return ResourceManager.GetString("LvEncryptionMethod", resourceCulture); } } /// /// Looks up a localized string similar to Remarks regular filter. /// public static string LvFilter { get { return ResourceManager.GetString("LvFilter", resourceCulture); } } /// /// 查找类似 More urls, separated by commas;Subscription conversion will be invalid 的本地化字符串。 /// public static string LvMoreUrl { get { return ResourceManager.GetString("LvMoreUrl", resourceCulture); } } /// /// 查找类似 Port 的本地化字符串。 /// public static string LvPort { get { return ResourceManager.GetString("LvPort", resourceCulture); } } /// /// Looks up a localized string similar to Remarks. /// public static string LvRemarks { get { return ResourceManager.GetString("LvRemarks", resourceCulture); } } /// /// Looks up a localized string similar to Type. /// public static string LvServiceType { get { return ResourceManager.GetString("LvServiceType", resourceCulture); } } /// /// Looks up a localized string similar to Sort. /// public static string LvSort { get { return ResourceManager.GetString("LvSort", resourceCulture); } } /// /// Looks up a localized string similar to Subs group. /// public static string LvSubscription { get { return ResourceManager.GetString("LvSubscription", resourceCulture); } } /// /// Looks up a localized string similar to Delay(ms). /// public static string LvTestDelay { get { return ResourceManager.GetString("LvTestDelay", resourceCulture); } } /// /// Looks up a localized string similar to Test Results. /// public static string LvTestResults { get { return ResourceManager.GetString("LvTestResults", resourceCulture); } } /// /// Looks up a localized string similar to Speed(M/s). /// public static string LvTestSpeed { get { return ResourceManager.GetString("LvTestSpeed", resourceCulture); } } /// /// Looks up a localized string similar to TLS. /// public static string LvTLS { get { return ResourceManager.GetString("LvTLS", resourceCulture); } } /// /// Looks up a localized string similar to Download traffic today. /// public static string LvTodayDownloadDataAmount { get { return ResourceManager.GetString("LvTodayDownloadDataAmount", resourceCulture); } } /// /// Looks up a localized string similar to Upload traffic today. /// public static string LvTodayUploadDataAmount { get { return ResourceManager.GetString("LvTodayUploadDataAmount", resourceCulture); } } /// /// Looks up a localized string similar to Total download traffic. /// public static string LvTotalDownloadDataAmount { get { return ResourceManager.GetString("LvTotalDownloadDataAmount", resourceCulture); } } /// /// Looks up a localized string similar to Total upload traffic. /// public static string LvTotalUploadDataAmount { get { return ResourceManager.GetString("LvTotalUploadDataAmount", resourceCulture); } } /// /// Looks up a localized string similar to Transport. /// public static string LvTransportProtocol { get { return ResourceManager.GetString("LvTransportProtocol", resourceCulture); } } /// /// Looks up a localized string similar to Url(Optional). /// public static string LvUrl { get { return ResourceManager.GetString("LvUrl", resourceCulture); } } /// /// Looks up a localized string similar to User Agent. /// public static string LvUserAgent { get { return ResourceManager.GetString("LvUserAgent", resourceCulture); } } /// /// Looks up a localized string similar to Medium. /// public static string MediumFresh { get { return ResourceManager.GetString("MediumFresh", resourceCulture); } } /// /// Looks up a localized string similar to Add a custom configuration server. /// public static string menuAddCustomServer { get { return ResourceManager.GetString("menuAddCustomServer", resourceCulture); } } /// /// Looks up a localized string similar to Import bulk URL from clipboard (Ctrl+V). /// public static string menuAddServerViaClipboard { get { return ResourceManager.GetString("menuAddServerViaClipboard", resourceCulture); } } /// /// Looks up a localized string similar to Scan QR code on the screen (Ctrl+S). /// public static string menuAddServerViaScan { get { return ResourceManager.GetString("menuAddServerViaScan", resourceCulture); } } /// /// Looks up a localized string similar to Add [Shadowsocks] server. /// public static string menuAddShadowsocksServer { get { return ResourceManager.GetString("menuAddShadowsocksServer", resourceCulture); } } /// /// Looks up a localized string similar to Add [Socks] server. /// public static string menuAddSocksServer { get { return ResourceManager.GetString("menuAddSocksServer", resourceCulture); } } /// /// Looks up a localized string similar to Add [Trojan] server. /// public static string menuAddTrojanServer { get { return ResourceManager.GetString("menuAddTrojanServer", resourceCulture); } } /// /// Looks up a localized string similar to Add [VLESS] server. /// public static string menuAddVlessServer { get { return ResourceManager.GetString("menuAddVlessServer", resourceCulture); } } /// /// Looks up a localized string similar to Add [VMess] server. /// public static string menuAddVmessServer { get { return ResourceManager.GetString("menuAddVmessServer", resourceCulture); } } /// /// Looks up a localized string similar to Check Update. /// public static string menuCheckUpdate { get { return ResourceManager.GetString("menuCheckUpdate", resourceCulture); } } /// /// Looks up a localized string similar to Clear all service statistics. /// public static string menuClearServerStatistics { get { return ResourceManager.GetString("menuClearServerStatistics", resourceCulture); } } /// /// Looks up a localized string similar to Close. /// public static string menuClose { get { return ResourceManager.GetString("menuClose", resourceCulture); } } /// /// Looks up a localized string similar to Clone selected server. /// public static string menuCopyServer { get { return ResourceManager.GetString("menuCopyServer", resourceCulture); } } /// /// 查找类似 DNS Settings 的本地化字符串。 /// public static string menuDNSSetting { get { return ResourceManager.GetString("menuDNSSetting", resourceCulture); } } /// /// 查找类似 Edit Server (Ctrl+D) 的本地化字符串。 /// public static string menuEditServer { get { return ResourceManager.GetString("menuEditServer", resourceCulture); } } /// /// Looks up a localized string similar to Exit. /// public static string menuExit { get { return ResourceManager.GetString("menuExit", resourceCulture); } } /// /// Looks up a localized string similar to Export selected server for client configuration. /// public static string menuExport2ClientConfig { get { return ResourceManager.GetString("menuExport2ClientConfig", resourceCulture); } } /// /// Looks up a localized string similar to Export selected server for server configuration. /// public static string menuExport2ServerConfig { get { return ResourceManager.GetString("menuExport2ServerConfig", resourceCulture); } } /// /// Looks up a localized string similar to Export share URLs to clipboard (Ctrl+C). /// public static string menuExport2ShareUrl { get { return ResourceManager.GetString("menuExport2ShareUrl", resourceCulture); } } /// /// Looks up a localized string similar to Export subscription (base64) share to clipboard. /// public static string menuExport2SubContent { get { return ResourceManager.GetString("menuExport2SubContent", resourceCulture); } } /// /// Looks up a localized string similar to GlobalHotkeySetting. /// public static string menuGlobalHotkeySetting { get { return ResourceManager.GetString("menuGlobalHotkeySetting", resourceCulture); } } /// /// Looks up a localized string similar to Help. /// public static string menuHelp { get { return ResourceManager.GetString("menuHelp", resourceCulture); } } /// /// Looks up a localized string similar to Import old config guiNConfig. /// public static string menuImportOldGuiConfig { get { return ResourceManager.GetString("menuImportOldGuiConfig", resourceCulture); } } /// /// Looks up a localized string similar to Import Rules From Clipboard. /// public static string menuImportRulesFromClipboard { get { return ResourceManager.GetString("menuImportRulesFromClipboard", resourceCulture); } } /// /// Looks up a localized string similar to Import Rules From File. /// public static string menuImportRulesFromFile { get { return ResourceManager.GetString("menuImportRulesFromFile", resourceCulture); } } /// /// Looks up a localized string similar to Import Rules From Sub Url. /// public static string menuImportRulesFromUrl { get { return ResourceManager.GetString("menuImportRulesFromUrl", resourceCulture); } } /// /// Looks up a localized string similar to One-click multi test Latency and speed (Ctrl+E). /// public static string menuMixedTestServer { get { return ResourceManager.GetString("menuMixedTestServer", resourceCulture); } } /// /// Looks up a localized string similar to Move to bottom (B). /// public static string menuMoveBottom { get { return ResourceManager.GetString("menuMoveBottom", resourceCulture); } } /// /// Looks up a localized string similar to Down (D). /// public static string menuMoveDown { get { return ResourceManager.GetString("menuMoveDown", resourceCulture); } } /// /// Looks up a localized string similar to Move up and down. /// public static string menuMoveTo { get { return ResourceManager.GetString("menuMoveTo", resourceCulture); } } /// /// Looks up a localized string similar to Move to group. /// public static string menuMoveToGroup { get { return ResourceManager.GetString("menuMoveToGroup", resourceCulture); } } /// /// Looks up a localized string similar to Move to top (T). /// public static string menuMoveTop { get { return ResourceManager.GetString("menuMoveTop", resourceCulture); } } /// /// Looks up a localized string similar to Up (U). /// public static string menuMoveUp { get { return ResourceManager.GetString("menuMoveUp", resourceCulture); } } /// /// Looks up a localized string similar to Clear All. /// public static string menuMsgViewClear { get { return ResourceManager.GetString("menuMsgViewClear", resourceCulture); } } /// /// Looks up a localized string similar to Copy (Ctrl+C). /// public static string menuMsgViewCopy { get { return ResourceManager.GetString("menuMsgViewCopy", resourceCulture); } } /// /// Looks up a localized string similar to Copy All. /// public static string menuMsgViewCopyAll { get { return ResourceManager.GetString("menuMsgViewCopyAll", resourceCulture); } } /// /// Looks up a localized string similar to Set message filters. /// public static string menuMsgViewFilter { get { return ResourceManager.GetString("menuMsgViewFilter", resourceCulture); } } /// /// Looks up a localized string similar to Select All (Ctrl+A). /// public static string menuMsgViewSelectAll { get { return ResourceManager.GetString("menuMsgViewSelectAll", resourceCulture); } } /// /// Looks up a localized string similar to OptionSetting. /// public static string menuOptionSetting { get { return ResourceManager.GetString("menuOptionSetting", resourceCulture); } } /// /// Looks up a localized string similar to Test servers ping (Ctrl+P). /// public static string menuPingServer { get { return ResourceManager.GetString("menuPingServer", resourceCulture); } } /// /// Looks up a localized string similar to Channel. /// public static string menuPromotion { get { return ResourceManager.GetString("menuPromotion", resourceCulture); } } /// /// Looks up a localized string similar to Test servers real delay (Ctrl+R). /// public static string menuRealPingServer { get { return ResourceManager.GetString("menuRealPingServer", resourceCulture); } } /// /// 查找类似 Reboot as administrator 的本地化字符串。 /// public static string menuRebootAsAdmin { get { return ResourceManager.GetString("menuRebootAsAdmin", resourceCulture); } } /// /// 查找类似 Reload 的本地化字符串。 /// public static string menuReload { get { return ResourceManager.GetString("menuReload", resourceCulture); } } /// /// Looks up a localized string similar to Remove duplicate servers. /// public static string menuRemoveDuplicateServer { get { return ResourceManager.GetString("menuRemoveDuplicateServer", resourceCulture); } } /// /// Looks up a localized string similar to Remove selected servers (Delete). /// public static string menuRemoveServer { get { return ResourceManager.GetString("menuRemoveServer", resourceCulture); } } /// /// Looks up a localized string similar to Routing. /// public static string menuRouting { get { return ResourceManager.GetString("menuRouting", resourceCulture); } } /// /// Looks up a localized string similar to Advanced Function. /// public static string menuRoutingAdvanced { get { return ResourceManager.GetString("menuRoutingAdvanced", resourceCulture); } } /// /// Looks up a localized string similar to Add. /// public static string menuRoutingAdvancedAdd { get { return ResourceManager.GetString("menuRoutingAdvancedAdd", resourceCulture); } } /// /// Looks up a localized string similar to Import Advanced Rules. /// public static string menuRoutingAdvancedImportRules { get { return ResourceManager.GetString("menuRoutingAdvancedImportRules", resourceCulture); } } /// /// 查找类似 Remove selected (Delete) 的本地化字符串。 /// public static string menuRoutingAdvancedRemove { get { return ResourceManager.GetString("menuRoutingAdvancedRemove", resourceCulture); } } /// /// Looks up a localized string similar to Set as active rule. /// public static string menuRoutingAdvancedSetDefault { get { return ResourceManager.GetString("menuRoutingAdvancedSetDefault", resourceCulture); } } /// /// Looks up a localized string similar to Basic Function. /// public static string menuRoutingBasic { get { return ResourceManager.GetString("menuRoutingBasic", resourceCulture); } } /// /// Looks up a localized string similar to Import Basic Rules. /// public static string menuRoutingBasicImportRules { get { return ResourceManager.GetString("menuRoutingBasicImportRules", resourceCulture); } } /// /// Looks up a localized string similar to RoutingRuleDetailsSetting. /// public static string menuRoutingRuleDetailsSetting { get { return ResourceManager.GetString("menuRoutingRuleDetailsSetting", resourceCulture); } } /// /// Looks up a localized string similar to Rule Setting. /// public static string menuRoutingRuleSetting { get { return ResourceManager.GetString("menuRoutingRuleSetting", resourceCulture); } } /// /// Looks up a localized string similar to RoutingSetting. /// public static string menuRoutingSetting { get { return ResourceManager.GetString("menuRoutingSetting", resourceCulture); } } /// /// Looks up a localized string similar to Rule Add. /// public static string menuRuleAdd { get { return ResourceManager.GetString("menuRuleAdd", resourceCulture); } } /// /// Looks up a localized string similar to Export Selected Rules. /// public static string menuRuleExportSelected { get { return ResourceManager.GetString("menuRuleExportSelected", resourceCulture); } } /// /// Looks up a localized string similar to Rule List. /// public static string menuRuleList { get { return ResourceManager.GetString("menuRuleList", resourceCulture); } } /// /// Looks up a localized string similar to Remove Rules. /// public static string menuRuleRemove { get { return ResourceManager.GetString("menuRuleRemove", resourceCulture); } } /// /// Looks up a localized string similar to Select All (Ctrl+A). /// public static string menuSelectAll { get { return ResourceManager.GetString("menuSelectAll", resourceCulture); } } /// /// Looks up a localized string similar to Servers. /// public static string menuServers { get { return ResourceManager.GetString("menuServers", resourceCulture); } } /// /// Looks up a localized string similar to Set as active server (Enter). /// public static string menuSetDefaultServer { get { return ResourceManager.GetString("menuSetDefaultServer", resourceCulture); } } /// /// Looks up a localized string similar to Setting. /// public static string menuSetting { get { return ResourceManager.GetString("menuSetting", resourceCulture); } } /// /// Looks up a localized string similar to Share Server (Ctrl+F). /// public static string menuShareServer { get { return ResourceManager.GetString("menuShareServer", resourceCulture); } } /// /// Looks up a localized string similar to Sort by test result. /// public static string menuSortServerResult { get { return ResourceManager.GetString("menuSortServerResult", resourceCulture); } } /// /// Looks up a localized string similar to Test servers download speed (Ctrl+T). /// public static string menuSpeedServer { get { return ResourceManager.GetString("menuSpeedServer", resourceCulture); } } /// /// Looks up a localized string similar to Add. /// public static string menuSubAdd { get { return ResourceManager.GetString("menuSubAdd", resourceCulture); } } /// /// Looks up a localized string similar to Delete. /// public static string menuSubDelete { get { return ResourceManager.GetString("menuSubDelete", resourceCulture); } } /// /// Looks up a localized string similar to Edit. /// public static string menuSubEdit { get { return ResourceManager.GetString("menuSubEdit", resourceCulture); } } /// /// Looks up a localized string similar to Update current subscription without proxy. /// public static string menuSubGroupUpdate { get { return ResourceManager.GetString("menuSubGroupUpdate", resourceCulture); } } /// /// Looks up a localized string similar to Update current subscription with proxy. /// public static string menuSubGroupUpdateViaProxy { get { return ResourceManager.GetString("menuSubGroupUpdateViaProxy", resourceCulture); } } /// /// Looks up a localized string similar to Subs group. /// public static string menuSubscription { get { return ResourceManager.GetString("menuSubscription", resourceCulture); } } /// /// 查找类似 Subscription group Settings 的本地化字符串。 /// public static string menuSubSetting { get { return ResourceManager.GetString("menuSubSetting", resourceCulture); } } /// /// Looks up a localized string similar to Share. /// public static string menuSubShare { get { return ResourceManager.GetString("menuSubShare", resourceCulture); } } /// /// Looks up a localized string similar to Update subscription without proxy. /// public static string menuSubUpdate { get { return ResourceManager.GetString("menuSubUpdate", resourceCulture); } } /// /// Looks up a localized string similar to Update subscription with proxy. /// public static string menuSubUpdateViaProxy { get { return ResourceManager.GetString("menuSubUpdateViaProxy", resourceCulture); } } /// /// Looks up a localized string similar to System proxy. /// public static string menuSystemproxy { get { return ResourceManager.GetString("menuSystemproxy", resourceCulture); } } /// /// Looks up a localized string similar to Clear system proxy. /// public static string menuSystemProxyClear { get { return ResourceManager.GetString("menuSystemProxyClear", resourceCulture); } } /// /// Looks up a localized string similar to Do not change system proxy. /// public static string menuSystemProxyNothing { get { return ResourceManager.GetString("menuSystemProxyNothing", resourceCulture); } } /// /// Looks up a localized string similar to Pac Mode. /// public static string menuSystemProxyPac { get { return ResourceManager.GetString("menuSystemProxyPac", resourceCulture); } } /// /// Looks up a localized string similar to Set system proxy. /// public static string menuSystemProxySet { get { return ResourceManager.GetString("menuSystemProxySet", resourceCulture); } } /// /// Looks up a localized string similar to Test servers with tcping (Ctrl+O). /// public static string menuTcpingServer { get { return ResourceManager.GetString("menuTcpingServer", resourceCulture); } } /// /// Looks up a localized string similar to Test current service status. /// public static string menuTestMe { get { return ResourceManager.GetString("menuTestMe", resourceCulture); } } /// /// Looks up a localized string similar to {0} Website. /// public static string menuWebsiteItem { get { return ResourceManager.GetString("menuWebsiteItem", resourceCulture); } } /// /// Looks up a localized string similar to Clear original subscription content. /// public static string MsgClearSubscription { get { return ResourceManager.GetString("MsgClearSubscription", resourceCulture); } } /// /// Looks up a localized string similar to The link is invalid. /// public static string MsgDeepLinkIsInvalid { get { return ResourceManager.GetString("MsgDeepLinkIsInvalid", resourceCulture); } } /// /// Looks up a localized string similar to Download GeoFile: {0} successfully. /// public static string MsgDownloadGeoFileSuccessfully { get { return ResourceManager.GetString("MsgDownloadGeoFileSuccessfully", resourceCulture); } } /// /// Looks up a localized string similar to Download Core successfully. /// public static string MsgDownloadV2rayCoreSuccessfully { get { return ResourceManager.GetString("MsgDownloadV2rayCoreSuccessfully", resourceCulture); } } /// /// Looks up a localized string similar to Failed to import subscription content. /// public static string MsgFailedImportSubscription { get { return ResourceManager.GetString("MsgFailedImportSubscription", resourceCulture); } } /// /// Looks up a localized string similar to Filter, support regular. /// public static string MsgFilterTitle { get { return ResourceManager.GetString("MsgFilterTitle", resourceCulture); } } /// /// Looks up a localized string similar to Get subscription content successfully. /// public static string MsgGetSubscriptionSuccessfully { get { return ResourceManager.GetString("MsgGetSubscriptionSuccessfully", resourceCulture); } } /// /// Looks up a localized string similar to Information. /// public static string MsgInformationTitle { get { return ResourceManager.GetString("MsgInformationTitle", resourceCulture); } } /// /// Looks up a localized string similar to Please fill in the Url. /// public static string MsgNeedUrl { get { return ResourceManager.GetString("MsgNeedUrl", resourceCulture); } } /// /// Looks up a localized string similar to Nothing has been Updated. /// public static string MsgNothingUpdated { get { return ResourceManager.GetString("MsgNothingUpdated", resourceCulture); } } /// /// Looks up a localized string similar to No valid subscriptions set. /// public static string MsgNoValidSubscription { get { return ResourceManager.GetString("MsgNoValidSubscription", resourceCulture); } } /// /// Looks up a localized string similar to PAC update failed. /// public static string MsgPACUpdateFailed { get { return ResourceManager.GetString("MsgPACUpdateFailed", resourceCulture); } } /// /// Looks up a localized string similar to PAC update succeeded. /// public static string MsgPACUpdateSuccessfully { get { return ResourceManager.GetString("MsgPACUpdateSuccessfully", resourceCulture); } } /// /// Looks up a localized string similar to Resolve {0} successfully. /// public static string MsgParsingSuccessfully { get { return ResourceManager.GetString("MsgParsingSuccessfully", resourceCulture); } } /// /// 查找类似 Servers Filter, press Enter to execute 的本地化字符串。 /// public static string MsgProgramNeedsRestarting { get { return ResourceManager.GetString("MsgProgramNeedsRestarting", resourceCulture); } } /// /// Looks up a localized string similar to Servers Filter. /// public static string MsgServerTitle { get { return ResourceManager.GetString("MsgServerTitle", resourceCulture); } } /// /// 查找类似 Updates are not enabled, skip this subscription 的本地化字符串。 /// public static string MsgSkipSubscriptionUpdate { get { return ResourceManager.GetString("MsgSkipSubscriptionUpdate", resourceCulture); } } /// /// Looks up a localized string similar to Start getting subscriptions. /// public static string MsgStartGettingSubscriptions { get { return ResourceManager.GetString("MsgStartGettingSubscriptions", resourceCulture); } } /// /// Looks up a localized string similar to To do this, the program must be run in Administrator mode. /// public static string MsgStartProgramAsAdmin { get { return ResourceManager.GetString("MsgStartProgramAsAdmin", resourceCulture); } } /// /// Looks up a localized string similar to Start updating {0}.... /// public static string MsgStartUpdating { get { return ResourceManager.GetString("MsgStartUpdating", resourceCulture); } } /// /// Looks up a localized string similar to Start updating PAC.... /// public static string MsgStartUpdatingPAC { get { return ResourceManager.GetString("MsgStartUpdatingPAC", resourceCulture); } } /// /// Looks up a localized string similar to Invalid subscription content. /// public static string MsgSubscriptionDecodingFailed { get { return ResourceManager.GetString("MsgSubscriptionDecodingFailed", resourceCulture); } } /// /// Looks up a localized string similar to is unpacking.... /// public static string MsgUnpacking { get { return ResourceManager.GetString("MsgUnpacking", resourceCulture); } } /// /// Looks up a localized string similar to Update subscription end. /// public static string MsgUpdateSubscriptionEnd { get { return ResourceManager.GetString("MsgUpdateSubscriptionEnd", resourceCulture); } } /// /// Looks up a localized string similar to Update subscription starts. /// public static string MsgUpdateSubscriptionStart { get { return ResourceManager.GetString("MsgUpdateSubscriptionStart", resourceCulture); } } /// /// Looks up a localized string similar to Update Core successfully. /// public static string MsgUpdateV2rayCoreSuccessfully { get { return ResourceManager.GetString("MsgUpdateV2rayCoreSuccessfully", resourceCulture); } } /// /// Looks up a localized string similar to Update Core successfully! Restarting service.... /// public static string MsgUpdateV2rayCoreSuccessfullyMore { get { return ResourceManager.GetString("MsgUpdateV2rayCoreSuccessfullyMore", resourceCulture); } } /// /// Looks up a localized string similar to This feature relies on the Http global proxy, please set it correctly first.. /// public static string NeedHttpGlobalProxy { get { return ResourceManager.GetString("NeedHttpGlobalProxy", resourceCulture); } } /// /// Looks up a localized string similar to Normal use of this version requires .NET Framework 4.8. /// public static string NetFrameworkRequirementsTip { get { return ResourceManager.GetString("NetFrameworkRequirementsTip", resourceCulture); } } /// /// Looks up a localized string similar to Non-VMess or ss protocol. /// public static string NonvmessOrssProtocol { get { return ResourceManager.GetString("NonvmessOrssProtocol", resourceCulture); } } /// /// Looks up a localized string similar to non-standard service, this feature is invalid. /// public static string NonVmessService { get { return ResourceManager.GetString("NonVmessService", resourceCulture); } } /// /// Looks up a localized string similar to The Core file (file name: {1}) was not found under the folder ({0}), please download and put it in the folder, download address: {2}. /// public static string NotFoundCore { get { return ResourceManager.GetString("NotFoundCore", resourceCulture); } } /// /// Looks up a localized string similar to Not Run As Admin. /// public static string NotRunAsAdmin { get { return ResourceManager.GetString("NotRunAsAdmin", resourceCulture); } } /// /// Looks up a localized string similar to Scan completed, no valid QR code found. /// public static string NoValidQRcodeFound { get { return ResourceManager.GetString("NoValidQRcodeFound", resourceCulture); } } /// /// Looks up a localized string similar to operation failed, please check and retry. /// public static string OperationFailed { get { return ResourceManager.GetString("OperationFailed", resourceCulture); } } /// /// Looks up a localized string similar to Operation success. /// public static string OperationSuccess { get { return ResourceManager.GetString("OperationSuccess", resourceCulture); } } /// /// Looks up a localized string similar to Please Fill Remarks. /// public static string PleaseFillRemarks { get { return ResourceManager.GetString("PleaseFillRemarks", resourceCulture); } } /// /// Looks up a localized string similar to Please select the encryption method. /// public static string PleaseSelectEncryption { get { return ResourceManager.GetString("PleaseSelectEncryption", resourceCulture); } } /// /// Looks up a localized string similar to Please select a protocol. /// public static string PleaseSelectProtocol { get { return ResourceManager.GetString("PleaseSelectProtocol", resourceCulture); } } /// /// Looks up a localized string similar to Please select rules. /// public static string PleaseSelectRules { get { return ResourceManager.GetString("PleaseSelectRules", resourceCulture); } } /// /// Looks up a localized string similar to Please select the server first. /// public static string PleaseSelectServer { get { return ResourceManager.GetString("PleaseSelectServer", resourceCulture); } } /// /// Looks up a localized string similar to Fast. /// public static string QuickFresh { get { return ResourceManager.GetString("QuickFresh", resourceCulture); } } /// /// Looks up a localized string similar to Global hotkey {0} registered failed, reason {1}. /// public static string RegisterGlobalHotkeyFailed { get { return ResourceManager.GetString("RegisterGlobalHotkeyFailed", resourceCulture); } } /// /// Looks up a localized string similar to Global hotkey {0} registered successfully. /// public static string RegisterGlobalHotkeySuccessfully { get { return ResourceManager.GetString("RegisterGlobalHotkeySuccessfully", resourceCulture); } } /// /// Looks up a localized string similar to Servers deduplication completed. Old: {0}, New: {1}.. /// public static string RemoveDuplicateServerResult { get { return ResourceManager.GetString("RemoveDuplicateServerResult", resourceCulture); } } /// /// Looks up a localized string similar to Are you sure to remove the rules?. /// public static string RemoveRules { get { return ResourceManager.GetString("RemoveRules", resourceCulture); } } /// /// Looks up a localized string similar to Are you sure to remove the server?. /// public static string RemoveServer { get { return ResourceManager.GetString("RemoveServer", resourceCulture); } } /// /// Looks up a localized string similar to All Sites. /// public static string RoutingAllSites { get { return ResourceManager.GetString("RoutingAllSites", resourceCulture); } } public static string HomeAdvancedSettings { get { return ResourceManager.GetString("HomeAdvancedSettings", resourceCulture); } } public static string HomeImport { get { return ResourceManager.GetString("HomeImport", resourceCulture); } } public static string HomeDelay { get { return ResourceManager.GetString("HomeDelay", resourceCulture); } } public static string HomeRemaining { get { return ResourceManager.GetString("HomeRemaining", resourceCulture); } } public static string HomeConnected { get { return ResourceManager.GetString("HomeConnected", resourceCulture); } } public static string HomeNotConnected { get { return ResourceManager.GetString("HomeNotConnected", resourceCulture); } } public static string HomeDisconnected { get { return ResourceManager.GetString("HomeDisconnected", resourceCulture); } } public static string HomeProxyAuto { get { return ResourceManager.GetString("HomeProxyAuto", resourceCulture); } } public static string HomeProxyLoadBalance { get { return ResourceManager.GetString("HomeProxyLoadBalance", resourceCulture); } } public static string HomeProxyManual { get { return ResourceManager.GetString("HomeProxyManual", resourceCulture); } } public static string HomeProxyModeSelection { get { return ResourceManager.GetString("HomeProxyModeSelection", resourceCulture); } } public static string HomeConnecting { get { return ResourceManager.GetString("HomeConnecting", resourceCulture); } } public static string HomeDays { get { return ResourceManager.GetString("HomeDays", resourceCulture); } } public static string HomeUsage { get { return ResourceManager.GetString("HomeUsage", resourceCulture); } } public static string HomeDelete { get { return ResourceManager.GetString("HomeDelete", resourceCulture); } } public static string HomeWelcomeMsg { get { return ResourceManager.GetString("HomeWelcomeMsg", resourceCulture); } } /// /// Looks up a localized string similar to Blocked Sites. /// public static string RoutingBlockedSites { get { return ResourceManager.GetString("RoutingBlockedSites", resourceCulture); } } /// /// Looks up a localized string similar to Foreign Sites. /// public static string RoutingForeignSites { get { return ResourceManager.GetString("RoutingForeignSites", resourceCulture); } } /// /// Looks up a localized string similar to {0},One of the required.. /// public static string RoutingRuleDetailRequiredTips { get { return ResourceManager.GetString("RoutingRuleDetailRequiredTips", resourceCulture); } } /// /// Looks up a localized string similar to Run As Admin. /// public static string RunAsAdmin { get { return ResourceManager.GetString("RunAsAdmin", resourceCulture); } } /// /// Looks up a localized string similar to The client configuration file is saved at: {0}. /// public static string SaveClientConfigurationIn { get { return ResourceManager.GetString("SaveClientConfigurationIn", resourceCulture); } } /// /// 查找类似 {0}:{1}/s↑ | {2}/s↓ 的本地化字符串。 /// public static string SpeedDisplayText { get { return ResourceManager.GetString("SpeedDisplayText", resourceCulture); } } /// /// Looks up a localized string similar to Slow. /// public static string SlowFresh { get { return ResourceManager.GetString("SlowFresh", resourceCulture); } } /// /// Looks up a localized string similar to Note: This feature relies on the Http global proxy. Please manually adjust the Http global proxy and active node after testing.. /// public static string SpeedServerTips { get { return ResourceManager.GetString("SpeedServerTips", resourceCulture); } } /// /// Looks up a localized string similar to Testing.... /// public static string Speedtesting { get { return ResourceManager.GetString("Speedtesting", resourceCulture); } } /// /// Looks up a localized string similar to Test completed. /// public static string SpeedtestingCompleted { get { return ResourceManager.GetString("SpeedtestingCompleted", resourceCulture); } } /// /// Looks up a localized string similar to Skip test. /// public static string SpeedtestingSkip { get { return ResourceManager.GetString("SpeedtestingSkip", resourceCulture); } } /// /// Looks up a localized string similar to Waiting for testing. /// public static string SpeedtestingWait { get { return ResourceManager.GetString("SpeedtestingWait", resourceCulture); } } /// /// Looks up a localized string similar to PAC failed to start. Please run this program as Administrator.. /// public static string StartPacFailed { get { return ResourceManager.GetString("StartPacFailed", resourceCulture); } } /// /// Looks up a localized string similar to Start service ({0}).... /// public static string StartService { get { return ResourceManager.GetString("StartService", resourceCulture); } } /// /// Looks up a localized string similar to Group please leave blank here. /// public static string SubUrlTips { get { return ResourceManager.GetString("SubUrlTips", resourceCulture); } } /// /// Looks up a localized string similar to Configuration successful ///{0}. /// public static string SuccessfulConfiguration { get { return ResourceManager.GetString("SuccessfulConfiguration", resourceCulture); } } /// /// Looks up a localized string similar to Custom configuration server imported successfully.. /// public static string SuccessfullyImportedCustomServer { get { return ResourceManager.GetString("SuccessfullyImportedCustomServer", resourceCulture); } } /// /// Looks up a localized string similar to {0} servers have been imported from clipboard.. /// public static string SuccessfullyImportedServerViaClipboard { get { return ResourceManager.GetString("SuccessfullyImportedServerViaClipboard", resourceCulture); } } /// /// Looks up a localized string similar to Scan import URL successfully. /// public static string SuccessfullyImportedServerViaScan { get { return ResourceManager.GetString("SuccessfullyImportedServerViaScan", resourceCulture); } } /// /// Looks up a localized string similar to System proxy. /// public static string SystemProxy { get { return ResourceManager.GetString("SystemProxy", resourceCulture); } } /// /// Looks up a localized string similar to Address. /// public static string TbAddress { get { return ResourceManager.GetString("TbAddress", resourceCulture); } } /// /// Looks up a localized string similar to AllowInsecure. /// public static string TbAllowInsecure { get { return ResourceManager.GetString("TbAllowInsecure", resourceCulture); } } /// /// Looks up a localized string similar to Alpn. /// public static string TbAlpn { get { return ResourceManager.GetString("TbAlpn", resourceCulture); } } /// /// Looks up a localized string similar to AlterId. /// public static string TbAlterId { get { return ResourceManager.GetString("TbAlterId", resourceCulture); } } /// /// Looks up a localized string similar to AutoRefresh. /// public static string TbAutoRefresh { get { return ResourceManager.GetString("TbAutoRefresh", resourceCulture); } } /// /// Looks up a localized string similar to Domain and ip are auto sorted when saving. /// public static string TbAutoSort { get { return ResourceManager.GetString("TbAutoSort", resourceCulture); } } /// /// Looks up a localized string similar to Browse. /// public static string TbBrowse { get { return ResourceManager.GetString("TbBrowse", resourceCulture); } } /// /// Looks up a localized string similar to Cancel. /// public static string TbCancel { get { return ResourceManager.GetString("TbCancel", resourceCulture); } } /// /// Looks up a localized string similar to Clear system proxy. /// public static string TbClearSystemProxy { get { return ResourceManager.GetString("TbClearSystemProxy", resourceCulture); } } /// /// Looks up a localized string similar to Confirm. /// public static string TbConfirm { get { return ResourceManager.GetString("TbConfirm", resourceCulture); } } /// /// Looks up a localized string similar to Core Type. /// public static string TbCoreType { get { return ResourceManager.GetString("TbCoreType", resourceCulture); } } /// /// Looks up a localized string similar to Display GUI. /// public static string TbDisplayGUI { get { return ResourceManager.GetString("TbDisplayGUI", resourceCulture); } } /// /// Looks up a localized string similar to Display Log. /// public static string TbDisplayLog { get { return ResourceManager.GetString("TbDisplayLog", resourceCulture); } } /// /// 查找类似 Support DnsObject, Click to view the document 的本地化字符串。 /// public static string TbDnsObjectDoc { get { return ResourceManager.GetString("TbDnsObjectDoc", resourceCulture); } } /// /// 查找类似 Please fill in DNS Structure, Click to view the document 的本地化字符串。 /// public static string TbDnsSingboxObjectDoc { get { return ResourceManager.GetString("TbDnsSingboxObjectDoc", resourceCulture); } } /// /// 查找类似 Domain Matcher 的本地化字符串。 /// public static string TbdomainMatcher { get { return ResourceManager.GetString("TbdomainMatcher", resourceCulture); } } /// /// Looks up a localized string similar to Domain strategy. /// public static string TbdomainStrategy { get { return ResourceManager.GetString("TbdomainStrategy", resourceCulture); } } /// /// 查找类似 Sing-box domain strategy 的本地化字符串。 /// public static string TbdomainStrategy4Singbox { get { return ResourceManager.GetString("TbdomainStrategy4Singbox", resourceCulture); } } /// /// 查找类似 Edit 的本地化字符串。 /// public static string TbEdit { get { return ResourceManager.GetString("TbEdit", resourceCulture); } } /// /// Looks up a localized string similar to Use Proxy. /// public static string TbEnableProxy { get { return ResourceManager.GetString("TbEnableProxy", resourceCulture); } } /// /// Looks up a localized string similar to Enable advanced function. /// public static string TbenableRoutingAdvanced { get { return ResourceManager.GetString("TbenableRoutingAdvanced", resourceCulture); } } /// /// Looks up a localized string similar to Enable Tun. /// public static string TbEnableTunAs { get { return ResourceManager.GetString("TbEnableTunAs", resourceCulture); } } /// /// Looks up a localized string similar to Fingerprint. /// public static string TbFingerprint { get { return ResourceManager.GetString("TbFingerprint", resourceCulture); } } /// /// Looks up a localized string similar to Flow. /// public static string TbFlow5 { get { return ResourceManager.GetString("TbFlow5", resourceCulture); } } /// /// 查找类似 GlobalHotkey Settings 的本地化字符串。 /// public static string TbGlobalHotkeySetting { get { return ResourceManager.GetString("TbGlobalHotkeySetting", resourceCulture); } } /// /// Looks up a localized string similar to Set directly by pressing the keyboard, Take effect after restart. /// public static string TbGlobalHotkeySettingTip { get { return ResourceManager.GetString("TbGlobalHotkeySettingTip", resourceCulture); } } /// /// Looks up a localized string similar to Generate. /// public static string TbGUID { get { return ResourceManager.GetString("TbGUID", resourceCulture); } } /// /// Looks up a localized string similar to Camouflage type. /// public static string TbHeaderType { get { return ResourceManager.GetString("TbHeaderType", resourceCulture); } } /// /// Looks up a localized string similar to UUID(id). /// public static string TbId { get { return ResourceManager.GetString("TbId", resourceCulture); } } /// /// Looks up a localized string similar to Password. /// public static string TbId3 { get { return ResourceManager.GetString("TbId3", resourceCulture); } } /// /// Looks up a localized string similar to Password(Optional). /// public static string TbId4 { get { return ResourceManager.GetString("TbId4", resourceCulture); } } /// /// Looks up a localized string similar to UUID(id). /// public static string TbId5 { get { return ResourceManager.GetString("TbId5", resourceCulture); } } /// /// Looks up a localized string similar to Transport protocol(network). /// public static string TbNetwork { get { return ResourceManager.GetString("TbNetwork", resourceCulture); } } /// /// Looks up a localized string similar to Do not change system proxy. /// public static string TbNotChangeSystemProxy { get { return ResourceManager.GetString("TbNotChangeSystemProxy", resourceCulture); } } /// /// Looks up a localized string similar to Path. /// public static string TbPath { get { return ResourceManager.GetString("TbPath", resourceCulture); } } /// /// Looks up a localized string similar to Port. /// public static string TbPort { get { return ResourceManager.GetString("TbPort", resourceCulture); } } /// /// Looks up a localized string similar to txtPreSocksPort. /// public static string TbPreSocksPort { get { return ResourceManager.GetString("TbPreSocksPort", resourceCulture); } } /// /// Looks up a localized string similar to PublicKey. /// public static string TbPublicKey { get { return ResourceManager.GetString("TbPublicKey", resourceCulture); } } /// /// Looks up a localized string similar to Alias (remarks). /// public static string TbRemarks { get { return ResourceManager.GetString("TbRemarks", resourceCulture); } } /// /// Looks up a localized string similar to Camouflage domain(host). /// public static string TbRequestHost { get { return ResourceManager.GetString("TbRequestHost", resourceCulture); } } /// /// Looks up a localized string similar to Reset. /// public static string TbReset { get { return ResourceManager.GetString("TbReset", resourceCulture); } } /// /// Looks up a localized string similar to 3.Block Domain or IP. /// public static string TbRoutingTabBlock { get { return ResourceManager.GetString("TbRoutingTabBlock", resourceCulture); } } /// /// Looks up a localized string similar to 2.Direct Domain or IP. /// public static string TbRoutingTabDirect { get { return ResourceManager.GetString("TbRoutingTabDirect", resourceCulture); } } /// /// Looks up a localized string similar to 1.Proxy Domain or IP. /// public static string TbRoutingTabProxy { get { return ResourceManager.GetString("TbRoutingTabProxy", resourceCulture); } } /// /// Looks up a localized string similar to Pre-defined Rule Set List. /// public static string TbRoutingTabRuleList { get { return ResourceManager.GetString("TbRoutingTabRuleList", resourceCulture); } } /// /// Looks up a localized string similar to *Set the rules, separated by commas (,); The comma in the regular is replaced by <COMMA>. /// public static string TbRoutingTips { get { return ResourceManager.GetString("TbRoutingTips", resourceCulture); } } /// /// Looks up a localized string similar to Ruleobject Doc. /// public static string TbRuleobjectDoc { get { return ResourceManager.GetString("TbRuleobjectDoc", resourceCulture); } } /// /// Looks up a localized string similar to Encryption method (security). /// public static string TbSecurity { get { return ResourceManager.GetString("TbSecurity", resourceCulture); } } /// /// Looks up a localized string similar to Encryption. /// public static string TbSecurity3 { get { return ResourceManager.GetString("TbSecurity3", resourceCulture); } } /// /// Looks up a localized string similar to User(Optional). /// public static string TbSecurity4 { get { return ResourceManager.GetString("TbSecurity4", resourceCulture); } } /// /// Looks up a localized string similar to Encryption. /// public static string TbSecurity5 { get { return ResourceManager.GetString("TbSecurity5", resourceCulture); } } /// /// Looks up a localized string similar to Set system proxy. /// public static string TbSetSystemProxy { get { return ResourceManager.GetString("TbSetSystemProxy", resourceCulture); } } /// /// 查找类似 Click to import default DNS config 的本地化字符串。 /// public static string TBSettingDnsImportDefConfig { get { return ResourceManager.GetString("TBSettingDnsImportDefConfig", resourceCulture); } } /// /// 查找类似 Advanced proxy settings, protocol selection (optional) 的本地化字符串。 /// public static string TbSettingsAdvancedProtocol { get { return ResourceManager.GetString("TbSettingsAdvancedProtocol", resourceCulture); } } /// /// Looks up a localized string similar to Allow connections from the LAN. /// public static string TbSettingsAllowLAN { get { return ResourceManager.GetString("TbSettingsAllowLAN", resourceCulture); } } /// /// Looks up a localized string similar to Auto hide startup. /// public static string TbSettingsAutoHideStartup { get { return ResourceManager.GetString("TbSettingsAutoHideStartup", resourceCulture); } } /// /// 查找类似 Automatic update interval of Geo (hours) 的本地化字符串。 /// public static string TbSettingsAutoTest { get { return ResourceManager.GetString("TbSettingsAutoTest", resourceCulture); } } /// /// Looks up a localized string similar to Automatic update interval of subscriptions (hours). /// public static string TbSettingsAutoUpdate { get { return ResourceManager.GetString("TbSettingsAutoUpdate", resourceCulture); } } /// /// Looks up a localized string similar to Automatic update interval of and Geo (hours). /// public static string TbSettingsAutoUpdateInterval { get { return ResourceManager.GetString("TbSettingsAutoUpdateInterval", resourceCulture); } } /// /// Looks up a localized string similar to Color. /// public static string TbSettingsColor { get { return ResourceManager.GetString("TbSettingsColor", resourceCulture); } } /// /// Looks up a localized string similar to Dark Mode. /// public static string TbSettingsColorMode { get { return ResourceManager.GetString("TbSettingsColorMode", resourceCulture); } } /// /// Looks up a localized string similar to Core: basic settings. /// public static string TbSettingsCore { get { return ResourceManager.GetString("TbSettingsCore", resourceCulture); } } /// /// 查找类似 V2ray DNS settings 的本地化字符串。 /// public static string TbSettingsCoreDns { get { return ResourceManager.GetString("TbSettingsCoreDns", resourceCulture); } } /// /// 查找类似 Sing-box DNS settings 的本地化字符串。 /// public static string TbSettingsCoreDnsSingbox { get { return ResourceManager.GetString("TbSettingsCoreDnsSingbox", resourceCulture); } } /// /// 查找类似 Core: KCP settings 的本地化字符串。 /// public static string TbSettingsCoreKcp { get { return ResourceManager.GetString("TbSettingsCoreKcp", resourceCulture); } } /// /// Looks up a localized string similar to CoreType settings. /// public static string TbSettingsCoreType { get { return ResourceManager.GetString("TbSettingsCoreType", resourceCulture); } } /// /// Looks up a localized string similar to FontFamily(Require restart). /// public static string TbSettingsCurrentFontFamily { get { return ResourceManager.GetString("TbSettingsCurrentFontFamily", resourceCulture); } } /// /// Looks up a localized string similar to Copy the font TTF file to the directory guiFonts, restart the settings. /// public static string TbSettingsCurrentFontFamilyTip { get { return ResourceManager.GetString("TbSettingsCurrentFontFamilyTip", resourceCulture); } } /// /// Looks up a localized string similar to AllowInsecure. /// public static string TbSettingsDefAllowInsecure { get { return ResourceManager.GetString("TbSettingsDefAllowInsecure", resourceCulture); } } /// /// Looks up a localized string similar to Default TLS fingerprint. /// public static string TbSettingsDefFingerprint { get { return ResourceManager.GetString("TbSettingsDefFingerprint", resourceCulture); } } /// /// Looks up a localized string similar to User-Agent. /// public static string TbSettingsDefUserAgent { get { return ResourceManager.GetString("TbSettingsDefUserAgent", resourceCulture); } } /// /// Looks up a localized string similar to This parameter is valid only for tcp/http and ws. /// public static string TbSettingsDefUserAgentTips { get { return ResourceManager.GetString("TbSettingsDefUserAgentTips", resourceCulture); } } /// /// Looks up a localized string similar to Outbound Freedom domainStrategy. /// public static string TbSettingsDomainStrategy4Freedom { get { return ResourceManager.GetString("TbSettingsDomainStrategy4Freedom", resourceCulture); } } /// /// Looks up a localized string similar to Double-click server make active. /// public static string TbSettingsDoubleClick2Activate { get { return ResourceManager.GetString("TbSettingsDoubleClick2Activate", resourceCulture); } } /// /// Looks up a localized string similar to Automatically adjust column width after updating subscription. /// public static string TbSettingsEnableAutoAdjustMainLvColWidth { get { return ResourceManager.GetString("TbSettingsEnableAutoAdjustMainLvColWidth", resourceCulture); } } /// /// Looks up a localized string similar to Check for pre-release updates. /// public static string TbSettingsEnableCheckPreReleaseUpdate { get { return ResourceManager.GetString("TbSettingsEnableCheckPreReleaseUpdate", resourceCulture); } } /// /// Looks up a localized string similar to Enable Server Drag Drop Sort(Require restart). /// public static string TbSettingsEnableDragDropSort { get { return ResourceManager.GetString("TbSettingsEnableDragDropSort", resourceCulture); } } /// /// Looks up a localized string similar to Enable hardware acceleration(Require restart). /// public static string TbSettingsEnableHWA { get { return ResourceManager.GetString("TbSettingsEnableHWA", resourceCulture); } } /// /// Looks up a localized string similar to Exception. /// public static string TbSettingsException { get { return ResourceManager.GetString("TbSettingsException", resourceCulture); } } /// /// Looks up a localized string similar to Exception. Do not use proxy server for addresses beginning with,Use semicolon (;). /// public static string TbSettingsExceptionTip { get { return ResourceManager.GetString("TbSettingsExceptionTip", resourceCulture); } } /// /// Looks up a localized string similar to FontSize. /// public static string TbSettingsFontSize { get { return ResourceManager.GetString("TbSettingsFontSize", resourceCulture); } } /// /// Looks up a localized string similar to Http Port. /// public static string TbSettingsHttpPort { get { return ResourceManager.GetString("TbSettingsHttpPort", resourceCulture); } } /// /// Looks up a localized string similar to Ignore Geo files when updating core. /// public static string TbSettingsIgnoreGeoUpdateCore { get { return ResourceManager.GetString("TbSettingsIgnoreGeoUpdateCore", resourceCulture); } } /// /// Looks up a localized string similar to Enable IPv6. /// public static string TbSettingsIpv6 { get { return ResourceManager.GetString("TbSettingsIpv6", resourceCulture); } } /// /// Looks up a localized string similar to Keep older when deduplication. /// public static string TbSettingsKeepOlderDedupl { get { return ResourceManager.GetString("TbSettingsKeepOlderDedupl", resourceCulture); } } /// /// Looks up a localized string similar to Language(Restart). /// public static string TbSettingsLanguage { get { return ResourceManager.GetString("TbSettingsLanguage", resourceCulture); } } /// /// Looks up a localized string similar to Enable Log. /// public static string TbSettingsLogEnabled { get { return ResourceManager.GetString("TbSettingsLogEnabled", resourceCulture); } } /// /// 查找类似 Enable logging to file 的本地化字符串。 /// public static string TbSettingsLogEnabledToFile { get { return ResourceManager.GetString("TbSettingsLogEnabledToFile", resourceCulture); } } /// /// 查找类似 Log Level 的本地化字符串。 /// public static string TbSettingsLogLevel { get { return ResourceManager.GetString("TbSettingsLogLevel", resourceCulture); } } /// /// Looks up a localized string similar to Turn on Mux Multiplexing. /// public static string TbSettingsMuxEnabled { get { return ResourceManager.GetString("TbSettingsMuxEnabled", resourceCulture); } } /// /// Looks up a localized string similar to v2rayN settings. /// public static string TbSettingsN { get { return ResourceManager.GetString("TbSettingsN", resourceCulture); } } /// /// Looks up a localized string similar to New Port for LAN. /// public static string TbSettingsNewPort4LAN { get { return ResourceManager.GetString("TbSettingsNewPort4LAN", resourceCulture); } } /// /// Looks up a localized string similar to Pac listen port. /// public static string TbSettingsPacListenPort { get { return ResourceManager.GetString("TbSettingsPacListenPort", resourceCulture); } } /// /// Looks up a localized string similar to Auth pass. /// public static string TbSettingsPass { get { return ResourceManager.GetString("TbSettingsPass", resourceCulture); } } /// /// Looks up a localized string similar to Custom DNS (multiple, separated by commas (,)). /// public static string TbSettingsRemoteDNS { get { return ResourceManager.GetString("TbSettingsRemoteDNS", resourceCulture); } } /// /// Looks up a localized string similar to RouteOnly. /// public static string TbSettingsRouteOnly { get { return ResourceManager.GetString("TbSettingsRouteOnly", resourceCulture); } } /// /// Looks up a localized string similar to After modifying the following parameters, click Save to take effect. /// public static string TbSettingsSaveTip { get { return ResourceManager.GetString("TbSettingsSaveTip", resourceCulture); } } /// /// Looks up a localized string similar to Set Win10 UWP Loopback. /// public static string TbSettingsSetUWP { get { return ResourceManager.GetString("TbSettingsSetUWP", resourceCulture); } } /// /// Looks up a localized string similar to Turn on Sniffing. /// public static string TbSettingsSniffingEnabled { get { return ResourceManager.GetString("TbSettingsSniffingEnabled", resourceCulture); } } /// /// Looks up a localized string similar to Socks Port. /// public static string TbSettingsSocksPort { get { return ResourceManager.GetString("TbSettingsSocksPort", resourceCulture); } } /// /// Looks up a localized string similar to http port=socks port+1. /// public static string TbSettingsSocksPortTip { get { return ResourceManager.GetString("TbSettingsSocksPortTip", resourceCulture); } } /// /// Looks up a localized string similar to SpeedTest Single Timeout Value. /// public static string TbSettingsSpeedTestTimeout { get { return ResourceManager.GetString("TbSettingsSpeedTestTimeout", resourceCulture); } } /// /// Looks up a localized string similar to SpeedTest Url. /// public static string TbSettingsSpeedTestUrl { get { return ResourceManager.GetString("TbSettingsSpeedTestUrl", resourceCulture); } } /// /// Looks up a localized string similar to Start on boot. /// public static string TbSettingsStartBoot { get { return ResourceManager.GetString("TbSettingsStartBoot", resourceCulture); } } /// /// Looks up a localized string similar to Set this with admin privileges, get admin privileges after startup. /// public static string TbSettingsStartBootTip { get { return ResourceManager.GetString("TbSettingsStartBootTip", resourceCulture); } } /// /// Looks up a localized string similar to Enable Statistics (Require restart). /// public static string TbSettingsStatistics { get { return ResourceManager.GetString("TbSettingsStatistics", resourceCulture); } } /// /// Looks up a localized string similar to Statistics freshrate (second). /// public static string TbSettingsStatisticsFreshRate { get { return ResourceManager.GetString("TbSettingsStatisticsFreshRate", resourceCulture); } } /// /// Looks up a localized string similar to Subscription conversion Url. /// public static string TbSettingsSubConvert { get { return ResourceManager.GetString("TbSettingsSubConvert", resourceCulture); } } /// /// Looks up a localized string similar to System proxy settings. /// public static string TbSettingsSystemproxy { get { return ResourceManager.GetString("TbSettingsSystemproxy", resourceCulture); } } /// /// Looks up a localized string similar to Enable Security Protocol TLS v1.3 (subscription/update). /// public static string TbSettingsTLS13 { get { return ResourceManager.GetString("TbSettingsTLS13", resourceCulture); } } /// /// Looks up a localized string similar to Tray right-click menu servers display limit. /// public static string TbSettingsTrayMenuServersLimit { get { return ResourceManager.GetString("TbSettingsTrayMenuServersLimit", resourceCulture); } } /// /// Looks up a localized string similar to TunMode settings. /// public static string TbSettingsTunMode { get { return ResourceManager.GetString("TbSettingsTunMode", resourceCulture); } } /// /// Looks up a localized string similar to Bypass Mode. /// public static string TbSettingsTunModeBypassMode { get { return ResourceManager.GetString("TbSettingsTunModeBypassMode", resourceCulture); } } /// /// Looks up a localized string similar to Enable: If no route matches, the final proxy. /// public static string TbSettingsTunModeBypassModeTip { get { return ResourceManager.GetString("TbSettingsTunModeBypassModeTip", resourceCulture); } } /// /// Looks up a localized string similar to Custom Template. /// public static string TbSettingsTunModeCustomTemplate { get { return ResourceManager.GetString("TbSettingsTunModeCustomTemplate", resourceCulture); } } /// /// Looks up a localized string similar to Direct IP CIDR, separated by commas (,). /// public static string TbSettingsTunModeDirectIP { get { return ResourceManager.GetString("TbSettingsTunModeDirectIP", resourceCulture); } } /// /// Looks up a localized string similar to Direct Process name, separated by commas (,). /// public static string TbSettingsTunModeDirectProcess { get { return ResourceManager.GetString("TbSettingsTunModeDirectProcess", resourceCulture); } } /// /// Looks up a localized string similar to DNS object, e.g. {"servers":[]}. /// public static string TbSettingsTunModeDNS { get { return ResourceManager.GetString("TbSettingsTunModeDNS", resourceCulture); } } /// /// Looks up a localized string similar to Proxy IP CIDR, separated by commas (,). /// public static string TbSettingsTunModeProxyIP { get { return ResourceManager.GetString("TbSettingsTunModeProxyIP", resourceCulture); } } /// /// Looks up a localized string similar to Proxy Process name, separated by commas (,). /// public static string TbSettingsTunModeProxyProcess { get { return ResourceManager.GetString("TbSettingsTunModeProxyProcess", resourceCulture); } } /// /// Looks up a localized string similar to Show console. /// public static string TbSettingsTunModeShowWindow { get { return ResourceManager.GetString("TbSettingsTunModeShowWindow", resourceCulture); } } /// /// Looks up a localized string similar to Enable UDP. /// public static string TbSettingsUdpEnabled { get { return ResourceManager.GetString("TbSettingsUdpEnabled", resourceCulture); } } /// /// Looks up a localized string similar to Auth user. /// public static string TbSettingsUser { get { return ResourceManager.GetString("TbSettingsUser", resourceCulture); } } /// /// Looks up a localized string similar to ShortId. /// public static string TbShortId { get { return ResourceManager.GetString("TbShortId", resourceCulture); } } /// /// Looks up a localized string similar to SNI. /// public static string TbSNI { get { return ResourceManager.GetString("TbSNI", resourceCulture); } } /// /// Looks up a localized string similar to SpiderX. /// public static string TbSpiderX { get { return ResourceManager.GetString("TbSpiderX", resourceCulture); } } /// /// Looks up a localized string similar to TLS. /// public static string TbStreamSecurity { get { return ResourceManager.GetString("TbStreamSecurity", resourceCulture); } } /// /// Looks up a localized string similar to Pac Mode. /// public static string TbSystemProxyPac { get { return ResourceManager.GetString("TbSystemProxyPac", resourceCulture); } } /// /// Looks up a localized string similar to The ping of current service: {0} ms. /// public static string TestMeOutput { get { return ResourceManager.GetString("TestMeOutput", resourceCulture); } } /// /// Looks up a localized string similar to Routing setting is changed. /// public static string TipChangeRouting { get { return ResourceManager.GetString("TipChangeRouting", resourceCulture); } } /// /// Looks up a localized string similar to System proxy setting is changed. /// public static string TipChangeSystemProxy { get { return ResourceManager.GetString("TipChangeSystemProxy", resourceCulture); } } /// /// Looks up a localized string similar to Please turn off when there is an abnormal disconnection. /// public static string TipDisplayLog { get { return ResourceManager.GetString("TipDisplayLog", resourceCulture); } } /// /// Looks up a localized string similar to *Default value tcp. /// public static string TipNetwork { get { return ResourceManager.GetString("TipNetwork", resourceCulture); } } /// /// 查找类似 * After setting this value, an socks service will be started using Sing-box to provide functions such as speed display 的本地化字符串。 /// public static string TipPreSocksPort { get { return ResourceManager.GetString("TipPreSocksPort", resourceCulture); } } /// /// Looks up a localized string similar to Too many servers, please open the main interface. /// public static string TooManyServersTip { get { return ResourceManager.GetString("TooManyServersTip", resourceCulture); } } /// /// Looks up a localized string similar to *tcp camouflage type. /// public static string TransportHeaderTypeTip1 { get { return ResourceManager.GetString("TransportHeaderTypeTip1", resourceCulture); } } /// /// Looks up a localized string similar to *kcp camouflage type. /// public static string TransportHeaderTypeTip2 { get { return ResourceManager.GetString("TransportHeaderTypeTip2", resourceCulture); } } /// /// Looks up a localized string similar to *QUIC camouflage type. /// public static string TransportHeaderTypeTip3 { get { return ResourceManager.GetString("TransportHeaderTypeTip3", resourceCulture); } } /// /// Looks up a localized string similar to *grpc mode. /// public static string TransportHeaderTypeTip4 { get { return ResourceManager.GetString("TransportHeaderTypeTip4", resourceCulture); } } /// /// Looks up a localized string similar to *ws path. /// public static string TransportPathTip1 { get { return ResourceManager.GetString("TransportPathTip1", resourceCulture); } } /// /// Looks up a localized string similar to *h2 path. /// public static string TransportPathTip2 { get { return ResourceManager.GetString("TransportPathTip2", resourceCulture); } } /// /// Looks up a localized string similar to *QUIC key/Kcp seed. /// public static string TransportPathTip3 { get { return ResourceManager.GetString("TransportPathTip3", resourceCulture); } } /// /// Looks up a localized string similar to *grpc serviceName. /// public static string TransportPathTip4 { get { return ResourceManager.GetString("TransportPathTip4", resourceCulture); } } /// /// Looks up a localized string similar to *Kcp seed. /// public static string TransportPathTip5 { get { return ResourceManager.GetString("TransportPathTip5", resourceCulture); } } /// /// Looks up a localized string similar to *http host Separated by commas (,). /// public static string TransportRequestHostTip1 { get { return ResourceManager.GetString("TransportRequestHostTip1", resourceCulture); } } /// /// Looks up a localized string similar to *ws host. /// public static string TransportRequestHostTip2 { get { return ResourceManager.GetString("TransportRequestHostTip2", resourceCulture); } } /// /// Looks up a localized string similar to *h2 host Separated by commas (,). /// public static string TransportRequestHostTip3 { get { return ResourceManager.GetString("TransportRequestHostTip3", resourceCulture); } } /// /// Looks up a localized string similar to *QUIC security. /// public static string TransportRequestHostTip4 { get { return ResourceManager.GetString("TransportRequestHostTip4", resourceCulture); } } /// /// Looks up a localized string similar to Ungrouped. /// public static string UngroupedServers { get { return ResourceManager.GetString("UngroupedServers", resourceCulture); } } } } ================================================ FILE: v2rayN/v2rayN/Resx/ResUI.fa-Ir.resx ================================================  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 صادرات دسته ای محتوای اشتراک به کلیپ بورد با موفقیت انجام شد Batch export share URL to clipboard successfully لطفا ابتدا تنظیمات سرور را بررسی کنید فرمت پیکربندی نادرست است توجه داشته باشید که پیکربندی سفارشی کاملاً به پیکربندی خود شما بستگی دارد و با همه تنظیمات کار نمی کند. اگر می خواهید از پروکسی سیستم استفاده کنید، لطفاً پورت درحال شنود را به صورت دستی تغییر دهید. درحال دانلود... دانلود Whether to download? {0} تبدیل فایل پیکربندی انجام نشد فایل پیکربندی پیش فرض ایجاد نشد پیکربندی پیش فرض دریافت نشد سرور پیکربندی سفارشی وارد نشد فایل پیکربندی خوانده نشد لطفا فرمت صحیح پورت سرور را پر کنید لطفاً پارامترهای KCP را به درستی پر کنید لطفاً پورت گوش دادن محلی را پر کنید لطفا رمز عبور را وارد کنید لطفا آدرس سرور را وارد کنید لطفا شناسه کاربری را وارد کنید فایل پیکربندی مشتری صحیح نیست، لطفا بررسی کنید پیکربندی درستی نیست، لطفا بررسی کنید فایل پیکربندی سرور صحیح نیست، لطفا بررسی کنید پیکربندی اولیه {0} در حال حاضر به روز است. {0} در حال حاضر به روز است. آدرس امنیت پورت نوع گروه فرعی ترافیک دانلود امروز ترافیک اپلود امروز کل ترافیک دانلود کل ترافیک آپلود جابجایی محتوای اشتراک اصلی را پاک کنید دانلود Core با موفقیت محتوای اشتراک وارد نشد محتوای اشتراک با موفقیت دریافت شد هیچ اشتراک معتبری تنظیم نشده است Resolve {0} successfully شروع به دریافت اشتراک شد شروع بروزرسانی {0}... محتوای اشتراک نامعتبر است در حال باز کردن بسته می باشد ... بروزرسانی اشتراک به پایان رسید چیزی بروزرسانی نشد برای اجرای این عملیات، برنامه باید در حالت Administrator اجرا شود لینک نامعتبر است ! برای انجام این عملیات، برنامه باید راه‌اندازی مجدد شود بروزرسانی اشتراک شروع شد هسته با موفقیت بروزرسانی شد هسته با موفقیت بروزرسانی شد! راه اندازی مجدد سرویس... Non-VMess or ss protocol non-standard service, this feature is invalid The Core file (file name: {1}) was not found under the folder ({0}), please download and put it in the folder, download address: {2} Scan completed, no valid QR code found عملیات انجام نشد، لطفا بررسی کنید و دوباره امتحان کنید Please Fill Remarks لطفاً روش رمزگذاری را انتخاب کنید لطفا یک پروتکل انتخاب کنید لطفا ابتدا سرور را انتخاب کنید Servers deduplication completed. Old: {0}, New: {1}. آیا مطمئن هستید که سرور را حذف می کنید؟ The client configuration file is saved at: {0} Start service ({0})... پیکربندی با موفقیت انجام شد {0} سرور پیکربندی سفارشی با موفقیت وارد شد. {0} سرورها از کلیپ بورد وارد شده اند. اسکن URL وارد کردن با موفقیت پینگ سرویس فعلی: {0} ms موفقیت عملیات لطفا قوانین را انتخاب کنید آیا مطمئن هستید که قوانین را حذف می کنید؟ {0},یکی از مورد نیاز. Remarks Url(Optional) Count Please fill in the address (Url) Do you want to append rules? Choose yes to append, choose otherwise to replace دانلود GeoFile: {0} با موفقیت افزودن حذف به هیدیفای خوش امدید روز مصرف متصل شده خودکار متعادل دستی متصل نشده قطع شده باقیمانده تاخیر در حال اتصال... انتخاب حالت پروکسی اطلاعات نماد سفارشی لطفاً DNS سفارشی صحیح را پر کنید تنظیمات پیشرفته تاخیر ws path h2 path QUIC key/Kcp seed grpc serviceName http host Separated by commas (,) ws host h2 host Separated by commas (,) QUIC securty tcp camouflage type kcp camouflage type QUIC camouflage type grpc mode TLS Kcp seed Global hotkey {0} registered failed, reason {1} Global hotkey {0} registered successfully گروه بندی نشده همه سرورها Please browse to import server configuration پروکسی سیستم درحال تست کردن... تعداد سرورها خیلی زیاد است، لطفا رابط اصلی را باز کنید LAN محلی فیلتر سرورها بررسی بروزرسانی بستن خروج تنظیم کلید میانبر کلی کمک تنظیمات پارامتر اطلاع رسانی بارگذاری مجدد تنظیم مسیریابی سرورها تنظیمات اشتراک فعلی را بدون پروکسی به روز شود اشتراک فعلی را با پروکسی به روز شود گروه اشتراک تنظیم گروه اشتراک اشتراک را بدون پروکسی به روز شود اشتراک را با پروکسی به روز شود پروکسی سیستم پاک کردن پروکسی سیستم پروکسی سیستم تغییر نکند حالت Pac تنظیم پراکسی سیستم رنگ حالت تاریک زبان وارد کردن URL انبوه از کلیپ بورد (Ctrl+V) اسکن کد QR روی صفحه (Ctrl+S) سرور انتخاب شده را شبیه سازی کنید سرورهای تکراری را حذف کنید حذف سرورهای انتخابی (Delete) به عنوان سرور فعال تنظیم کنید (Enter) تمام آمار خدمات را پاک کنید تست پینگ سرورها (Ctrl+P) آزمایش سرورها با تاخیر واقعی (Ctrl+R) مرتب سازی بر اساس نتیجه تست تست سرعت دانلود سرورها (Ctrl+T) تست سرورها با tcping (Ctrl+O) وضعیت سرویس فعلی را تست کنید سرور انتخابی را برای پیکربندی کلاینت صادر کنید URL های اشتراک گذاری را به کلیپ بورد صادر کنید (Ctrl+C) اشتراک (base64) را به کلیپ بورد صادر کنید یک سرور پیکربندی سفارشی اضافه شود سرور [شادوساکس] را اضافه کنید سرور [ساکس] را اضافه کنید سرور [تروجان] را اضافه کنید سرور [VLESS] را اضافه کنید سرور [VMess] را اضافه کنید انتخاب همه (Ctrl+A) همه را پاک کن کپی (Ctrl+C) کپی همه فیلترهای پیام را تنظیم کنید انتخاب همه (Ctrl+A) اضافه کردن حذف ویرایش اشتراک به روز رسانی فعال شد مرتب سازی عامل کاربر لغو تایید انتقال آدرس اجازه ناامن Alpn AlterId Fingerprint Camouflage type UUID(id) پروتکل جابجایی (شبکه) مسیر پورت Alias (remarks) Camouflage domain(host) Encryption method (security) SNI TLS Default value tcp نوع هسته جریان Generate رمزعبور رمز عبور (اختیاری) UUID(id) رمزگذاری کاربر (اختیاری) رمزگذاری txtPreSocksPort * After setting this value, an socks service will be started using Sing-box to provide functions such as speed display Browse ویرایش تنظیمات پیشرفته پروکسی، انتخاب پروتکل (اختیاری) اتصالات از LAN را مجاز کنید Auto hide startup فاصله به روز رسانی خودکار و Geo (ساعت) هسته: تنظیمات اولیه V2ray DNS settings هسته: تنظیمات KCP تنظیمات CoreType اجازه ناامن Outbound Freedom domainStrategy پس از به‌روزرسانی اشتراک، عرض ستون را به صورت خودکار تنظیم شود به روز رسانی های پیش از انتشار را بررسی شود استثنا Exception. Do not use proxy server for addresses beginning with,Use semicolon (;) پورت Http هنگام به‌روزرسانی هسته، فایل‌های Geo را نادیده بگیرید Keep older when deduplication ثبت گزارش های محلی سطح ثبت رویداد Turn on Mux Multiplexing تنظیمات v2rayN Auth pass سفارشی DNS (multiple, separated by commas (,)) Set Win10 UWP Loopback Turn on Sniffing ساکس Port درهنگام راه ائدازی شروع شود فعال کردن آمار (نیاز به راه اندازی مجدد) نرخ تازه سازی آمار (ثانیه) Subscription conversion Url تنظیمات پراکسی سیستم Enable Security Protocol TLS v1.3 (subscription/update) Tray right-click menu servers display limit UDP را فعال شود Auth user پاک کردن پروکسی سیستم نمایش رابط کاربری گرافیکی تنظیم کلید میانبر جهانی مستقیماً با فشار دادن صفحه کلید تنظیم کنید، بعد از راه اندازی مجدد اعمال شود پروکسی سیستم را تغییر ندهید بازنشانی تنظیم پراکسی سیستم حالت Pac اشتراک گذاری سرور(Ctrl+F) مسیریابی به عنوان ادمین اجرا نمی شود اجرا به عنوان ادمین به پایین حرکت شود(B) پایین (D) Move to top (T) Up (U) Filter, support regular {0} Website عملکرد پیشرفته اضافه کردن وارد کردن قوانین پیشرفته حذف انتخاب شده Set as active rule عملکرد پایه واردات قوانین اساسی تطبیق دامنه استراتژی دامنه فعال کردن عملکرد پیشرفته 3.Block Domain or IP 2.Direct Domain or IP 1.Proxy Domain or IP لیست مجموعه قوانین از پیش تعریف شده *Set the rules, separated by commas (,); The comma in the regular is replaced by <COMMA> وارد کردن قوانین از کلیپ بورد وارد کردن قوانین از فایل وارد کردن قوانین از Sub Url تنظیم قانون اضافه کردن قانون صادر کردن قوانین انتخاب شده فهرست قوانین حذف قوانین تنظیم جزئیات قانون مسیریابی دامنه و آی پی در هنگام ذخیره به طور خودکار مرتب می شوند Ruleobject Doc پشتیبانی از DnsObject گروه لطفا اینجا را خالی بگذارید تنظیمات مسیریابی تغییر کرده است تنظیمات پراکسی سیستم تغییر کرده است فقط مسیر One-click test Latency and speed (Ctrl+E) تاخیر (میلی‌ثانیه) Speed(M/s) Core اجرا نشد، لطفاً گزارش را ببینید Remarks regular filter نمایش گزارش پیکربندی قدیمی guiNConfig را وارد شود Tun را فعال شود پورت جدید برای LAN تنظیمات TunMode Direct IP CIDR, separated by commas (,) Direct Process name, separated by commas (,) نمایش کنسول User-Agent This parameter is valid only for tcp/http and ws فعال‌سازی شتاب‌دهنده سخت‌افزاری (نیاز به راه‌اندازی مجدد) فعال کردن پروکسی همه سایت‌ها سایت‌های فیلترشده سایت‌های خارجی ================================================ FILE: v2rayN/v2rayN/Resx/ResUI.resx ================================================  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 Batch export subscription to clipboard successfully Batch export share URL to clipboard successfully Please check the server settings first Invalid configuration format Note that custom configuration relies entirely on your own configuration and does not work with all settings. If you want to use the system proxy, please modify the listening port manually. Downloading... Download Whether to download? {0} Failed to convert configuration file Failed to generate default configuration file Failed to get the default configuration Failed to import custom configuration server Failed to read configuration file Please fill in the correct format server port Please fill in the KCP parameters correctly Please fill in the local listening port Import Delete Welcome to the Hiddify Usage Days Connected Auto Load Balance Manual Not Connected Disconnected Remaining Delay Connecting... Proxy Mode Selection Advanced Settings ّInformation نماد سفارشی لطفاً DNS سفارشی صحیح را پر کنید Please fill in the password Please fill in the server address Please fill in the user ID is not the correct client configuration file, please check is not the correct configuration, please check is not the correct server configuration file, please check Initial Configuration {0} already up to date. {0} already up to date. Address Security Port Type Subs group Download traffic today Upload traffic today Total download traffic Total upload traffic Transport Clear original subscription content Download Core successfully Failed to import subscription content Get subscription content successfully No valid subscriptions set Resolve {0} successfully Start getting subscriptions Start updating {0}... Invalid subscription content is unpacking... Update subscription end Nothing has been Updated To do this, the program must be run in Administrator mode The link is invalid To perform this operation, the program must be restarted ! Update subscription starts Update Core successfully Update Core successfully! Restarting service... Non-VMess or ss protocol non-standard service, this feature is invalid The Core file (file name: {1}) was not found under the folder ({0}), please download and put it in the folder, download address: {2} Scan completed, no valid QR code found operation failed, please check and retry Please Fill Remarks Please select the encryption method Please select a protocol Please select the server first Servers deduplication completed. Old: {0}, New: {1}. Are you sure to remove the server? The client configuration file is saved at: {0} Start service ({0})... Configuration successful {0} Custom configuration server imported successfully. {0} servers have been imported from clipboard. Scan import URL successfully The ping of current service: {0} ms Operation success Please select rules Are you sure to remove the rules? {0},One of the required. Remarks Delay Url(Optional) Count Please fill in the Url Do you want to append rules? Choose yes to append, choose otherwise to replace Download GeoFile: {0} successfully Information Custom Icon Please fill in the correct custom DNS *ws path *h2 path *QUIC key/Kcp seed *grpc serviceName *http host Separated by commas (,) *ws host *h2 host Separated by commas (,) *QUIC security *tcp camouflage type *kcp camouflage type *QUIC camouflage type *grpc mode TLS *Kcp seed Global hotkey {0} registered failed, reason {1} Global hotkey {0} registered successfully Ungrouped All Please browse to import server configuration System proxy Testing... Too many servers, please open the main interface LAN Local Servers Filter, press Enter to execute Check Update Close Exit GlobalHotkeySetting Help Option Setting Channel Reload Routing Setting Servers Settings Update current subscription without proxy Update current subscription with proxy Subs group Subscription group Settings Update subscription without proxy Update subscription with proxy System proxy Clear system proxy Do not change system proxy Pac Mode Set system proxy Color Dark Mode Language(Restart) Import bulk URL from clipboard (Ctrl+V) Scan QR code on the screen (Ctrl+S) Clone selected server Remove duplicate servers Remove selected servers (Delete) Set as active server (Enter) Clear all service statistics Test servers ping (Ctrl+P) Test servers real delay (Ctrl+R) Sort by test result Test servers download speed (Ctrl+T) Test servers with tcping (Ctrl+O) Test current service status Export selected server for client configuration Export share URLs to clipboard (Ctrl+C) Export subscription (base64) share to clipboard Add a custom configuration server Add [Shadowsocks] server Add [Socks] server Add [Trojan] server Add [VLESS] server Add [VMess] server Select All (Ctrl+A) Clear All Copy (Ctrl+C) Copy All Set message filters Select All (Ctrl+A) Add Delete Edit Share Enabled Update Sort User Agent Cancel Confirm Transport Address AllowInsecure Alpn AlterId Fingerprint Camouflage type UUID(id) Transport protocol(network) Path Port Alias (remarks) Camouflage domain(host) Encryption method (security) SNI TLS *Default value tcp Core Type Flow Generate Password Password(Optional) UUID(id) Encryption User(Optional) Encryption txtPreSocksPort * After setting this value, an socks service will be started using Sing-box to provide functions such as speed display Browse Edit Advanced proxy settings, protocol selection (optional) Allow connections from the LAN Auto hide startup Automatic update interval of Geo (hours) Core: basic settings V2ray DNS settings Core: KCP settings CoreType settings AllowInsecure Outbound Freedom domainStrategy Automatically adjust column width after updating subscription Check for pre-release updates Exception Exception. Do not use proxy server for addresses beginning with,Use semicolon (;) Http Port Ignore Geo files when updating core Keep older when deduplication Enable Log Log Level Turn on Mux Multiplexing v2rayN settings Auth pass Custom DNS (multiple, separated by commas (,)) Set Win10 UWP Loopback Turn on Sniffing Socks Port Start on boot Enable Statistics (Require restart) Statistics freshrate (second) Subscription conversion Url System proxy settings Enable Security Protocol TLS v1.3 (subscription/update) Tray right-click menu servers display limit Enable UDP Auth user Clear system proxy Display GUI GlobalHotkey Settings Set directly by pressing the keyboard, Take effect after restart Do not change system proxy Reset Set system proxy Pac Mode Share Server (Ctrl+F) Routing Not Run As Admin Run As Admin Move to bottom (B) Down (D) Move to top (T) Up (U) Filter, support regular {0} Website Advanced Function Add Import Advanced Rules Remove selected (Delete) Set as active rule(Enter) Basic Function Import Basic Rules Domain Matcher Domain strategy Enable advanced function 3.Block Domain or IP 2.Direct Domain or IP 1.Proxy Domain or IP Pre-defined Rule Set List *Set the rules, separated by commas (,); The comma in the regular is replaced by <COMMA> Import Rules From Clipboard Import Rules From File Import Rules From Sub Url Rule Settings Rule Add Export Selected Rules Rule List Remove Rules (Delete) RoutingRuleDetailsSetting Domain and ip are auto sorted when saving Ruleobject Doc Support DnsObject, Click to view the document Group please leave blank here Routing setting is changed System proxy setting is changed RouteOnly One-click multi test Latency and speed (Ctrl+E) Delay(ms) Speed(M/s) Failed to run Core, please see the log Remarks regular filter Display Log Import old config guiNConfig Enable Tun New Port for LAN TunMode settings Direct IP CIDR, separated by commas (,) Direct Process name, separated by commas (,) Show console Move to group Custom Template Enable Server Drag Drop Sort(Require restart) AutoRefresh Skip test Edit Server (Ctrl+D) Double-click server make active Test completed Default TLS fingerprint User-Agent This parameter is valid only for tcp/http and ws FontFamily(Require restart) Copy the font TTF file to the directory guiFonts, restart the settings http port=socks port+1 Set this with admin privileges, get admin privileges after startup FontSize Proxy IP CIDR, separated by commas (,) Proxy Process name, separated by commas (,) Bypass Mode Enable: If no route matches, the final proxy SpeedTest Single Timeout Value SpeedTest Url DNS object, e.g. {"servers":[]} Move up and down PublicKey ShortId SpiderX Enable hardware acceleration(Require restart) Waiting for testing Please turn off when there is an abnormal disconnection Updates are not enabled, skip this subscription Reboot as administrator More urls, separated by commas;Subscription conversion will be invalid {0}:{1}/s↑ | {2}/s↓ Automatic update interval(minutes) Enable logging to file Convert target type Please leave blank if no conversion is required DNS Settings Sing-box DNS settings Please fill in DNS Structure, Click to view the document Click to import default DNS config Sing-box domain strategy Use Proxy All Sites Blocked Sites Foreign Sites ================================================ FILE: v2rayN/v2rayN/Resx/ResUI.ru.resx ================================================  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 Экспортирование подписок в буфер обмена успешно завершено Экспортирование URL в буфер обмена успешно завершено Пожалуйста, сначала проверьте настройки сервера Недопустимый формат конфигурации Обратите внимание, что пользовательская конфигурация полностью зависит от вашей собственной конфигурации и работает не со всеми настройками. Если вы хотите использовать системный прокси, пожалуйста, измените порт прослушивания вручную. Загрузка... Скорость загрузки Хотите загрузить? {0} Не удалось преобразовать файл конфигурации Не удалось создать файл конфигурации по умолчаниюe Не удалось получить конфигурацию по умолчанию Не удалось импортировать сервер пользовательской конфигурации Не удалось прочитать файл конфигурации Пожалуйста, укажите порт сервера в правильном формате Пожалуйста, заполните параметры KCP корректно Пожалуйста, укажите локальный порт прослушивания Пожалуйста, введите пароль Пожалуйста, заполните адрес сервера Пожалуйста, заполните идентификатор пользователя Некорректный файл конфигурации клиента, пожалуйста, проверьте Некорректная конфигурация, пожалуйста, проверьте Некорректный файл конфигурации сервера, пожалуйста, проверьте Исходная конфигурация {0} является последней версией. {0} является последней версией. Адрес Безопасность Порт Тип Группа подписки Загружено трафика сегодня Отдано трафика сегодня Всего загружено Всего отдано Протокол Очистить контент оригинальной подписки Ядро успешно загружено Не удалось импортировать содержимое подписки Содержимое подписки успешно импортировано Нет установлены подписки Парсинг {0} прошел успешно Начинаю получать подписки Начинаю обновление {0}... Некорректное содержимое подписки распаковывается... Обновление подписки закончено ничего не было обновлено Для этого программа должна быть запущена в режиме Administrator Недопустимая ссылка Для выполнения этой операции программу необходимо перезапустить ! Обновление подписки начинается Успешное обновление ядра Успешное обновление ядра! Перезапуск службы... Не является протоколом Vmess или SS нестандартный сервис, эта функция недействительна Файл Core (имя файла: {1}) не найден в папке ({0}), загрузите и поместите его в папку, адрес загрузки: {2} Сканирование завершено, не найден корректный QR код операция безуспешна, проверьте и попробуйте ещё раз Пожалуйста, заполните примечания Пожалуйста, выберите метод шифрования Пожалуйста, выберите протокол Сначала выберите сервер Удаление дублей завершено. Старая: {0}, Новая: {1}. Вы уверены, что хотите удалить сервер? Файл конфигурации клиента сохранен по адресу: {0} Запуск сервиса ({0})... Конфигурация успешна {0} Пользовательский сервер конфигурации успешно импортирован. {0} серверов импортировано из буфера обмена. Сканирование URL-адреса импорта успешна. Пинг текущей службы: {0} мс Операция успешна Выберите правила Вы уверены, что хотите удалить правила? {0}, Один из обязательных.. Примечания Url(Необязательно) Количество Пожалуйста, заполните адрес (Url) Вы хотите добавить правила? Выберите «Да», чтобы добавить, выберите иное, чтобы заменить Загрузка GeoFile: {0} успешна Информация Пользовательская иконка Пожалуйста, заполните правильный пользовательский DNS *ws путь *h2 путь *QUIC ключ/Kcp seed *grpc serviceName *http хосты разделенные запятыми (,) *ws хост *h2 хосты разделенные запятыми (,) * безопасность QUIC * тип TCP камуфляжа * тип KCP камуфляжа * тип QUIC камуфляжа * режим grpc TLS *Kcp seed Не удалось зарегистрировать глобальную горячую клавишу {0}, причина: {1} Глобальная горячая клавиша {0} зарегистрирована успешно Разгруппировано Все сервера Пожалуйста, просмотрите, чтобы импортировать конфигурацию сервера Системный прокси Тестирование... Слишком много серверов, пожалуйста, откройте главный интерфейс LAN Локальный Фильтр серверов Проверить обновления Закрыть Выход Глобальная настройка горячих клавиш Помощь Настройка параметров Содействие Перезагрузка Настройки маршрутизации Сервера Настройки Обновить текущую подписку без прокси Обновить текущую подписку с прокси Группа подписки Настройки группы подписки Обновить подписку без прокси Обновить подписку с прокси Системный прокси Очистить системный прокси Не менять системный прокси Режим PAC Установить системный прокси Цвет Тёмный режим Язык (требуется перезапуск) Импорт массива URL из буфера обмена (Ctrl+V) Сканировать QR-код с экрана (Ctrl+S) Клонировать выбранный сервер Удалить дубликаты серверов Удалить выбранные серверы (Delete) Установить как активный сервер (Enter) Очистить всю статистику Проверить пинг серверов (Ctrl+P) Тест на реальную задержку серверов (Ctrl+R) Сортировать по результату теста Проверить скорость загрузки серверов (Ctrl+T) Тестировать сервера с tcping (Ctrl+O) Проверить текущий статус службы Экспортировать выбранный сервер для клиента Экспорт URL-адресов общего доступа в буфер обмена (Ctrl+C) Экспортировать ссылку-подписку (base64) в буфер обмена Добавить сервер пользовательской конфигурации Добавить сервер [Shadowsocks] Добавить сервер [Socks] Добавить сервер [Trojan] Добавить сервер [VLESS] Добавить сервер [VMess] Выбрать все (Ctrl+A) Очистить все Скопировать (Ctrl+C) Скопировать все Установить фильтры сообщений Выбрать все (Ctrl+A) Добавить Удалить Редактировать Поделиться Включены обновления Сортировка User Agent Отмена Подтвердить Транспорт Адрес Разрешить небезопасные ALPN AlterId Отпечаток Тип камуфляжа UUID(id) Транспортный протокол сети Путь Порт Псевдоним (примечания) Маскирующий домен (хост) Метод шифрования SNI TLS * По-умолчанию TCP Ядро Поток Генерировать Пароль Пароль(Необязательно) UUID(id) Шифрование Пользователь(Необязательно) Шифрования txtPreSocksPort * После установки этого значения служба socks будет запущена с использованием Sing-box для обеспечения таких функций, как отображение скорости Просмотр Редактировать Расширенные настройки прокси, выбор протокола (необязательно) Разрешить подключения из локальной сети Auto hide startup Интервал автоматического обновления Geo в часах Ядро: базовые настройки V2ray DNS settings Ядро: настройки KCP Настройки типа ядра Разрешить небезопасные Outbound Freedom domainStrategy Автоматически регулировать ширину столбца после обновления подписки Проверить наличие предварительных обновлений Исключение Исключение. Не используйте прокси-сервер для адресов, начинающихся с (,), используйте точку с запятой (;) HTTP порт Игнорировать файлы Geo при обновлении ядра Сохранить старые при удалении дублей Записывать логи Уровень логгирования Включите мультиплексирование Mux Настройки v2rayN Пароль аутентификации Пользовательский DNS (если несколько делите с запятыми (,)) Set Win10 UWP Loopback Включить сниффинг Порт Socks Автозапуск Включить статистику (требуется перезагрузка) Частота обновления статистики в секундах URL-адрес конверсии подписки Настройки системного прокси Включить протокол безопасности TLS v1.3 (обновление подписки) Tray right-click menu servers display limit Включить UDP Auth user Очистить системный прокси Показать GUI Настройка горячих клавиш Установите непосредственно, нажав на клавиатуру, вступит в силу после перезапуска Не изменять системный прокси Обнулить Установить системный прокси Режим PAC Поделиться сервером (Ctrl+F) Маршрутизация Пользователь Администратор Спуститься вниз (B) Вниз (D) Подняться наверх (T) Вверх (U) Фильтр, поддерживает regex {0} веб-сайт Расширенная функция Добавить Добавить расширенные правила Удалить выбранные Установить как активное правило Основные функции Импорт основных правил Сопоставитель доменов Доменная стратегия Включить расширенные функции 3.Заблокировать домен или IP 2.Прямой домен или IP 1.Прокси-домен или IP Предустановленный список наборов правил * Установите правила, разделенные запятыми (,); Запятая в регулярке заменена на <COMMA> Импорт правил из буфера обмена Импорт правил из файла Импорт правил из URL Настройка правил Добавить правило Экспорт выделенных правил Список правил Удалить правила (Delete) RoutingRuleDetailsSetting Домен и IP автоматически сортируются при сохранении Ruleobject Doc Поддержка DnsObject Group please leave blank here Настройки маршрутизации изменены Системные прокси изменены Только маршрут Тест задержки и скорости (Ctrl+E) Задержка (ms) Скорость (M/s) Не удалось запустить ядро, посмотрите логи Remarks regular filter Показать логи Импортировать старый конфиг guiNConfig Включить интерфейс Новый порт для локальной сети Настройки TunMode Прямой IP CIDR, разделенный запятыми (,) Имя процесса, разделенное запятыми (,) Показать консоль Перейти в группу Пользовательский шаблон Включить сортировку перетаскиванием сервера (требуется перезагрузка) Автообновление Пропустить тест Редактировать сервер (Ctrl+D) Двойной клик чтобы сделать сервер активным Тест завершен TLS отпечаток по умлочанию User-Agent Этот параметр действителен только для TCP/HTTP и WS Шрифт (требуется перезагрузка) Скопируйте файл шрифта TTF в каталог guiFonts, перезапустите настройки HTTP port=socks port+1 Установите это с правами администратора Размер шрифта Включить аппаратное ускорение (требуется перезагрузка) Active Proxy ================================================ FILE: v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx ================================================  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 批量导出订阅内容至剪贴板成功 批量导出分享URL至剪贴板成功 请先检查服务器设置 配置格式不正确 注意,自定义配置完全依赖您自己的配置,不能使用所有设置功能。如需使用系统代理请手动修改监听端口。 下载开始... 下载 是否下载? {0} 转换配置文件失败 生成默认配置文件失败 获取默认配置失败 导入自定义配置服务器失败 读取配置文件失败 请填写正确格式服务器端口 请正确填写KCP参数 请填写本地监听端口 请填写密码 请填写服务器地址 请填写用户ID 不是正确的客户端配置文件,请检查 不是正确的配置,请检查 不是正确的服务端配置文件,请检查 初始化配置 {0} 已是最新版本。 {0} 已是最新版本。 地址 加密方式 端口 类型 订阅分组 今日下载 今日上传 总下载 总上传 传输协议 清除原订阅内容 下载Core成功 导入订阅内容失败 获取订阅内容成功 未设置有效的订阅 解析{0}成功 开始获取订阅内容 开始更新 {0}... 无效的订阅内容 正在解压...... 未更新任何内容 更新订阅开始 更新Core成功 更新Core成功!正在重启服务... 非VMess或ss协议 非标准服务,此功能无效 在文件夹 ({0}) 下未找到Core文件 (文件名:{1}),请下载后放入文件夹,下载地址: {2} 扫描完成,未发现有效二维码 操作失败,请检查重试 请填写别名 请选择加密方式 请选择协议 请先选择服务器 服务器去重完成。原数量: {0},现数量: {1} 是否确定移除服务器? 客户端配置文件保存在:{0} 启动服务({0})... 配置成功 {0} 成功导入自定义配置服务器 成功从剪贴板导入 {0} 个服务器 扫描导入URL成功 当前服务的真连接延迟: {0} ms 操作成功 请先选择规则 是否确定移除规则? {0},必填其中一项. 别名 可选地址(Url) 数量 请填写Url 是否追加规则?选择是则追加,选择否则替换 下载 GeoFile: {0} 成功 信息 自定义图标 请填写正确的自定义DNS *ws path *h2 path *QUIC 加密密钥 *grpc serviceName *http host中间逗号(,)分隔 *ws host *h2 host中间逗号(,)分隔 *QUIC 加密方式 *tcp伪装类型 *kcp伪装类型 *QUIC伪装类型 *grpc 模式 TLS *Kcp seed 注册全局热键 {0} 失败,原因 {1} 注册全局热键 {0} 成功 未分组服务器 所有 请浏览导入服务器配置 系统代理 测试中... 服务器太多,请打开主界面操作 局域网 本地 没有更新任何内容 为此,程序必须在 "Administrator" 中运行 链接无效 要执行此操作,必须重新启动程序 ! 服务器过滤器,按回车执行 检查更新 关闭 退出 全局热键设置 帮助 参数设置 推广 重启服务 路由设置 服务器 设置 更新当前订阅(不通过代理) 更新当前订阅(通过代理) 订阅分组 订阅分组设置 更新全部订阅(不通过代理) 更新全部订阅(通过代理) 系统代理 清除系统代理 不改变系统代理 Pac模式 自动配置系统代理 颜色 暗黑模式 语言(重启) 从剪贴板导入批量URL (Ctrl+V) 扫描屏幕上的二维码 (Ctrl+S) 克隆所选服务器 移除重复的服务器 移除所选服务器(多选) (Delete) 设为活动服务器 (Enter) 清除所有服务统计数据 测试服务器延迟Ping(多选) (Ctrl+P) 测试服务器真连接延迟(多选) (Ctrl+R) 按测试结果排序 测试服务器速度(多选) (Ctrl+T) 测试服务器延迟Tcping(多选) (Ctrl+O) 测试当前服务状态 导出所选服务器为客户端配置 批量导出分享URL至剪贴板(多选) (Ctrl+C) 批量导出订阅内容至剪贴板(多选) 添加自定义配置服务器 添加[Shadowsocks]服务器 添加[Socks]服务器 添加[Trojan]服务器 添加[VLESS]服务器 添加[VMess]服务器 全选 (Ctrl+A) 清除所有 复制 (Ctrl+C) 复制所有 设置信息过滤器 全选 (Ctrl+A) 添加 删除 编辑 分享 启用更新 排序 User Agent(可选) 取消 确定 底层传输方式(transport) 地址(address) 跳过证书验证(allowInsecure) Alpn 额外ID(alterId) Fingerprint 伪装类型(type) 用户ID(id) 传输协议(network) 路径(path) 端口(port) 别名(remarks) 伪装域名(host) 加密方式(security) SNI 传输层安全(TLS) *默认tcp,选错会无法连接 Core类型 流控(flow) 生成 密码(password) 密码(可选) 用户ID(id) 加密方式(encryption) 用户名(可选) 加密方式(encryption) Socks端口 * 自定义配置的Socks端口值,可不设置;当设置此值后,将使用Sing-box额外启动一个前置Socks服务,提供分流和速度显示等功能 浏览 编辑 高级代理设置, 协议选择(可选) 允许来自局域网的连接 启动后隐藏窗口 自动更新Geo文件的间隔(单位小时) Core: 基础设置 V2ray DNS设置 Core: KCP设置 Core类型设置 默认跳过证书验证(allowInsecure) Outbound Freedom domainStrategy 自动调整服务器列宽在更新订阅后 检查Pre-Release更新(请谨慎启用) 例外 例外. 对于下列字符开头的地址不使用代理配置文件:使用分号(;)分隔 本地http监听端口 更新Core时忽略Geo文件 去重时保留序号较小的项 启用日志 日志等级 开启Mux多路复用 v2rayN 设置 认证密码 自定义DNS(可多个,用逗号(,)分隔) 解除Win10 UWP应用回环代理限制 开启流量探测 本地socks监听端口 开机启动(可能会不成功) 启用统计(实时网速显示,需重启) 统计刷新频率(单位秒) 订阅转换网址(可选) 系统代理设置 启用安全协议TLS v1.3 (订阅/检查更新) 托盘右键菜单服务器展示数量限制 开启UDP 认证用户名 清除系统代理 显示主界面 全局热键设置 直接按键盘进行设置, 重启后生效 不改变系统代理 重置 自动配置系统代理 Pac模式 分享服务器 (Ctrl+F) 路由 以非管理员身份运行 以管理员身份运行 下移至底 (B) 下移 (D) 上移至顶 (T) 上移 (U) 过滤器, 支持正则 {0} 官网 高级功能 添加规则集 一键导入高级规则 移除所选规则 (Delete) 设为活动规则 (Enter) 基础功能 一键导入基础规则 域名匹配算法 域名解析策略 启用高级功能 3.阻止的Domain或IP 2.直连的Domain或IP 1.代理的Domain或IP 预定义规则集列表 *设置的路由规则,用逗号(,)分隔;正则中的逗号用<COMMA>替代 从剪贴板中导入规则 从文件中导入规则 从订阅Url中导入规则 规则集设置 添加规则 导出所选规则至剪贴板 规则列表 移除所选规则 (Delete) 路由规则详情设置 保存时Domain和IP自动排序 规则详细说明文档 支持填写DnsObject,JSON格式,点击查看文档 普通分组此处请留空 路由设置改变 系统代理设置改变 RouteOnly 一键多线程测试延迟和速度 (Ctrl+E) 延迟(ms) 速度(M/s) 运行Core失败,请看日志 别名正则过滤 显示日志 导入旧的配置文件guiNConfig 启用Tun模式 为局域网开启新的端口 Tun模式设置 直连的IP CIDR,用逗号(,)分隔 直连的进程名,用逗号(,)分隔 显示控制台 移至订阅分组 自定义配置模板 启用服务器拖放排序(需重启) 自动刷新 跳过测试 编辑服务器 (Ctrl+D) 主界面双击设为活动服务器 测试完成 默认TLS指纹(fingerprint) 用户代理(User-Agent) 仅对tcp/http、ws协议生效 当前字体(需重启) 拷贝字体TTF文件到目录guiFonts,重启设置 http端口=socks端口+1 以管理员权限设置此项,在启动后获得管理员权限 字体大小 代理的IP CIDR,用逗号(,)分隔 代理的进程名,用逗号(,)分隔 绕行模式 启用:路由无匹配则最终代理 测速单个超时值 测速文件地址 DNS对象,例如 {"servers":[]} 移至上下 PublicKey ShortId SpiderX 启用硬件加速(需重启) 等待测试中... 当有异常断流时请关闭 未启用更新,跳过此订阅 以管理员身份重启 更多地址(url),用逗号(,)分隔;订阅转换将失效 自动更新间隔(分钟) 启用日志存到文件 订阅转换目标类型 不需要转换时请留空 DNS设置 Sing-box DNS设置 请填写 DNS JSON 结构,点击查看文档 点击导入默认DNS配置 Sing-box域名解析策略 Active Proxy ================================================ FILE: v2rayN/v2rayN/Sample/SampleClientConfig ================================================ { "log": { "access": "Vaccess.log", "error": "Verror.log", "loglevel": "warning" }, "inbounds": [ { "tag": "tag1", "port": 10808, "protocol": "socks", "listen": "127.0.0.1", "settings": { "auth": "noauth", "udp": true }, "sniffing": { "enabled": true, "destOverride": [ "http", "tls" ] } }, { "tag": "tag2", "port": 10809, "protocol": "http", "listen": "127.0.0.1", "settings": { "allowTransparent": false }, "sniffing": { "enabled": true, "destOverride": [ "http", "tls" ] } }, { "tag": "tag3", "port": 10809, "protocol": "http", "listen": "127.0.0.1", "settings": { "allowTransparent": false }, "sniffing": { "enabled": true, "destOverride": [ "http", "tls" ] } } ], "outbounds": [ { "tag": "proxy", "protocol": "vmess", "settings": { "vnext": [ { "address": "v2ray.cool", "port": 10086, "users": [ { "id": "a3482e88-686a-4a58-8126-99c9df64b7bf", "security": "auto" } ] } ], "servers": [ { "address": "v2ray.cool", "method": "chacha20", "ota": false, "password": "123456", "port": 10086, "level": 1 } ] }, "streamSettings": { "network": "tcp" }, "mux": { "enabled": false } }, { "protocol": "freedom", "settings": {}, "tag": "direct" }, { "protocol": "blackhole", "tag": "block", "settings": { "response": { "type": "http" } } } ], "routing": { "domainStrategy": "IPIfNonMatch", "rules": [ { "inboundTag": [ "api" ], "outboundTag": "api", "type": "field" } ], "balancers": [] } //, //"observatory": { //"subjectSelector": ["balancer"], //"probeURL": "http://www.google.com/generate_204", //"probeInterval": "1m" //} } ================================================ FILE: v2rayN/v2rayN/Sample/SampleHttprequest ================================================ {"version":"1.1","method":"GET","path":[$requestPath$],"headers":{"Host":[$requestHost$],"User-Agent":[$requestUserAgent$],"Accept-Encoding":["gzip, deflate"],"Connection":["keep-alive"],"Pragma":"no-cache"}} ================================================ FILE: v2rayN/v2rayN/Sample/SampleHttpresponse ================================================ {"version":"1.1","status":"200","reason":"OK","headers":{"Content-Type":["application/octet-stream","video/mpeg"],"Transfer-Encoding":["chunked"],"Connection":["keep-alive"],"Pragma":"no-cache"}} ================================================ FILE: v2rayN/v2rayN/Sample/SampleInbound ================================================ { "tag": "tag1", "port": 10808, "protocol": "socks", "listen": "127.0.0.1", "settings": { "auth": "noauth", "udp": true, "allowTransparent": false }, "sniffing": { "enabled": true, "destOverride": [ "http", "tls" ] } } ================================================ FILE: v2rayN/v2rayN/Sample/SingboxSampleClientConfig ================================================ { "log": { "level": "debug", "timestamp": true }, "inbounds": [ { "type": "socks", "tag": "socks", "listen": "127.0.0.1", "listen_port": 10000 } ], "outbounds": [ { "type": "vless", "tag": "proxy", "server": "", "server_port": 443 }, { "type": "direct", "tag": "direct" }, { "type": "block", "tag": "block" } ], "route": { "rules": [] } } ================================================ FILE: v2rayN/v2rayN/Sample/custom_routing_black ================================================ [ { "outboundTag": "proxy", "domain": [ "domain:example.com", "domain:example2.com" ] }, { "type": "field", "port": "", "outboundTag": "block", "domain": [ "geosite:category-ads-all" ] }, { "type": "field", "port": "", "outboundTag": "proxy", "domain": [ "tld-!ir" ] }, { "type": "field", "port": "", "outboundTag": "proxy", "ip": [ "109.239.140.0/24", "149.154.160.0/22", "149.154.164.0/22", "149.154.168.0/22", "149.154.172.0/22", "67.198.55.0/24", "91.108.12.0/22", "91.108.16.0/22", "91.108.20.0/22", "91.108.20.0/23", "91.108.4.0/22", "91.108.56.0/22", "91.108.56.0/23", "91.108.8.0/22", "95.161.64.0/20", "95.161.84.0/23", "2001:67c:4e8::/48", "2001:b28:f23c::/48", "2001:b28:f23d::/48", "2001:b28:f23f::/48", "2001:b28:f242::/48" ] }, { "type": "field", "port": "", "outboundTag": "proxy", "ip": [ "geoip:facebook", "geoip:fastly", "geoip:netflix", "geoip:telegram", "geoip:twitter", "geoip:ae", "geoip:au", "geoip:br", "geoip:ca", "geoip:de", "geoip:dk", "geoip:es", "geoip:fi", "geoip:fr", "geoip:gb", "geoip:gr", "geoip:hk", "geoip:id", "geoip:il", "geoip:in", "geoip:iq", "geoip:it", "geoip:jp", "geoip:kr", "geoip:mo", "geoip:my", "geoip:nl", "geoip:no", "geoip:nz", "geoip:ph", "geoip:ru", "geoip:sa", "geoip:sg", "geoip:th", "geoip:tr", "geoip:tw", "geoip:us", "geoip:vn" ] }, { "type": "field", "port": "0-65535", "outboundTag": "direct" } ] ================================================ FILE: v2rayN/v2rayN/Sample/custom_routing_global ================================================ [ { "port": "0-65535", "outboundTag": "proxy" } ] ================================================ FILE: v2rayN/v2rayN/Sample/custom_routing_locked ================================================ [ { "domain": [ "geosite:google" ], "outboundTag": "proxy" }, { "outboundTag": "direct", "domain": [ "domain:example-example.com", "domain:example-example2.com" ] }, { "outboundTag": "block", "domain": [ "geosite:category-ads-all" ] } ] ================================================ FILE: v2rayN/v2rayN/Sample/custom_routing_rules ================================================ [{ "remarks": "block", "outboundTag": "block", "domain": [ "geosite:category-ads-all" ] }, { "remarks": "direct", "outboundTag": "direct", "domain": [ "geosite:ir" ] }, { "remarks": "direct", "outboundTag": "direct", "ip": [ "geoip:private", "geoip:ir" ] }, { "remarks": "proxy", "port": "0-65535", "outboundTag": "proxy" } ] ================================================ FILE: v2rayN/v2rayN/Sample/custom_routing_white ================================================ [ { "outboundTag": "direct", "domain": [ "domain:example.com", "domain:example2.com" ] }, { "type": "field", "outboundTag": "block", "domain": [ "geosite:category-ads-all" ] }, { "type": "field", "outboundTag": "direct", "domain": [ "geosite:private", "geosite:apple@cn", "geosite:google@cn", "geosite:tld-cn", "tld-ir" ] }, { "type": "field", "outboundTag": "proxy", "domain": [ "geoip:!ir" ] }, { "type": "field", "outboundTag": "direct", "ip": [ "geoip:private", "geoip:cn", "geoip:ir" ], "domain": [] }, { "type": "field", "port": "0-65535", "outboundTag": "proxy" } ] ================================================ FILE: v2rayN/v2rayN/Sample/dns_singbox_normal ================================================ { "servers": [ { "tag": "remote", "address": "tcp://8.8.8.8", "detour": "proxy" }, { "tag": "local", "address": "223.5.5.5", "detour": "direct" }, { "tag": "block", "address": "rcode://success" } ], "rules": [ { "geosite": [ "cn" ], "server": "local" }, { "geosite": [ "category-ads-all" ], "server": "block" } ] } ================================================ FILE: v2rayN/v2rayN/Sample/dns_v2ray_normal ================================================ { "hosts": { "dns.google": "8.8.8.8", "proxy.example.com": "127.0.0.1" }, "servers": [ { "address": "223.5.5.5", "domains": [ "geosite:cn" ], "expectIPs": [ "geoip:cn" ] }, "1.1.1.1", "8.8.8.8", "https://dns.google/dns-query" ] } ================================================ FILE: v2rayN/v2rayN/Sample/tun_singbox ================================================ { "log": { "disabled": $log_disabled$, "level": "debug", $log_output$ "timestamp": true }, "dns": $dns_object$ , "inbounds": [ { "type": "tun", "tag": "tun-in", "interface_name": "singbox_tun", "inet4_address": "172.19.0.1/30", "mtu": $mtu$, "auto_route": true, "strict_route": $strict_route$, "stack": "$stack$", "sniff": true } ], "outbounds": [ { "type": "socks", "tag": "proxy", "udp_fragment": true, "server": "127.0.0.1", "server_port": $socksPort$ }, { "type": "block", "tag": "block" }, { "type": "direct", "tag": "direct" }, { "type": "dns", "tag": "dns_out" } ], "route": { "auto_detect_interface": true, "rules": [ { "inbound": "dns_in", "outbound": "dns_out" }, { "protocol": "dns", "outbound": "dns_out" }, { "network": "udp", "port": [ 135, 137, 138, 139, 5353 ], "outbound": "block" }, { "ip_cidr": [ "224.0.0.0/3", "ff00::/8" ], "outbound": "block" }, { "source_ip_cidr": [ "224.0.0.0/3", "ff00::/8" ], "outbound": "block" }, { "port": 53, "process_name": [ $dnsProcessName$], "outbound": "dns_out" }, { "process_name": [ $directProcessName$], "outbound": "direct" } $ruleDirectIPs$ $ruleDirectProcess$ $ruleProxyIPs$ $ruleProxyProcess$ $ruleFinally$ ] } } ================================================ FILE: v2rayN/v2rayN/Sample/tun_singbox_dns ================================================ { "servers": [ { "tag": "remote", "address": "tcp://8.8.8.8", "detour": "proxy" }, { "tag": "local", "address": "223.5.5.5", "detour": "direct" }, { "tag": "block", "address": "rcode://success" } ], "rules": [ { "geosite": [ "cn" ], "server": "local", "disable_cache": true }, { "geosite": [ "category-ads-all" ], "server": "block", "disable_cache": true } ], "strategy": "ipv4_only" } ================================================ FILE: v2rayN/v2rayN/Sample/tun_singbox_inbound ================================================ { "type":"tun", "tag":"tun-in", "interface_name":"singbox_tun", "inet4_address":"172.19.0.1/30", "mtu":9000, "auto_route":true, "strict_route":false, "stack":"system", "sniff":true } ================================================ FILE: v2rayN/v2rayN/Sample/tun_singbox_rules ================================================ [ { "inbound": [ "dns_in" ], "outbound": "dns_out" }, { "protocol": [ "dns" ], "outbound": "dns_out" }, { "network": "udp", "port": [ 135, 137, 138, 139, 5353 ], "outbound": "block" }, { "ip_cidr": [ "224.0.0.0/3", "ff00::/8" ], "outbound": "block" }, { "source_ip_cidr": [ "224.0.0.0/3", "ff00::/8" ], "outbound": "block" } ] ================================================ FILE: v2rayN/v2rayN/Tool/DeepLinking.cs ================================================ using Microsoft.Win32; using v2rayN.Handler; namespace v2rayN.Tool { public class DeepLinking { const string FriendlyName = "HiddifyN"; const string SchemeSeperator = "://"; readonly static string applicationLocation = Utils.GetExePath(); public static void RegisterSchemes() { foreach (var scheme in System.Enum.GetNames(typeof(Scheme))) { // If scheme registered we just skip it if (CheckSchemeRegistered(scheme)) { continue; } using (var key = Registry.CurrentUser.CreateSubKey("SOFTWARE\\Classes\\" + scheme)) { // Replace typeof(App) by the class that contains the Main method or any class located in the project that produces the exe. // or replace typeof(App).Assembly.Location by anything that gives the full path to the exe key.SetValue("", "URL:" + FriendlyName); key.SetValue("URL Protocol", ""); using (var defaultIcon = key.CreateSubKey("DefaultIcon")) { defaultIcon.SetValue("", applicationLocation + ",1"); } using (var commandKey = key.CreateSubKey(@"shell\open\command")) { commandKey.SetValue("", "\"" + applicationLocation + "\" \"%1\""); } } } } public static bool CheckSchemeRegistered(string scheme) { using (var key = Registry.CurrentUser.CreateSubKey("SOFTWARE\\Classes\\" + scheme)) { if (key?.GetValue("")?.ToString() == "URL:" + FriendlyName) { using (var defaultIcon = key.OpenSubKey("DefaultIcon")) { if (defaultIcon?.GetValue("").ToString() == applicationLocation + ",1") { using (var commandKey = key.OpenSubKey(@"shell\open\command")) { if (commandKey?.GetValue("").ToString() == "\"" + applicationLocation + "\" \"%1\"") { return true; } } } } } } return false; } public static (bool, string?) IsUriForProgram(string uri) { uri = uri.ToLower(); foreach (var scheme in System.Enum.GetNames(typeof(Scheme))) { if (uri.StartsWith(scheme + SchemeSeperator)) { return (true, scheme); } } return (false, null); } private static (Protocol?, string?) ParseProtocol(string uri) { Protocol protocol = new Protocol(); string err = null; // Parse Vless Uri if (uri.StartsWith("vless" + SchemeSeperator)) { protocol.Uri = uri; protocol.Scheme = Scheme.vless; } // Parse Vmess Uri else if (uri.StartsWith("vmess" + SchemeSeperator)) { protocol.Uri = uri; protocol.Scheme = Scheme.vmees; } // Parse Shadowsocks(ss) Uri else if (uri.StartsWith("ss" + SchemeSeperator)) { protocol.Uri = uri; protocol.Scheme = Scheme.ss; } // Parse Trojan Uri else if (uri.StartsWith("trojan" + SchemeSeperator)) { protocol.Uri = uri; protocol.Scheme = Scheme.trojan; } // Handle Unexcepted Uri else { return (res: null, err: $"The {uri} is not supported in deep linking"); } return (protocol, err); } private static (Subscription?, string?) ParseSubscription(string uri) { // Valid uri sample: hiddify://install-sub?url=domain.com/path/clash.yml&name=sub_name if (!uri.Contains("url=")) { return (null, "Invalid uri"); } // Extract url //var url Utils.ExtractUrlParameterFromUri(uri); #region Download sub link data //// Download url data //string data = ""; //string err = ""; //var task = Task.Run(async () => //{ // try // { // var downloader = new DownloadHandle(); // // Download through proxy // string url_res = await downloader.TryDownloadString(subscription.Url, true, ""); // if (Utils.IsNullOrEmpty(url_res.Trim())) // { // // Download without proxy // url_res = await downloader.TryDownloadString(subscription.Url, false, ""); // } // data = url_res; // } // catch (Exception e) // { // err = e.Message; // } //}); //task.Wait(); //if (err != "") //{ // return (null, err); //} //if (Utils.IsNullOrEmpty(data.Trim())) //{ // return (null, "Error occurred getting url data"); //} //subscription.Data = data; #endregion Subscription subscription = new Subscription(); subscription.Url = Utils.ChangeHiddifySubDeeplinkToNormalSubUri(uri); return (subscription, ""); } private static bool IsUriSub(string uri) { if (uri.StartsWith("hiddify://install-sub")) { return true; } return false; } public static (ParseResult? res, string? err) ParseUri(string uri) { ParseResult result = new ParseResult(); string err = null; // If the uri is a subscription link we should download it and then add it // If the uri is just a protocol link, we have nothing much to do if (IsUriSub(uri)) { (result.subscription,err) = ParseSubscription(uri); } else { (result.protocol,err) = ParseProtocol(uri); } if (err != null && err != "") { return (null, err); } // Return result (error field is null) return (result, null); } } public class ParseResult { public Protocol? protocol { get; set; } public Subscription? subscription { get; set; } } public class Protocol { // It will be extracted when it's getting add //public string? Name { get; set; } public string Uri { get; set; } // It's useless for now public Scheme Scheme { get; set; } } public class Subscription { // Name of the sub will be extracted when it's getting add //public string Name { get; set; } public string Url { get; set; } // We don't download sub link data, we just imoprt it and then update the sub //public string Data { get; set; } } public enum Scheme { // Clash will be regarded as a subscription //clash vless, vmees, ss, trojan, // The program main scheme hiddify, } } ================================================ FILE: v2rayN/v2rayN/Tool/FileManager.cs ================================================ using System.IO; using System.IO.Compression; using System.Text; namespace v2rayN.Tool { public static class FileManager { public static bool ByteArrayToFile(string fileName, byte[] content) { try { File.WriteAllBytes(fileName, content); return true; } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } return false; } public static void UncompressFile(string fileName, byte[] content) { try { using FileStream fs = File.Create(fileName); using GZipStream input = new(new MemoryStream(content), CompressionMode.Decompress, false); input.CopyTo(fs); } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } } public static string NonExclusiveReadAllText(string path) { return NonExclusiveReadAllText(path, Encoding.Default); } public static string NonExclusiveReadAllText(string path, Encoding encoding) { try { using FileStream fs = new(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); using StreamReader sr = new(fs, encoding); return sr.ReadToEnd(); } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); throw; } } public static bool ZipExtractToFile(string fileName, string toPath, string ignoredName) { try { using ZipArchive archive = ZipFile.OpenRead(fileName); foreach (ZipArchiveEntry entry in archive.Entries) { if (entry.Length == 0) { continue; } try { if (!Utils.IsNullOrEmpty(ignoredName) && entry.Name.Contains(ignoredName)) { continue; } entry.ExtractToFile(Path.Combine(toPath, entry.Name), true); } catch (IOException ex) { Utils.SaveLog(ex.Message, ex); } } } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); return false; } return true; } } } ================================================ FILE: v2rayN/v2rayN/Tool/Job.cs ================================================ using System.Diagnostics; using System.Runtime.InteropServices; namespace v2rayN { /* * See: * http://stackoverflow.com/questions/6266820/working-example-of-createjobobject-setinformationjobobject-pinvoke-in-net */ public class Job : IDisposable { private IntPtr handle = IntPtr.Zero; public Job() { handle = CreateJobObject(IntPtr.Zero, null); IntPtr extendedInfoPtr = IntPtr.Zero; JOBOBJECT_BASIC_LIMIT_INFORMATION info = new() { LimitFlags = 0x2000 }; JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new() { BasicLimitInformation = info }; try { int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); extendedInfoPtr = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) throw new Exception(string.Format("Unable to set information. Error: {0}", Marshal.GetLastWin32Error())); } finally { if (extendedInfoPtr != IntPtr.Zero) { Marshal.FreeHGlobal(extendedInfoPtr); } } } public bool AddProcess(IntPtr processHandle) { bool succ = AssignProcessToJobObject(handle, processHandle); if (!succ) { Utils.SaveLog("Failed to call AssignProcessToJobObject! GetLastError=" + Marshal.GetLastWin32Error()); } return succ; } public bool AddProcess(int processId) { return AddProcess(Process.GetProcessById(processId).Handle); } #region IDisposable private bool disposed; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposed) return; disposed = true; if (disposing) { // no managed objects to free } if (handle != IntPtr.Zero) { CloseHandle(handle); handle = IntPtr.Zero; } } ~Job() { Dispose(false); } #endregion IDisposable #region Interop [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] private static extern IntPtr CreateJobObject(IntPtr a, string? lpName); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CloseHandle(IntPtr hObject); #endregion Interop } #region Helper classes [StructLayout(LayoutKind.Sequential)] internal struct IO_COUNTERS { public UInt64 ReadOperationCount; public UInt64 WriteOperationCount; public UInt64 OtherOperationCount; public UInt64 ReadTransferCount; public UInt64 WriteTransferCount; public UInt64 OtherTransferCount; } [StructLayout(LayoutKind.Sequential)] internal struct JOBOBJECT_BASIC_LIMIT_INFORMATION { public Int64 PerProcessUserTimeLimit; public Int64 PerJobUserTimeLimit; public UInt32 LimitFlags; public UIntPtr MinimumWorkingSetSize; public UIntPtr MaximumWorkingSetSize; public UInt32 ActiveProcessLimit; public UIntPtr Affinity; public UInt32 PriorityClass; public UInt32 SchedulingClass; } [StructLayout(LayoutKind.Sequential)] public struct SECURITY_ATTRIBUTES { public UInt32 nLength; public IntPtr lpSecurityDescriptor; public Int32 bInheritHandle; } [StructLayout(LayoutKind.Sequential)] internal struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION { public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; public IO_COUNTERS IoInfo; public UIntPtr ProcessMemoryLimit; public UIntPtr JobMemoryLimit; public UIntPtr PeakProcessMemoryUsed; public UIntPtr PeakJobMemoryUsed; } public enum JobObjectInfoType { AssociateCompletionPortInformation = 7, BasicLimitInformation = 2, BasicUIRestrictions = 4, EndOfJobTimeInformation = 6, ExtendedLimitInformation = 9, SecurityLimitInformation = 5, GroupInformation = 11 } #endregion Helper classes } ================================================ FILE: v2rayN/v2rayN/Tool/Logging.cs ================================================ using NLog; using NLog.Config; using NLog.Targets; using System.IO; namespace v2rayN.Tool { public class Logging { public static void Setup() { LoggingConfiguration config = new(); FileTarget fileTarget = new(); config.AddTarget("file", fileTarget); fileTarget.Layout = "${longdate}-${level:uppercase=true} ${message}"; fileTarget.FileName = Utils.GetLogPath("${shortdate}.txt"); config.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, fileTarget)); LogManager.Configuration = config; } public static void LoggingEnabled(bool enable) { if (!enable) { LogManager.SuspendLogging(); } } public static void ClearLogs() { Task.Run(() => { try { var now = DateTime.Now.AddMonths(-1); var dir = Utils.GetLogPath(); var files = Directory.GetFiles(dir, "*.txt"); foreach (var filePath in files) { var file = new FileInfo(filePath); if (file.CreationTime < now) { try { file.Delete(); } catch { } } } } catch { } }); } } } ================================================ FILE: v2rayN/v2rayN/Tool/QueryableExtension.cs ================================================ using System.Linq.Expressions; using System.Reflection; namespace v2rayN.Tool { public static class QueryableExtension { public static IOrderedQueryable OrderBy(this IQueryable query, string propertyName) { return _OrderBy(query, propertyName, false); } public static IOrderedQueryable OrderByDescending(this IQueryable query, string propertyName) { return _OrderBy(query, propertyName, true); } private static IOrderedQueryable _OrderBy(IQueryable query, string propertyName, bool isDesc) { string methodname = (isDesc) ? "OrderByDescendingInternal" : "OrderByInternal"; var memberProp = typeof(T).GetProperty(propertyName); var method = typeof(QueryableExtension).GetMethod(methodname) .MakeGenericMethod(typeof(T), memberProp.PropertyType); return (IOrderedQueryable)method.Invoke(null, new object[] { query, memberProp }); } public static IOrderedQueryable OrderByInternal(IQueryable query, PropertyInfo memberProperty) {//public return query.OrderBy(_GetLamba(memberProperty)); } public static IOrderedQueryable OrderByDescendingInternal(IQueryable query, PropertyInfo memberProperty) {//public return query.OrderByDescending(_GetLamba(memberProperty)); } private static Expression> _GetLamba(PropertyInfo memberProperty) { if (memberProperty.PropertyType != typeof(TProp)) throw new Exception(); var thisArg = Expression.Parameter(typeof(T)); var lamba = Expression.Lambda>(Expression.Property(thisArg, memberProperty), thisArg); return lamba; } } } ================================================ FILE: v2rayN/v2rayN/Tool/TestSpeed.cs ================================================ using v2rayN; using Newtonsoft; using System.Diagnostics; using Newtonsoft.Json.Linq; using System.Net; using Newtonsoft.Json; using System.Windows.Navigation; namespace HiddifyN.Tool { public class TestSpeed { private string _appHttpProxy; public TestSpeed() { WebProxy p = (WebProxy)Utils.GetAppProxyAddress(); _appHttpProxy = p.Address.OriginalString; } public double? UploadSpeed(bool withProxy = true) { var sInfo = new ProcessStartInfo(); var extra = withProxy ? $"--http-proxy={_appHttpProxy}" : ""; sInfo = new ProcessStartInfo() { FileName = Global.SpeedTestProgramExePath, Arguments = $"--no-download --no-icmp --json {extra}", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true, }; // Start speed tester program and get its output or error and handle it var (stdout, stderr) = Utils.StartProcess(sInfo); if (stdout == null) { return null; } // Parse json result dynamic testerResult = JObject.Parse(ConvertJsonListToObject(stdout.Trim())); // Get download speed as Mbps double uploadSpeed = testerResult.upload; return uploadSpeed; } public double? DownloadSpeed(bool withProxy = true) { var sInfo = new ProcessStartInfo(); var extra = withProxy ? $"--http-proxy={_appHttpProxy}" : ""; sInfo = new ProcessStartInfo() { FileName = Global.SpeedTestProgramExePath, Arguments = $"--no-upload --no-icmp --json {extra}", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true, }; // Start speed tester program and get its output or error and handle it var (stdout, stderr) = Utils.StartProcess(sInfo); if (stdout == null) { return null; } // Parse json result dynamic testerResult = JObject.Parse(ConvertJsonListToObject(stdout.Trim())); // Get download speed as Mbps double downloadSpeed = testerResult.download; return downloadSpeed; } private string ConvertJsonListToObject(string j) { return j.Remove(j.Length- 1,1).Remove(0,1).Trim(); } } } ================================================ FILE: v2rayN/v2rayN/Tool/UI.cs ================================================ using System.Windows; namespace v2rayN { internal class UI { private static readonly string caption = "HiddifyN"; public static void Show(string msg) { MessageBox.Show(msg, caption, MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK); } public static void ShowWarning(string msg) { MessageBox.Show(msg, caption, MessageBoxButton.OK, MessageBoxImage.Warning, MessageBoxResult.OK); } public static void ShowError(string msg) { MessageBox.Show(msg, caption, MessageBoxButton.OK, MessageBoxImage.Error); } public static MessageBoxResult ShowYesNo(string msg) { return MessageBox.Show(msg, caption, MessageBoxButton.YesNo, MessageBoxImage.Question); } } } ================================================ FILE: v2rayN/v2rayN/Tool/Utils.cs ================================================ using Downloader; using Microsoft.Win32; using Microsoft.Win32.TaskScheduler; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NLog; using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.IO; using System.IO.Compression; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Printing.IndexedProperties; using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.Serialization.Formatters.Binary; using System.Security.Cryptography; using System.Security.Policy; using System.Security.Principal; using System.Text; using System.Text.RegularExpressions; using System.Web; using System.Windows; using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using v2rayN.Base; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Tool; using ZXing; using ZXing.Common; using ZXing.QrCode; using ZXing.Windows.Compatibility; using System.Net.Mail; using System.Windows.Data; using System.Globalization; namespace v2rayN { internal class Utils { #region 资源Json操作 /// /// 获取嵌入文本资源 /// /// /// public static string GetEmbedText(string res) { string result = string.Empty; try { Assembly assembly = Assembly.GetExecutingAssembly(); using Stream? stream = assembly.GetManifestResourceStream(res); ArgumentNullException.ThrowIfNull(stream); using StreamReader reader = new(stream); result = reader.ReadToEnd(); } catch (Exception ex) { SaveLog(ex.Message, ex); } return result; } /// /// 取得存储资源 /// /// public static string? LoadResource(string res) { try { if (!File.Exists(res)) return null; return File.ReadAllText(res); } catch (Exception ex) { SaveLog(ex.Message, ex); } return null; } /// /// 反序列化成对象 /// /// /// /// public static T? FromJson(string? strJson) { try { if (string.IsNullOrEmpty(strJson)) { return default; } return JsonConvert.DeserializeObject(strJson); } catch { return default; } } /// /// 序列化成Json /// /// /// public static string ToJson(object? obj, bool indented = true) { string result = string.Empty; try { if (obj == null) { return result; } if (indented) { result = JsonConvert.SerializeObject(obj, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); } else { result = JsonConvert.SerializeObject(obj, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); } } catch (Exception ex) { SaveLog(ex.Message, ex); } return result; } /// /// 保存成json文件 /// /// /// /// public static int ToJsonFile(object? obj, string filePath, bool nullValue = true) { int result; try { using StreamWriter file = File.CreateText(filePath); JsonSerializer serializer; if (nullValue) { serializer = new JsonSerializer() { Formatting = Formatting.Indented }; } else { serializer = new JsonSerializer() { Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore }; } serializer.Serialize(file, obj); result = 0; } catch (Exception ex) { SaveLog(ex.Message, ex); result = -1; } return result; } public static JObject? ParseJson(string strJson) { try { return JObject.Parse(strJson); } catch (Exception ex) { //SaveLog(ex.Message, ex); return null; } } #endregion 资源Json操作 #region 转换函数 /// /// List转逗号分隔的字符串 /// /// /// public static string List2String(List lst, bool wrap = false) { try { if (lst == null) { return string.Empty; } if (wrap) { return string.Join("," + Environment.NewLine, lst); } else { return string.Join(",", lst); } } catch (Exception ex) { SaveLog(ex.Message, ex); return string.Empty; } } /// /// 逗号分隔的字符串,转List /// /// /// public static List String2List(string str) { try { str = str.Replace(Environment.NewLine, ""); return new List(str.Split(',', StringSplitOptions.RemoveEmptyEntries)); } catch (Exception ex) { SaveLog(ex.Message, ex); return new List(); } } /// /// 逗号分隔的字符串,先排序后转List /// /// /// public static List String2ListSorted(string str) { try { str = str.Replace(Environment.NewLine, ""); List list = new(str.Split(',', StringSplitOptions.RemoveEmptyEntries)); list.Sort(); return list; } catch (Exception ex) { SaveLog(ex.Message, ex); return new List(); } } /// /// Base64编码 /// /// /// public static string Base64Encode(string plainText) { try { byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText); return Convert.ToBase64String(plainTextBytes); } catch (Exception ex) { SaveLog("Base64Encode", ex); return string.Empty; } } /// /// Base64解码 /// /// /// public static string Base64Decode(string plainText) { try { plainText = plainText.TrimEx() .Replace(Environment.NewLine, "") .Replace("\n", "") .Replace("\r", "") .Replace('_', '/') .Replace('-', '+') .Replace(" ", ""); if (plainText.Length % 4 > 0) { plainText = plainText.PadRight(plainText.Length + 4 - plainText.Length % 4, '='); } byte[] data = Convert.FromBase64String(plainText); return Encoding.UTF8.GetString(data); } catch (Exception ex) { SaveLog("Base64Decode", ex); return string.Empty; } } /// /// 转Int /// /// /// public static int ToInt(object obj) { try { return Convert.ToInt32(obj); } catch (Exception ex) { //SaveLog(ex.Message, ex); return 0; } } public static bool ToBool(object obj) { try { return Convert.ToBoolean(obj); } catch (Exception ex) { //SaveLog(ex.Message, ex); return false; } } public static string ToString(object obj) { try { return obj?.ToString() ?? string.Empty; } catch (Exception ex) { //SaveLog(ex.Message, ex); return string.Empty; } } /// /// byte 转成 有两位小数点的 方便阅读的数据 /// 比如 2.50 MB /// /// bytes /// 转换之后的数据 /// 单位 public static void ToHumanReadable(long amount, out double result, out string unit) { uint factor = 1024u; //long KBs = amount / factor; long KBs = amount; if (KBs > 0) { // multi KB long MBs = KBs / factor; if (MBs > 0) { // multi MB long GBs = MBs / factor; if (GBs > 0) { // multi GB long TBs = GBs / factor; if (TBs > 0) { result = TBs + ((GBs % factor) / (factor + 0.0)); unit = "TB"; return; } result = GBs + ((MBs % factor) / (factor + 0.0)); unit = "GB"; return; } result = MBs + ((KBs % factor) / (factor + 0.0)); unit = "MB"; return; } result = KBs + ((amount % factor) / (factor + 0.0)); unit = "KB"; return; } else { result = amount; unit = "B"; } } public static string HumanFy(long amount) { ToHumanReadable(amount, out double result, out string unit); return $"{string.Format("{0:f1}", result)} {unit}"; } public static string UrlEncode(string url) { return Uri.EscapeDataString(url); //return HttpUtility.UrlEncode(url); } public static string UrlDecode(string url) { return HttpUtility.UrlDecode(url); } public static string GetMD5(string str) { byte[] byteOld = Encoding.UTF8.GetBytes(str); byte[] byteNew = MD5.HashData(byteOld); StringBuilder sb = new(32); foreach (byte b in byteNew) { sb.Append(b.ToString("x2")); } return sb.ToString(); } public static ImageSource IconToImageSource(Icon icon) { return Imaging.CreateBitmapSourceFromHIcon( icon.Handle, new System.Windows.Int32Rect(0, 0, icon.Width, icon.Height), BitmapSizeOptions.FromEmptyOptions()); } /// /// idn to idc /// /// /// public static string GetPunycode(string url) { if (string.IsNullOrWhiteSpace(url)) { return url; } try { Uri uri = new(url); if (uri.Host == uri.IdnHost) { return url; } else { return url.Replace(uri.Host, uri.IdnHost); } } catch { return url; } } public static bool IsBase64String(string plainText) { var buffer = new Span(new byte[plainText.Length]); return Convert.TryFromBase64String(plainText, buffer, out int _); } public static string Convert2Comma(string text) { if (string.IsNullOrWhiteSpace(text)) { return text; } return text.Replace(",", ",").Replace(Environment.NewLine, ","); } #endregion 转换函数 #region 数据检查 /// /// 判断输入的是否是数字 /// /// /// public static bool IsNumberic(string oText) { try { int var1 = ToInt(oText); return true; } catch (Exception ex) { SaveLog(ex.Message, ex); return false; } } /// /// 文本 /// /// /// public static bool IsNullOrEmpty(string? text) { if (string.IsNullOrEmpty(text)) { return true; } if (text == "null") { return true; } return false; } /// /// 验证IP地址是否合法 /// /// public static bool IsIP(string ip) { //如果为空 if (IsNullOrEmpty(ip)) { return false; } //清除要验证字符串中的空格 //ip = ip.TrimEx(); //可能是CIDR if (ip.IndexOf(@"/") > 0) { string[] cidr = ip.Split('/'); if (cidr.Length == 2) { if (!IsNumberic(cidr[0])) { return false; } ip = cidr[0]; } } //模式字符串 string pattern = @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$"; //验证 return IsMatch(ip, pattern); } /// /// 验证Domain地址是否合法 /// /// public static bool IsDomain(string domain) { //如果为空 if (IsNullOrEmpty(domain)) { return false; } return Uri.CheckHostName(domain) == UriHostNameType.Dns; } /// /// 验证输入字符串是否与模式字符串匹配,匹配返回true /// /// 输入字符串 /// 模式字符串 public static bool IsMatch(string input, string pattern) { return Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase); } public static bool IsIpv6(string ip) { if (IPAddress.TryParse(ip, out IPAddress? address)) { return address.AddressFamily switch { AddressFamily.InterNetwork => false, AddressFamily.InterNetworkV6 => true, _ => false, }; } return false; } #endregion 数据检查 #region 开机自动启动 /// /// 开机自动启动 /// /// /// public static void SetAutoRun(bool run) { try { var autoRunName = $"{Global.AutoRunName}_{GetMD5(StartupPath())}"; //delete first RegWriteValue(Global.AutoRunRegPath, autoRunName, ""); if (IsAdministrator()) { AutoStart(autoRunName, "", ""); } if (run) { string exePath = $"\"{GetExePath()}\""; if (IsAdministrator()) { AutoStart(autoRunName, exePath, ""); } else { RegWriteValue(Global.AutoRunRegPath, autoRunName, exePath); } } } catch (Exception ex) { SaveLog(ex.Message, ex); } } /// /// 是否已经设置开机自动启动 /// /// public static bool IsAutoRun() { try { //clear if (!RegReadValue(Global.AutoRunRegPath, Global.AutoRunName, "").IsNullOrEmpty()) { RegWriteValue(Global.AutoRunRegPath, Global.AutoRunName, ""); } string value = RegReadValue(Global.AutoRunRegPath, Global.AutoRunName, ""); string exePath = GetExePath(); if (value == exePath || value == $"\"{exePath}\"") { return true; } } catch (Exception ex) { SaveLog(ex.Message, ex); } return false; } /// /// 获取启动了应用程序的可执行文件的路径 /// /// public static string GetPath(string fileName) { string startupPath = StartupPath(); if (IsNullOrEmpty(fileName)) { return startupPath; } return Path.Combine(startupPath, fileName); } /// /// 获取启动了应用程序的可执行文件的路径及文件名 /// /// public static string GetExePath() { return Environment.ProcessPath; } public static string StartupPath() { return AppDomain.CurrentDomain.BaseDirectory; } public static string? RegReadValue(string path, string name, string def) { RegistryKey? regKey = null; try { regKey = Registry.CurrentUser.OpenSubKey(path, false); string? value = regKey?.GetValue(name) as string; if (IsNullOrEmpty(value)) { return def; } else { return value; } } catch (Exception ex) { SaveLog(ex.Message, ex); } finally { regKey?.Close(); } return def; } public static void RegWriteValue(string path, string name, object value) { RegistryKey? regKey = null; try { regKey = Registry.CurrentUser.CreateSubKey(path); if (IsNullOrEmpty(value.ToString())) { regKey?.DeleteValue(name, false); } else { regKey?.SetValue(name, value); } } catch (Exception ex) { SaveLog(ex.Message, ex); } finally { regKey?.Close(); } } /// /// 判断.Net Framework的Release是否符合 /// (.Net Framework 版本在4.0及以上) /// /// 需要的版本4.6.2=394802;4.8=528040 /// public static bool CheckForDotNetVersion(int release = 528040) { const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\"; using RegistryKey? ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey); if (ndpKey?.GetValue("Release") != null) { return (int)ndpKey.GetValue("Release") >= release; } return false; } /// /// Auto Start via TaskService /// /// /// /// /// public static void AutoStart(string taskName, string fileName, string description) { if (string.IsNullOrEmpty(taskName)) { return; } string TaskName = taskName; var logonUser = WindowsIdentity.GetCurrent().Name; string taskDescription = description; string deamonFileName = fileName; using var taskService = new TaskService(); var tasks = taskService.RootFolder.GetTasks(new Regex(TaskName)); foreach (var t in tasks) { taskService.RootFolder.DeleteTask(t.Name); } if (string.IsNullOrEmpty(fileName)) { return; } var task = taskService.NewTask(); task.RegistrationInfo.Description = taskDescription; task.Settings.DisallowStartIfOnBatteries = false; task.Settings.StopIfGoingOnBatteries = false; task.Settings.RunOnlyIfIdle = false; task.Settings.IdleSettings.StopOnIdleEnd = false; task.Settings.ExecutionTimeLimit = TimeSpan.Zero; task.Triggers.Add(new LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(10) }); task.Principal.RunLevel = TaskRunLevel.Highest; task.Actions.Add(new ExecAction(deamonFileName)); taskService.RootFolder.RegisterTaskDefinition(TaskName, task); } #endregion 开机自动启动 #region 测速 /// /// 取得本机 IP Address /// /// //public static List GetHostIPAddress() //{ // List lstIPAddress = new List(); // try // { // IPHostEntry IpEntry = Dns.GetHostEntry(Dns.GetHostName()); // foreach (IPAddress ipa in IpEntry.AddressList) // { // if (ipa.AddressFamily == AddressFamily.InterNetwork) // lstIPAddress.Add(ipa.ToString()); // } // } // catch (Exception ex) // { // SaveLog(ex.Message, ex); // } // return lstIPAddress; //} public static void SetSecurityProtocol(bool enableSecurityProtocolTls13) { if (enableSecurityProtocolTls13) { ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13; } else { ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12; } ServicePointManager.DefaultConnectionLimit = 256; } public static bool PortInUse(int port) { bool inUse = false; try { IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties(); IPEndPoint[] ipEndPoints = ipProperties.GetActiveTcpListeners(); var lstIpEndPoints = new List(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners()); foreach (IPEndPoint endPoint in ipEndPoints) { if (endPoint.Port == port) { inUse = true; break; } } } catch (Exception ex) { SaveLog(ex.Message, ex); } return inUse; } #endregion 测速 #region 杂项 /// /// 取得版本 /// /// public static string GetVersion(bool blFull = true) { try { string location = GetExePath(); if (blFull) { return string.Format("HiddifyN - V{0} - {1}-Test", FileVersionInfo.GetVersionInfo(location).FileVersion.ToString(), File.GetLastWriteTime(location).ToString("yyyy/MM/dd")); } else { return string.Format("HiddifyN/{0}", FileVersionInfo.GetVersionInfo(location).FileVersion.ToString()); } } catch (Exception ex) { SaveLog(ex.Message, ex); return string.Empty; } } /// /// 深度拷贝 /// /// /// /// public static T DeepCopy(T obj) { object retval; MemoryStream ms = new MemoryStream(); BinaryFormatter bf = new BinaryFormatter(); //序列化成流 bf.Serialize(ms, obj); ms.Seek(0, SeekOrigin.Begin); //反序列化成对象 retval = bf.Deserialize(ms); return (T)retval; } /// /// 获取剪贴板数 /// /// public static string? GetClipboardData() { string? strData = string.Empty; try { IDataObject data = Clipboard.GetDataObject(); if (data.GetDataPresent(DataFormats.UnicodeText)) { strData = data.GetData(DataFormats.UnicodeText)?.ToString(); } return strData; } catch (Exception ex) { SaveLog(ex.Message, ex); } return strData; } /// /// 拷贝至剪贴板 /// /// public static void SetClipboardData(string strData) { try { Clipboard.SetText(strData); } catch { } } /// /// 取得GUID /// /// public static string GetGUID(bool full = true) { try { if (full) { return Guid.NewGuid().ToString("D"); } else { return BitConverter.ToInt64(Guid.NewGuid().ToByteArray(), 0).ToString(); } } catch (Exception ex) { SaveLog(ex.Message, ex); } return string.Empty; } /// /// IsAdministrator /// /// public static bool IsAdministrator() { try { WindowsIdentity current = WindowsIdentity.GetCurrent(); WindowsPrincipal windowsPrincipal = new WindowsPrincipal(current); //WindowsBuiltInRole可以枚举出很多权限,例如系统用户、User、Guest等等 return windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator); } catch (Exception ex) { SaveLog(ex.Message, ex); return false; } } public static string GetDownloadFileName(string url) { var fileName = Path.GetFileName(url); fileName += "_temp"; return fileName; } public static IPAddress? GetDefaultGateway() { return NetworkInterface .GetAllNetworkInterfaces() .Where(n => n.OperationalStatus == OperationalStatus.Up) .Where(n => n.NetworkInterfaceType != NetworkInterfaceType.Loopback) .SelectMany(n => n.GetIPProperties()?.GatewayAddresses) .Select(g => g?.Address) .Where(a => a != null) // .Where(a => a.AddressFamily == AddressFamily.InterNetwork) // .Where(a => Array.FindIndex(a.GetAddressBytes(), b => b != 0) >= 0) .FirstOrDefault(); } public static bool IsGuidByParse(string strSrc) { return Guid.TryParse(strSrc, out Guid g); } public static void ProcessStart(string fileName) { try { Process.Start(new ProcessStartInfo(fileName) { UseShellExecute = true }); } catch (Exception ex) { SaveLog(ex.Message, ex); } } public static void SetDarkBorder(System.Windows.Window window, bool dark) { // Make sure the handle is created before the window is shown IntPtr hWnd = new System.Windows.Interop.WindowInteropHelper(window).EnsureHandle(); int attribute = dark ? 1 : 0; uint attributeSize = (uint)Marshal.SizeOf(attribute); DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, ref attribute, attributeSize); DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, ref attribute, attributeSize); } #endregion 杂项 #region TempPath // return path to store temporary files public static string GetTempPath(string filename = "") { string _tempPath = Path.Combine(StartupPath(), "guiTemps"); if (!Directory.Exists(_tempPath)) { Directory.CreateDirectory(_tempPath); } if (string.IsNullOrEmpty(filename)) { return _tempPath; } else { return Path.Combine(_tempPath, filename); } } public static string UnGzip(byte[] buf) { using MemoryStream sb = new(); using GZipStream input = new(new MemoryStream(buf), CompressionMode.Decompress, false); input.CopyTo(sb); sb.Position = 0; return new StreamReader(sb, Encoding.UTF8).ReadToEnd(); } public static string GetBackupPath(string filename) { string _tempPath = Path.Combine(StartupPath(), "guiBackups"); if (!Directory.Exists(_tempPath)) { Directory.CreateDirectory(_tempPath); } return Path.Combine(_tempPath, filename); } public static string GetConfigPath(string filename = "") { string _tempPath = Path.Combine(StartupPath(), "guiConfigs"); if (!Directory.Exists(_tempPath)) { Directory.CreateDirectory(_tempPath); } if (string.IsNullOrEmpty(filename)) { return _tempPath; } else { return Path.Combine(_tempPath, filename); } } public static string GetBinPath(string filename, ECoreType? coreType = null) { string _tempPath = Path.Combine(StartupPath(), "bin"); if (!Directory.Exists(_tempPath)) { Directory.CreateDirectory(_tempPath); } if (coreType != null) { _tempPath = Path.Combine(_tempPath, coreType.ToString()!); if (!Directory.Exists(_tempPath)) { Directory.CreateDirectory(_tempPath); } } if (string.IsNullOrEmpty(filename)) { return _tempPath; } else { return Path.Combine(_tempPath, filename); } } public static string GetLogPath(string filename = "") { string _tempPath = Path.Combine(StartupPath(), "guiLogs"); if (!Directory.Exists(_tempPath)) { Directory.CreateDirectory(_tempPath); } if (string.IsNullOrEmpty(filename)) { return _tempPath; } else { return Path.Combine(_tempPath, filename); } } public static string GetFontsPath(string filename = "") { string _tempPath = Path.Combine(StartupPath(), "guiFonts"); if (!Directory.Exists(_tempPath)) { Directory.CreateDirectory(_tempPath); } if (string.IsNullOrEmpty(filename)) { return _tempPath; } else { return Path.Combine(_tempPath, filename); } } #endregion TempPath #region Log public static void SaveLog(string strContent) { if (LogManager.IsLoggingEnabled()) { var logger = LogManager.GetLogger("Log1"); logger.Info(strContent); } } public static void SaveLog(string strTitle, Exception ex) { if (LogManager.IsLoggingEnabled()) { var logger = LogManager.GetLogger("Log2"); logger.Debug($"{strTitle},{ex.Message}"); logger.Debug(ex.StackTrace); if (ex?.InnerException != null) { logger.Error(ex.InnerException); } } } #endregion Log #region scan screen public static string ScanScreen(float dpiX, float dpiY) { try { var left = (int)(SystemParameters.WorkArea.Left); var top = (int)(SystemParameters.WorkArea.Top); var width = (int)(SystemParameters.WorkArea.Width / dpiX); var height = (int)(SystemParameters.WorkArea.Height / dpiY); using Bitmap fullImage = new Bitmap(width, height); using (Graphics g = Graphics.FromImage(fullImage)) { g.CopyFromScreen(left, top, 0, 0, fullImage.Size, CopyPixelOperation.SourceCopy); } int maxTry = 10; for (int i = 0; i < maxTry; i++) { int marginLeft = (int)((double)fullImage.Width * i / 2.5 / maxTry); int marginTop = (int)((double)fullImage.Height * i / 2.5 / maxTry); Rectangle cropRect = new(marginLeft, marginTop, fullImage.Width - marginLeft * 2, fullImage.Height - marginTop * 2); Bitmap target = new(width, height); double imageScale = (double)width / (double)cropRect.Width; using (Graphics g = Graphics.FromImage(target)) { g.DrawImage(fullImage, new Rectangle(0, 0, target.Width, target.Height), cropRect, GraphicsUnit.Pixel); } BitmapLuminanceSource source = new(target); BinaryBitmap bitmap = new(new HybridBinarizer(source)); QRCodeReader reader = new(); Result result = reader.decode(bitmap); if (result != null) { string ret = result.Text; return ret; } } } catch (Exception ex) { SaveLog(ex.Message, ex); } return string.Empty; } public static Tuple GetDpiXY(Window window) { IntPtr hWnd = new WindowInteropHelper(window).EnsureHandle(); Graphics g = Graphics.FromHwnd(hWnd); return new(96 / g.DpiX, 96 / g.DpiY); } #endregion scan screen #region Windows API [Flags] public enum DWMWINDOWATTRIBUTE : uint { DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19, DWMWA_USE_IMMERSIVE_DARK_MODE = 20, } [DllImport("dwmapi.dll")] public static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attribute, ref int attributeValue, uint attributeSize); #endregion Windows API // It doesn't really lock the file, because if the program be closed, the file will be unlocked // Instead of that, it will write locked in the file private static void LockMainFormReloadFile() { File.WriteAllText(Global.MainFormReloadFilePath, "locked"); } private static void UnlockMainFormReloadFile() { File.WriteAllText(Global.MainFormReloadFilePath, "unlocked"); } private static bool IsMainFormReloadFileLocked() { if (!File.Exists(Global.MainFormReloadFilePath)) { return false; } string content = File.ReadAllText(Global.MainFormReloadFilePath); if (content == "locked") { return true; } else if (content == "unlocked") { return false; } else { throw new Exception($"the {Global.MainFormReloadFilePath} lock file, abnormaly changed, please delete it"); } } public static void SetMainPageReload() { bool tryAgain = false; do { try { LockMainFormReloadFile(); } catch (Exception) { tryAgain = true; } } while (tryAgain); } public static void UnsetMainPageReload() { bool tryAgain = false; do { try { UnlockMainFormReloadFile(); } catch (Exception) { tryAgain = true; } }while(tryAgain); } public static bool DoesMainPageNeedReload() { return IsMainFormReloadFileLocked(); } public static void ExitSuccess() { System.Windows.Application.Current.Shutdown(); //int id = GetAppProcessID(); //Process.GetProcessById(id).Kill(true); Environment.Exit(0); } public static void ExitError(int err) { System.Windows.Application.Current.Shutdown(); //int id = GetAppProcessID(); //Process.GetProcessById(id).Kill(true); Environment.Exit(err); } public static int GetAppProcessID() { return Process.GetCurrentProcess().Id; } public static IWebProxy GetAppProxyAddress() { var httpPort = LazyConfig.Instance.GetLocalPort(Global.InboundHttp); return new WebProxy(Global.Loopback, httpPort); } public static void RestartProgram(bool asAdmin = false) { new Thread(delegate () { var mainProgramID = GetAppProcessID(); var pInfo = new ProcessStartInfo(); pInfo.FileName = Global.RestartProgramExePath; pInfo.WorkingDirectory = Environment.CurrentDirectory; if (asAdmin) { pInfo.Arguments = $"{mainProgramID} --a"; } else { pInfo.Arguments = $"{mainProgramID}"; } pInfo.CreateNoWindow = true; Process.Start(pInfo); }).Start(); } // I think it's the right way public static bool IsSystemProxyEnabled(ESysProxyType sysProxyType) { if (sysProxyType == ESysProxyType.ForcedChange || sysProxyType == ESysProxyType.Pac) { return true; } return false; } public static string? ExtractNameParameterFromUri(string uri) { // Extract name if (uri.Contains("name=")) { var splitted = uri.Split("name="); if (splitted.Length > 1) { string name = ""; foreach (char c in splitted[1].ToCharArray()) { if (c == '&' || c == '?') { break; } name += c; } return name; } } return null; } public static string? ExtractUrlParameterFromUri(string uri) { var splitted = uri.Split("url="); string? url = ""; if (splitted.Length > 1) { foreach (char c in splitted[1].ToCharArray()) { if (c == '&' || c == '?') { break; } url += c; } } if (Utils.IsNullOrEmpty(url)) { return null; } return url; } public static string ChangeHiddifySubDeeplinkToNormalSubUri(string hiddifySubDepplink) { // Valid uri sample: hiddify://install-sub?url=domain.com/path/clash.yml&name=sub_name // We need after "url=" part // Remove "hiddify://install-sub?" if (hiddifySubDepplink.Contains("url=")) { return System.Web.HttpUtility.UrlDecode(hiddifySubDepplink.Split("url=")[1]); } return hiddifySubDepplink; } public static HttpResponseHeaders? GetUrlResponseHeader(string url, bool useProgramProxy) { HttpClientHandler handler; if (!useProgramProxy) handler = new HttpClientHandler() { UseProxy = false }; else handler = new HttpClientHandler() { UseProxy = true }; using (var client = new HttpClient(handler)) { System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; client.DefaultRequestHeaders.Accept.Clear(); try { var response = client.Send(new HttpRequestMessage(HttpMethod.Head,url)); if (response.StatusCode == HttpStatusCode.OK) { return response.Headers; } } catch (Exception) { return null; } } return null; } public async static Task GetUrlResponseStatusCode(string url,bool useProgramProxy) { HttpClientHandler handler; if (!useProgramProxy) handler = new HttpClientHandler() { UseProxy = false}; else handler = new HttpClientHandler() { UseProxy =true}; using (var client = new HttpClient(handler)) { ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; client.DefaultRequestHeaders.Accept.Clear(); try { var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, url)); return response.StatusCode; } catch (Exception) { return null; } } } public async static Task IsUrlStatusCode204(string url, bool useProgramProxy) { HttpClientHandler handler; if (!useProgramProxy) handler = new HttpClientHandler() { UseProxy = false }; else handler = new HttpClientHandler() { UseProxy = true }; using (var client = new HttpClient(handler)) { ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; client.DefaultRequestHeaders.Accept.Clear(); try { var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, url)); if (response.StatusCode == HttpStatusCode.NoContent) return true; else return false; } catch (Exception) { return false; } } } public static DateTime EpochToDate(long epoch) { return DateTimeOffset.FromUnixTimeSeconds(epoch).DateTime; } public static string? GetHostAndFirstTwoPathInUri(string url) { // For example: // https://domain.com/first/two/all.txt?parameter=value // Will be: // https://domain.com/first/two/ Uri uri = new Uri(url); string[] splitted = uri.AbsolutePath.TrimStart('/').Split('/', 3); if (splitted.Length < 3) { return null; } return uri.Scheme + "://" + uri.Host + '/' + splitted[0] + '/' + splitted[1] + '/'; } // First return value is for stdout and second one is for stderr public static (string?,string?) StartProcess(ProcessStartInfo sInfo) { var errors = new StringBuilder(); var output = new StringBuilder(); var hadError = false; var p = Process.Start(sInfo); p.EnableRaisingEvents = true; p.OutputDataReceived += (s, d) => { output.Append(d.Data); }; p.ErrorDataReceived += (s, d) => { if (!hadError) { hadError = !String.IsNullOrEmpty(d.Data); } errors.Append(d.Data); }; p.BeginErrorReadLine(); p.BeginOutputReadLine(); p.WaitForExit(); string stdout = output.ToString(); string stderr = errors.ToString(); if (p.ExitCode != 0 || hadError) { return (null,stderr); } return (stdout,null); } #region Clash Subscription Info public static SubscriptionInfo? GetSubscriptionInfoFromHeaders(HttpResponseHeaders headers) { if (headers == null) { return null; } SubscriptionInfo clashSubscriptionInfo = new SubscriptionInfo(); IEnumerable userSubInfoValues; if (headers.TryGetValues("Subscription-Userinfo", out userSubInfoValues)) { // Split values foreach (var item in userSubInfoValues.FirstOrDefault().Split(";")) { // Split key and values int equalsSignIndex = item.IndexOf("="); string key = item.Substring(0, equalsSignIndex); string value = item.Substring(equalsSignIndex + 1); if (key == "upload") { long longValue; if (long.TryParse(value, out longValue)) { clashSubscriptionInfo.Upload = longValue; } } else if (key == "download") { long longValue; if (long.TryParse(value, out longValue)) { clashSubscriptionInfo.Download = longValue; } } else if (key == "total") { long longValue; if (long.TryParse(value, out longValue)) { clashSubscriptionInfo.Total = longValue; } } else if (key == "expire") { long longValue; if (long.TryParse(value, out longValue)) { clashSubscriptionInfo.ExpireDate = longValue; } } } } // Get profile web page url from header IEnumerable profileWebPageValue; if (headers.TryGetValues("Profile-Web-Page-Url",out profileWebPageValue)) { string profileWebPageUrl = profileWebPageValue.FirstOrDefault(); if (profileWebPageUrl != null) clashSubscriptionInfo.ProfileWebPageUrl = profileWebPageUrl; } IEnumerable profileTitleValue; if (headers.TryGetValues("Profile-Title", out profileTitleValue)) { string profileTitle = profileTitleValue.FirstOrDefault(); if (profileTitle != null) clashSubscriptionInfo.ProfileTitle = profileTitle; } IEnumerable profileUpdateIntervalValue; if (headers.TryGetValues("Profile-Update-Interval",out profileUpdateIntervalValue)) { int profileUpdateInterval = Convert.ToInt32(profileUpdateIntervalValue.FirstOrDefault()); if (profileUpdateIntervalValue != null) clashSubscriptionInfo.ProfileUpdateInterval = profileUpdateInterval; } return clashSubscriptionInfo; } public int CalculateRemaningExpireDays(DateTime dateTime) { return DateTime.Now.Subtract(dateTime).Days; } #endregion } } ================================================ FILE: v2rayN/v2rayN/ViewModels/AddServer2ViewModel.cs ================================================ using Microsoft.Win32; using ReactiveUI; using ReactiveUI.Fody.Helpers; using ReactiveUI.Validation.Helpers; using Splat; using System.IO; using System.Reactive; using System.Windows; using v2rayN.Base; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; namespace v2rayN.ViewModels { public class AddServer2ViewModel : ReactiveValidationObject { private static Config _config; private NoticeHandler? _noticeHandler; private Window _view; [Reactive] public ProfileItem SelectedSource { get; set; } public ReactiveCommand BrowseServerCmd { get; } public ReactiveCommand EditServerCmd { get; } public ReactiveCommand SaveServerCmd { get; } public bool IsModified { get; set; } public AddServer2ViewModel(ProfileItem profileItem, Window view) { _noticeHandler = Locator.Current.GetService(); _config = LazyConfig.Instance.GetConfig(); if (profileItem.indexId.IsNullOrEmpty()) { SelectedSource = profileItem; } else { SelectedSource = Utils.DeepCopy(profileItem); } _view = view; BrowseServerCmd = ReactiveCommand.Create(() => { BrowseServer(); }); EditServerCmd = ReactiveCommand.Create(() => { EditServer(); }); SaveServerCmd = ReactiveCommand.Create(() => { SaveServer(); }); Utils.SetDarkBorder(view, _config.uiItem.colorModeDark); } private void SaveServer() { string remarks = SelectedSource.remarks; if (Utils.IsNullOrEmpty(remarks)) { UI.Show(ResUI.PleaseFillRemarks); return; } if (Utils.IsNullOrEmpty(SelectedSource.address)) { UI.Show(ResUI.FillServerAddressCustom); return; } var item = LazyConfig.Instance.GetProfileItem(SelectedSource.indexId); if (item is null) { item = SelectedSource; } else { item.remarks = SelectedSource.remarks; item.address = SelectedSource.address; item.coreType = SelectedSource.coreType; item.displayLog = SelectedSource.displayLog; item.preSocksPort = SelectedSource.preSocksPort; } if (ConfigHandler.EditCustomServer(ref _config, item) == 0) { _noticeHandler?.Enqueue(ResUI.OperationSuccess); _view.DialogResult = true; } else { UI.Show(ResUI.OperationFailed); } } private void BrowseServer() { UI.Show(ResUI.CustomServerTips); OpenFileDialog fileDialog = new() { Multiselect = false, Filter = "Config|*.json|YAML|*.yaml;*.yml|All|*.*" }; if (fileDialog.ShowDialog() != true) { return; } string fileName = fileDialog.FileName; if (Utils.IsNullOrEmpty(fileName)) { return; } var item = LazyConfig.Instance.GetProfileItem(SelectedSource.indexId); item ??= SelectedSource; item.address = fileName; if (ConfigHandler.AddCustomServer(ref _config, item, false) == 0) { _noticeHandler?.Enqueue(ResUI.SuccessfullyImportedCustomServer); if (!Utils.IsNullOrEmpty(item.indexId)) { SelectedSource = Utils.DeepCopy(item); } IsModified = true; } else { UI.ShowWarning(ResUI.FailedImportedCustomServer); } } private void EditServer() { var address = SelectedSource.address; if (Utils.IsNullOrEmpty(address)) { UI.Show(ResUI.FillServerAddressCustom); return; } address = Utils.GetConfigPath(address); if (File.Exists(address)) { Utils.ProcessStart(address); } else { _noticeHandler?.Enqueue(ResUI.FailedReadConfiguration); } } } } ================================================ FILE: v2rayN/v2rayN/ViewModels/AddServerViewModel.cs ================================================ using ReactiveUI; using ReactiveUI.Fody.Helpers; using Splat; using System.Reactive; using System.Windows; using v2rayN.Base; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; namespace v2rayN.ViewModels { public class AddServerViewModel : ReactiveObject { private static Config _config; private NoticeHandler? _noticeHandler; private Window _view; [Reactive] public ProfileItem SelectedSource { get; set; } public ReactiveCommand SaveCmd { get; } public AddServerViewModel(ProfileItem profileItem, Window view) { _config = LazyConfig.Instance.GetConfig(); _noticeHandler = Locator.Current.GetService(); _view = view; if (profileItem.id.IsNullOrEmpty()) { profileItem.network = Global.DefaultNetwork; profileItem.headerType = Global.None; profileItem.requestHost = ""; profileItem.streamSecurity = ""; SelectedSource = profileItem; } else { SelectedSource = Utils.DeepCopy(profileItem); } SaveCmd = ReactiveCommand.Create(() => { SaveServer(); }); Utils.SetDarkBorder(view, _config.uiItem.colorModeDark); } private void SaveServer() { if (Utils.IsNullOrEmpty(SelectedSource.remarks)) { UI.Show(ResUI.PleaseFillRemarks); return; } if (Utils.IsNullOrEmpty(SelectedSource.address)) { UI.Show(ResUI.FillServerAddress); return; } var port = SelectedSource.port.ToString(); if (Utils.IsNullOrEmpty(port) || !Utils.IsNumberic(port) || SelectedSource.port <= 0 || SelectedSource.port >= Global.MaxPort) { UI.Show(ResUI.FillCorrectServerPort); return; } if (SelectedSource.configType == EConfigType.Shadowsocks) { if (Utils.IsNullOrEmpty(SelectedSource.id)) { UI.Show(ResUI.FillPassword); return; } if (Utils.IsNullOrEmpty(SelectedSource.security)) { UI.Show(ResUI.PleaseSelectEncryption); return; } } if (SelectedSource.configType != EConfigType.Socks) { if (Utils.IsNullOrEmpty(SelectedSource.id)) { UI.Show(ResUI.FillUUID); return; } } var item = LazyConfig.Instance.GetProfileItem(SelectedSource.indexId); if (item is null) { item = SelectedSource; } else { item.coreType = SelectedSource.coreType; item.remarks = SelectedSource.remarks; item.address = SelectedSource.address; item.port = SelectedSource.port; item.id = SelectedSource.id; item.alterId = SelectedSource.alterId; item.security = SelectedSource.security; item.flow = SelectedSource.flow; item.network = SelectedSource.network; item.headerType = SelectedSource.headerType; item.requestHost = SelectedSource.requestHost; item.path = SelectedSource.path; item.fragment = SelectedSource.fragment; item.streamSecurity = SelectedSource.streamSecurity; item.sni = SelectedSource.sni; item.allowInsecure = SelectedSource.allowInsecure; item.fingerprint = SelectedSource.fingerprint; item.alpn = SelectedSource.alpn; item.publicKey = SelectedSource.publicKey; item.shortId = SelectedSource.shortId; item.spiderX = SelectedSource.spiderX; } int ret = -1; switch (item.configType) { case EConfigType.VMess: ret = ConfigHandler.AddServer(ref _config, item); break; case EConfigType.Shadowsocks: ret = ConfigHandler.AddShadowsocksServer(ref _config, item); break; case EConfigType.Socks: ret = ConfigHandler.AddSocksServer(ref _config, item); break; case EConfigType.VLESS: ret = ConfigHandler.AddVlessServer(ref _config, item); break; case EConfigType.Trojan: ret = ConfigHandler.AddTrojanServer(ref _config, item); break; } if (ret == 0) { _noticeHandler?.Enqueue(ResUI.OperationSuccess); _view.DialogResult = true; //_view?.Close(); } else { UI.Show(ResUI.OperationFailed); } } } } ================================================ FILE: v2rayN/v2rayN/ViewModels/AnotherCommandImplementation.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Input; namespace v2rayN.ViewModels { public class AnotherCommandImplementation : ICommand { private readonly Action _execute; private readonly Func _canExecute; public AnotherCommandImplementation(Action execute) : this(execute, null) { } public AnotherCommandImplementation(Action execute, Func? canExecute) { if (execute is null) throw new ArgumentNullException(nameof(execute)); _execute = execute; _canExecute = canExecute ?? (x => true); } public bool CanExecute(object? parameter) => _canExecute(parameter); public void Execute(object? parameter) => _execute(parameter); public event EventHandler? CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public void Refresh() => CommandManager.InvalidateRequerySuggested(); } } ================================================ FILE: v2rayN/v2rayN/ViewModels/DNSSettingViewModel.cs ================================================ using ReactiveUI; using ReactiveUI.Fody.Helpers; using Splat; using System.Reactive; using System.Windows; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; namespace v2rayN.ViewModels { public class DNSSettingViewModel : ReactiveObject { private static Config _config; private NoticeHandler? _noticeHandler; private Window _view; [Reactive] public string domainStrategy4Freedom { get; set; } [Reactive] public string normalDNS { get; set; } [Reactive] public string normalDNS2 { get; set; } public ReactiveCommand SaveCmd { get; } public ReactiveCommand ImportDefConfig4V2rayCmd { get; } public ReactiveCommand ImportDefConfig4SingboxCmd { get; } public DNSSettingViewModel(Window view) { _config = LazyConfig.Instance.GetConfig(); _noticeHandler = Locator.Current.GetService(); _view = view; var item = LazyConfig.Instance.GetDNSItem(ECoreType.Xray); domainStrategy4Freedom = item?.domainStrategy4Freedom!; normalDNS = item?.normalDNS!; var item2 = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box); normalDNS2 = item2?.normalDNS!; SaveCmd = ReactiveCommand.Create(() => { SaveSetting(); }); ImportDefConfig4V2rayCmd = ReactiveCommand.Create(() => { normalDNS = Utils.GetEmbedText(Global.DNSV2rayNormalFileName); }); ImportDefConfig4SingboxCmd = ReactiveCommand.Create(() => { normalDNS2 = Utils.GetEmbedText(Global.DNSSingboxNormalFileName); }); Utils.SetDarkBorder(view, _config.uiItem.colorModeDark); } private void SaveSetting() { if (!Utils.IsNullOrEmpty(normalDNS)) { var obj = Utils.ParseJson(normalDNS); if (obj != null && obj.ContainsKey("servers") == true) { } else { if (normalDNS.Contains("{") || normalDNS.Contains("}")) { UI.Show(ResUI.FillCorrectDNSText); return; } } } if (!Utils.IsNullOrEmpty(normalDNS2)) { var obj2 = Utils.FromJson(normalDNS2); if (obj2 == null) { UI.Show(ResUI.FillCorrectDNSText); return; } } var item = LazyConfig.Instance.GetDNSItem(ECoreType.Xray); item.domainStrategy4Freedom = domainStrategy4Freedom; item.normalDNS = normalDNS; ConfigHandler.SaveDNSItems(_config, item); var item2 = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box); item2.normalDNS = Utils.ToJson(Utils.ParseJson(normalDNS2)); ConfigHandler.SaveDNSItems(_config, item2); _noticeHandler?.Enqueue(ResUI.OperationSuccess); _view.DialogResult = true; } } } ================================================ FILE: v2rayN/v2rayN/ViewModels/DemoItem.cs ================================================ using MaterialDesignThemes.Wpf; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Controls; using System.Windows; namespace v2rayN.ViewModels { public class DemoItem : ViewModelBase { private readonly Type _contentType; private readonly object? _dataContext; private object? _content; private ScrollBarVisibility _horizontalScrollBarVisibilityRequirement; private ScrollBarVisibility _verticalScrollBarVisibilityRequirement = ScrollBarVisibility.Auto; private Thickness _marginRequirement = new(16); private int _notificationNumber = 0; public DemoItem(string name, Type contentType, PackIconKind selectedIcon, PackIconKind unselectedIcon, object? dataContext = null) { Name = name; _contentType = contentType; _dataContext = dataContext; SelectedIcon = selectedIcon; UnselectedIcon = unselectedIcon; } public string Name { get; } public object? Content => _content ??= CreateContent(); public PackIconKind SelectedIcon { get; set; } public PackIconKind UnselectedIcon { get; set; } public object? Notifications { get { if (_notificationNumber == 0) return null; else return _notificationNumber < 100 ? _notificationNumber : "99+"; } } public ScrollBarVisibility HorizontalScrollBarVisibilityRequirement { get => _horizontalScrollBarVisibilityRequirement; set => SetProperty(ref _horizontalScrollBarVisibilityRequirement, value); } public ScrollBarVisibility VerticalScrollBarVisibilityRequirement { get => _verticalScrollBarVisibilityRequirement; set => SetProperty(ref _verticalScrollBarVisibilityRequirement, value); } public Thickness MarginRequirement { get => _marginRequirement; set => SetProperty(ref _marginRequirement, value); } private object? CreateContent() { var content = Activator.CreateInstance(_contentType); if (_dataContext != null && content is FrameworkElement element) { element.DataContext = _dataContext; } return content; } public void AddNewNotification() { _notificationNumber++; OnPropertyChanged(nameof(Notifications)); } public void DismissAllNotifications() { _notificationNumber = 0; OnPropertyChanged(nameof(Notifications)); } } } ================================================ FILE: v2rayN/v2rayN/ViewModels/HomeWindowViewModel.cs ================================================ using Google.Protobuf.Collections; using Google.Protobuf.WellKnownTypes; using MaterialDesignThemes.Wpf; using MaterialDesignThemes.Wpf.Transitions; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Configuration; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using v2rayN.Views; using v2rayN.ViewModels; using v2rayN.Converters; using v2rayN.Mode; namespace v2rayN.ViewModels { public class HomeWindowViewModel : ViewModelBase { public HomeWindowViewModel(ISnackbarMessageQueue snackbarMessageQueue) { _snackbarMessageQueue = snackbarMessageQueue; DemoItems = new ObservableCollection { new DemoItem( "Home", typeof(MainWindow), selectedIcon: PackIconKind.Home, unselectedIcon: PackIconKind.HomeOutline) }; MainDemoItems = new ObservableCollection { }; _demoItemsView = CollectionViewSource.GetDefaultView(DemoItems); DismissAllNotificationsCommand = new AnotherCommandImplementation( _ => DemoItems[0].DismissAllNotifications(), _ => DemoItems[0].Notifications != null); AddNewNotificationCommand = new AnotherCommandImplementation( _ => DemoItems[0].AddNewNotification()); AddNewNotificationCommand.Execute(new object()); NewProfileCommand = new AnotherCommandImplementation(ExecuteNewProfileDialog); Items1 = new ObservableCollection() { _selectedProfile, new SubItem { id = "A", remarks = "Profile2", url= "XAML Toolkit" }, new SubItem { id = "B", remarks = "Profile3", url= "Material Design in XAML Toolkit" }, new SubItem { id = "C", remarks = "Profile4", url= "Material " }, }; } private async void ExecuteNewProfileDialog(object? _) { //let's set up a little MVVM, cos that's what the cool kids are doing: //show the dialog _snackbarMessageQueue.Enqueue("Nothing find in the Clipboard"); //check the result... } private SubItem _selectedProfile = new SubItem { id = "A", remarks = "Profile 1", url = "XAML Toolkit" }; public SubItem SelectedProfile { get => _selectedProfile; set => SetProperty(ref _selectedProfile, value); } public ObservableCollection Items1 { get; } private readonly ICollectionView _demoItemsView; private DemoItem? _selectedItem; private int _selectedIndex; private string? _searchKeyword; private bool _controlsEnabled = true; private ISnackbarMessageQueue _snackbarMessageQueue; public ObservableCollection DemoItems { get; } public ObservableCollection MainDemoItems { get; } public DemoItem? SelectedItem { get => _selectedItem; set => SetProperty(ref _selectedItem, value); } public int SelectedIndex { get => _selectedIndex; set => SetProperty(ref _selectedIndex, value); } private bool _connectProgress = false; public bool ConnectProgress { get =>_connectProgress; set => SetProperty(ref _connectProgress, value); } public bool ControlsEnabled { get => _controlsEnabled; set => SetProperty(ref _controlsEnabled, value); } public AnotherCommandImplementation DismissAllNotificationsCommand { get; } public AnotherCommandImplementation AddNewNotificationCommand { get; } public AnotherCommandImplementation NewProfileCommand { get; } private static IEnumerable GenerateDemoItems(ISnackbarMessageQueue snackbarMessageQueue) { if (snackbarMessageQueue is null) throw new ArgumentNullException(nameof(snackbarMessageQueue)); yield return null; } } } ================================================ FILE: v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs ================================================ using DynamicData; using DynamicData.Binding; using MaterialDesignColors; using MaterialDesignColors.ColorManipulation; using MaterialDesignThemes.Wpf; using Microsoft.Win32; using ReactiveUI; using ReactiveUI.Fody.Helpers; using Splat; using System; using System.ComponentModel; using System.Diagnostics; using System.DirectoryServices.ActiveDirectory; using System.Drawing; using System.Globalization; using System.IO; using System.Reactive; using System.Reactive.Linq; using System.Reflection.Metadata.Ecma335; using System.Runtime.CompilerServices; using System.Security.Cryptography.Pkcs; using System.Security.RightsManagement; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Markup; using System.Windows.Media; using v2rayN.Base; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; using v2rayN.Tool; using v2rayN.Views; using Application = System.Windows.Application; namespace v2rayN.ViewModels { public class MainWindowViewModel : ReactiveObject { #region private prop private CoreHandler _coreHandler; private StatisticsHandler _statistics; private List _lstProfile; private string _subId = string.Empty; private string _serverFilter = string.Empty; private static Config _config; private readonly PaletteHelper _paletteHelper = new(); private Dictionary _dicHeaderSort = new(); private Action _updateView; private bool IsConnected = false; private string DefaultProxyMode = "Auto"; private bool IsForSettingBackLanguage = false; private bool IsDelayCalculationFinished = false; #endregion private prop // It's public because we need it in MainWindow.xaml.cs public NoticeHandler? _noticeHandler; #region ObservableCollection private IObservableCollection _profileItems = new ObservableCollectionExtended(); public IObservableCollection ProfileItems => _profileItems; private IObservableCollection _subItems = new ObservableCollectionExtended(); public IObservableCollection SubItems => _subItems; private IObservableCollection _routingItems = new ObservableCollectionExtended(); public IObservableCollection RoutingItems => _routingItems; private IObservableCollection _servers = new ObservableCollectionExtended(); public IObservableCollection Servers => _servers; //home [Reactive] public ListBoxItem HomeSelectedRoutingItem { get; set; } [Reactive] public ProxyModeEnum HomeSelectedProxyMode { get; set; } = ProxyModeEnum.Loadbalance; [Reactive] public int SelectedProfileDelay { get; set; } [Reactive] public bool V2RayNPanelVisible { get; set; } = false; [Reactive] public string ConnectVPNLabel { get; set; } = "Not Connected"; [Reactive] public string ConnectVPNLabelColor { get; set; } = "#FFFF0000"; [Reactive] public double WindowWidth { get; set; } [Reactive] public double MaxWindowWidth { get; set; } [Reactive] public ProfileItemModel SelectedProfile { get; set; } public IList SelectedProfiles { get; set; } [Reactive] public SubItem SelectedSub { get; set; } [Reactive] public SubItem SelectedMoveToGroup { get; set; } [Reactive] public RoutingItem SelectedRouting { get; set; } [Reactive] public ComboItem SelectedServer { get; set; } [Reactive] public string ServerFilter { get; set; } [Reactive] public bool BlServers { get; set; } #endregion ObservableCollection #region Menu //home public ReactiveCommand HomeNewProfileCmd { get; } public ReactiveCommand HomeConnectCmd { get; } public ReactiveCommand HomeUpdateUsageCmd { get; } public ReactiveCommand HomeGotoProfileCmd { get; } public ReactiveCommand HomeDeleteSubCmd { get; set; } public ReactiveCommand HomeRealPingServerCmd { get; } //servers public ReactiveCommand AddVmessServerCmd { get; } public ReactiveCommand AddVlessServerCmd { get; } public ReactiveCommand AddShadowsocksServerCmd { get; } public ReactiveCommand AddSocksServerCmd { get; } public ReactiveCommand AddTrojanServerCmd { get; } public ReactiveCommand AddCustomServerCmd { get; } public ReactiveCommand AddServerViaClipboardCmd { get; } public ReactiveCommand AddServerViaScanCmd { get; } //servers delete public ReactiveCommand EditServerCmd { get; } public ReactiveCommand RemoveServerCmd { get; } public ReactiveCommand RemoveDuplicateServerCmd { get; } public ReactiveCommand CopyServerCmd { get; } public ReactiveCommand SetDefaultServerCmd { get; } public ReactiveCommand ShareServerCmd { get; } //servers move public ReactiveCommand MoveTopCmd { get; } public ReactiveCommand MoveUpCmd { get; } public ReactiveCommand MoveDownCmd { get; } public ReactiveCommand MoveBottomCmd { get; } //servers ping public ReactiveCommand MixedTestServerCmd { get; } public ReactiveCommand PingServerCmd { get; } public ReactiveCommand TcpingServerCmd { get; } public ReactiveCommand RealPingServerCmd { get; } public ReactiveCommand SpeedServerCmd { get; } public ReactiveCommand SortServerResultCmd { get; } //servers export public ReactiveCommand Export2ClientConfigCmd { get; } public ReactiveCommand Export2ShareUrlCmd { get; } public ReactiveCommand Export2SubContentCmd { get; } //Subscription public ReactiveCommand SubSettingCmd { get; } public ReactiveCommand AddSubCmd { get; } public ReactiveCommand SubUpdateCmd { get; } public ReactiveCommand SubUpdateViaProxyCmd { get; } public ReactiveCommand SubGroupUpdateCmd { get; } public ReactiveCommand SubGroupUpdateViaProxyCmd { get; } //Setting public ReactiveCommand OptionSettingCmd { get; } public ReactiveCommand RoutingSettingCmd { get; } public ReactiveCommand DNSSettingCmd { get; } public ReactiveCommand GlobalHotkeySettingCmd { get; } public ReactiveCommand RebootAsAdminCmd { get; } public ReactiveCommand ClearServerStatisticsCmd { get; } public ReactiveCommand ImportOldGuiConfigCmd { get; } //CheckUpdate public ReactiveCommand CheckUpdateNCmd { get; } public ReactiveCommand CheckUpdateV2flyCoreCmd { get; } public ReactiveCommand CheckUpdateSagerNetCoreCmd { get; } public ReactiveCommand CheckUpdateXrayCoreCmd { get; } public ReactiveCommand CheckUpdateClashCoreCmd { get; } public ReactiveCommand CheckUpdateClashMetaCoreCmd { get; } public ReactiveCommand CheckUpdateSingBoxCoreCmd { get; } public ReactiveCommand CheckUpdateGeoCmd { get; } public ReactiveCommand ToggleV2rayNPanelCmd { get; } public ReactiveCommand ReloadCmd { get; } [Reactive] public bool BlReloadEnabled { get; set; } public ReactiveCommand NotifyLeftClickCmd { get; } [Reactive] public Icon NotifyIcon { get; set; } public ProxyModeEnum[] ProxyModes => (ProxyModeEnum[])Enum.GetValues(typeof(ProxyModeEnum)); [Reactive] public ImageSource AppIcon { get; set; } [Reactive] public bool BlShowTrayTip { get; set; } #endregion Menu #region System Proxy [Reactive] public bool BlSystemProxyClear { get; set; } [Reactive] public bool BlSystemProxySet { get; set; } [Reactive] public bool BlSystemProxyNothing { get; set; } [Reactive] public bool BlSystemProxyPac { get; set; } public ReactiveCommand SystemProxyClearCmd { get; } public ReactiveCommand SystemProxySetCmd { get; } public ReactiveCommand SystemProxyToggleCmd { get; } public ReactiveCommand SystemProxyNothingCmd { get; } public ReactiveCommand SystemProxyPacCmd { get; } [Reactive] public bool BlRouting { get; set; } [Reactive] public int SystemProxySelected { get; set; } #endregion System Proxy #region UI [Reactive] public bool ConnectProgress { get; set; } [Reactive] public bool ProfileExpanded { get; set; } [Reactive] public bool DelayProgress { get; set; } = false; [Reactive] public bool Loading { get; set; } = false; [Reactive] public string ConnectColor { get; set; } = "#FFE0E0E0"; [Reactive] public string InboundDisplay { get; set; } [Reactive] public string InboundLanDisplay { get; set; } [Reactive] public string RunningServerDisplay { get; set; } [Reactive] public string RunningServerToolTipText { get; set; } [Reactive] public string RunningInfoDisplay { get; set; } [Reactive] public string SpeedProxyDisplay { get; set; } [Reactive] public string SpeedDirectDisplay { get; set; } [Reactive] public bool EnableTun { get; set; } [Reactive] public bool SysProxyState { get; set; } [Reactive] public bool ColorModeDark { get; set; } private IObservableCollection _swatches = new ObservableCollectionExtended(); public IObservableCollection Swatches => _swatches; [Reactive] public Swatch SelectedSwatch { get; set; } [Reactive] public int CurrentFontSize { get; set; } [Reactive] public string CurrentLanguage { get; set; } #endregion UI #region Init // Program will change some values when it start // We will ignore that change, so we just consider user changes private bool ForInitiationLanguage = true; private bool ForInitiationTun = true; public MainWindowViewModel(ISnackbarMessageQueue snackbarMessageQueue, Action updateView) { _updateView = updateView; ThreadPool.RegisterWaitForSingleObject(App.ProgramStarted, OnProgramStarted, null, -1, false); Locator.CurrentMutable.RegisterLazySingleton(() => new NoticeHandler(snackbarMessageQueue), typeof(NoticeHandler)); _noticeHandler = Locator.Current.GetService(); _config = LazyConfig.Instance.GetConfig(); //ThreadPool.RegisterWaitForSingleObject(App.ProgramStarted, OnProgramStarted, null, -1, false); Init(); SelectedProfile = new(); SelectedSub = new(); SelectedMoveToGroup = new(); SelectedRouting = new(); SelectedServer = new(); if (_config.tunModeItem.enableTun && Utils.IsAdministrator()) { EnableTun = true; } _subId = _config.subIndexId; InitSubscriptionView(); RefreshRoutingsMenu(); RefreshServers(); // Enable Tls 1.3 _config.guiItem.enableSecurityProtocolTls13 = true; this.WhenAnyValue(x => x.HomeSelectedRoutingItem).Subscribe(c => HomeSelectedRouteChanged()); this.WhenAnyValue( x => x.HomeSelectedProxyMode).Subscribe(c => HomeSelectedProxyChanged()); var canEditRemove = this.WhenAnyValue( x => x.SelectedProfile, selectedSource => selectedSource != null && !selectedSource.indexId.IsNullOrEmpty()); this.WhenAnyValue( x => x.SelectedSub, y => y != null && !y.remarks.IsNullOrEmpty() && _subId != y.id) .Subscribe(c => SubSelectedChanged(c)); this.WhenAnyValue( x => x.SelectedMoveToGroup, y => y != null && !y.remarks.IsNullOrEmpty()) .Subscribe(c => MoveToGroup(c)); this.WhenAnyValue( x => x.SelectedRouting, y => y != null && !y.remarks.IsNullOrEmpty()) .Subscribe(c => RoutingSelectedChanged(c)); this.WhenAnyValue( x => x.SelectedServer, y => y != null && !y.Text.IsNullOrEmpty()) .Subscribe(c => ServerSelectedChanged(c)); this.WhenAnyValue( x => x.ServerFilter, y => y != null && _serverFilter != y) .Subscribe(c => ServerFilterChanged(c)); SystemProxySelected = (int)_config.sysProxyType; this.WhenAnyValue( x => x.SystemProxySelected, y => y >= 0) .Subscribe(c => DoSystemProxySelected(c)); this.WhenAnyValue( x => x.EnableTun, y => y == true) .Subscribe(c => DoEnableTun(c)); BindingUI(); RestoreUI(); //AutoHideStartup(); //home HomeNewProfileCmd = ReactiveCommand.Create(() => { HomeNewProfile(); }); HomeConnectCmd = ReactiveCommand.CreateFromTask(() => { return HomeConnect(); }); HomeUpdateUsageCmd = ReactiveCommand.Create(() => { if (SelectedSub != null) HomeUpdateUsage(SelectedSub); }); HomeGotoProfileCmd = ReactiveCommand.Create(() => { HomeGotoProfile(SelectedSub.id); }); HomeRealPingServerCmd = ReactiveCommand.CreateFromTask(() => { return Task.Run(async () => { // Till now, we started a server // Now we calculate real ping of the server to make sure, it's working DelayProgress = true; HomeRealPingServer(_config.indexId); // Wait for delay calculation (10 seconds) short count = 1; while (!IsDelayCalculationFinished) { // We don't want to stuck in a infinite loop if (count == 25) break; await Task.Delay(400).ConfigureAwait(false); count += 1; } DelayProgress = false; }); }); HomeDeleteSubCmd = ReactiveCommand.Create(() => { HomeDeleteSub(); }); //servers AddVmessServerCmd = ReactiveCommand.Create(() => { EditServer(true, EConfigType.VMess); }); AddVlessServerCmd = ReactiveCommand.Create(() => { EditServer(true, EConfigType.VLESS); }); AddShadowsocksServerCmd = ReactiveCommand.Create(() => { EditServer(true, EConfigType.Shadowsocks); }); AddSocksServerCmd = ReactiveCommand.Create(() => { EditServer(true, EConfigType.Socks); }); AddTrojanServerCmd = ReactiveCommand.Create(() => { EditServer(true, EConfigType.Trojan); }); AddCustomServerCmd = ReactiveCommand.Create(() => { EditServer(true, EConfigType.Custom); }); AddServerViaClipboardCmd = ReactiveCommand.Create(() => { AddServerOrSubViaClipboard(); }); AddServerViaScanCmd = ReactiveCommand.CreateFromTask(() => { return ScanScreenTaskAsync(); }); //servers delete EditServerCmd = ReactiveCommand.Create(() => { EditServer(false, EConfigType.Custom); }, canEditRemove); RemoveServerCmd = ReactiveCommand.Create(() => { RemoveServer(); }, canEditRemove); RemoveDuplicateServerCmd = ReactiveCommand.Create(() => { RemoveDuplicateServer(); }); CopyServerCmd = ReactiveCommand.Create(() => { CopyServer(); }, canEditRemove); SetDefaultServerCmd = ReactiveCommand.Create(() => { SetDefaultServer(); }, canEditRemove); ShareServerCmd = ReactiveCommand.Create(() => { ShareServer(); }, canEditRemove); //servers move MoveTopCmd = ReactiveCommand.Create(() => { MoveServer(EMove.Top); }, canEditRemove); MoveUpCmd = ReactiveCommand.Create(() => { MoveServer(EMove.Up); }, canEditRemove); MoveDownCmd = ReactiveCommand.Create(() => { MoveServer(EMove.Down); }, canEditRemove); MoveBottomCmd = ReactiveCommand.Create(() => { MoveServer(EMove.Bottom); }, canEditRemove); //servers ping MixedTestServerCmd = ReactiveCommand.Create(() => { ServerSpeedtest(ESpeedActionType.Mixedtest); }); PingServerCmd = ReactiveCommand.Create(() => { ServerSpeedtest(ESpeedActionType.Ping); }, canEditRemove); TcpingServerCmd = ReactiveCommand.Create(() => { ServerSpeedtest(ESpeedActionType.Tcping); }, canEditRemove); RealPingServerCmd = ReactiveCommand.Create(() => { ServerSpeedtest(ESpeedActionType.Realping); }, canEditRemove); SpeedServerCmd = ReactiveCommand.Create(() => { ServerSpeedtest(ESpeedActionType.Speedtest); }, canEditRemove); SortServerResultCmd = ReactiveCommand.Create(() => { SortServer(EServerColName.delayVal.ToString()); }); //servers export Export2ClientConfigCmd = ReactiveCommand.Create(() => { Export2ClientConfig(); }, canEditRemove); Export2ShareUrlCmd = ReactiveCommand.Create(() => { Export2ShareUrl(); }, canEditRemove); Export2SubContentCmd = ReactiveCommand.Create(() => { Export2SubContent(); }, canEditRemove); //Subscription SubSettingCmd = ReactiveCommand.Create(() => { SubSetting(); }); AddSubCmd = ReactiveCommand.Create(() => { AddSub(); }); SubUpdateCmd = ReactiveCommand.Create(() => { UpdateSubscriptionProcess("", false); }); SubUpdateViaProxyCmd = ReactiveCommand.Create(() => { UpdateSubscriptionProcess("", true); }); SubGroupUpdateCmd = ReactiveCommand.Create(() => { UpdateSubscriptionProcess(_subId, false); }); SubGroupUpdateViaProxyCmd = ReactiveCommand.Create(() => { UpdateSubscriptionProcess(_subId, true); }); //Setting OptionSettingCmd = ReactiveCommand.Create(() => { OptionSetting(); }); RoutingSettingCmd = ReactiveCommand.Create(() => { RoutingSetting(); }); DNSSettingCmd = ReactiveCommand.Create(() => { DNSSetting(); }); GlobalHotkeySettingCmd = ReactiveCommand.Create(() => { if ((new GlobalHotkeySettingWindow()).ShowDialog() == true) { _noticeHandler?.Enqueue(ResUI.OperationSuccess); } }); RebootAsAdminCmd = ReactiveCommand.Create(() => { RebootAsAdmin(); }); ClearServerStatisticsCmd = ReactiveCommand.Create(() => { _statistics?.ClearAllServerStatistics(); RefreshServers(); }); ImportOldGuiConfigCmd = ReactiveCommand.Create(() => { ImportOldGuiConfig(); }); //CheckUpdate CheckUpdateNCmd = ReactiveCommand.Create(() => { CheckUpdateN(); }); CheckUpdateV2flyCoreCmd = ReactiveCommand.Create(() => { CheckUpdateCore(ECoreType.v2fly_v5); }); CheckUpdateSagerNetCoreCmd = ReactiveCommand.Create(() => { CheckUpdateCore(ECoreType.SagerNet); }); CheckUpdateXrayCoreCmd = ReactiveCommand.Create(() => { CheckUpdateCore(ECoreType.Xray); }); CheckUpdateClashCoreCmd = ReactiveCommand.Create(() => { CheckUpdateCore(ECoreType.clash); }); CheckUpdateClashMetaCoreCmd = ReactiveCommand.Create(() => { CheckUpdateCore(ECoreType.clash_meta); }); CheckUpdateSingBoxCoreCmd = ReactiveCommand.Create(() => { CheckUpdateCore(ECoreType.sing_box); }); CheckUpdateGeoCmd = ReactiveCommand.Create(() => { CheckUpdateGeo(); }); ReloadCmd = ReactiveCommand.Create(() => { Reload(); }); NotifyLeftClickCmd = ReactiveCommand.Create(() => { ShowHideWindow(null); }); //System proxy SystemProxyClearCmd = ReactiveCommand.Create(() => { UnsetSysProxy(); }); SystemProxySetCmd = ReactiveCommand.Create(() => { SetSysProxy(); }); SystemProxyToggleCmd = ReactiveCommand.Create(() => { ToggleSysProxy(); }); SystemProxyNothingCmd = ReactiveCommand.Create(() => { SetListenerType(ESysProxyType.Unchanged); }); SystemProxyPacCmd = ReactiveCommand.Create(() => { SetListenerType(ESysProxyType.Pac); }); ToggleV2rayNPanelCmd = ReactiveCommand.Create(() => { ToggleV2rayPanel(); }); Global.ShowInTaskbar = true; // Auto update sub usage every Global.DefaultUpdateSubUsageIntervalSeconds seconds new Thread(delegate () { while (true) { if (SelectedSub != null) HomeUpdateUsage(SelectedSub); Thread.Sleep(TimeSpan.FromSeconds(Global.DefaultUpdateSubUsageIntervalSeconds)); } }).Start(); // Auto update sub (profiles/servers) new Thread(delegate () { while (true) { if (SelectedSub != null) { if (SelectedSub.enabled) { if (SelectedSub.profileUpdateInterval == 0) { bool useProxy = Utils.IsSystemProxyEnabled(_config.sysProxyType); var headers = Utils.GetUrlResponseHeader(SelectedSub.url,useProxy); var subInfo = Utils.GetSubscriptionInfoFromHeaders(headers); if (subInfo == null) continue; if (subInfo.ProfileUpdateInterval != 0) // Change sub item SelectedSub.profileUpdateInterval = subInfo.ProfileUpdateInterval; // Edit sub item interval ConfigHandler.AddSubItem(ref _config, SelectedSub); continue; } else { if (Utils.IsSystemProxyEnabled(_config.sysProxyType)) UpdateSubscriptionProcess(SelectedSub.id, true); else UpdateSubscriptionProcess(SelectedSub.id, false); } } Thread.Sleep(TimeSpan.FromHours(SelectedSub.profileUpdateInterval)); } else { Thread.Sleep(700); } } }).Start(); // Connect to the default sub //HomeConnect(true); } private void Init() { ConfigHandler.InitBuiltinRouting(ref _config); ConfigHandler.InitBuiltinDNS(_config); _coreHandler = new CoreHandler(_config, UpdateHandler); if (_config.guiItem.enableStatistics) { _statistics = new StatisticsHandler(_config, UpdateStatisticsHandler); } MainFormHandler.Instance.UpdateTask(_config, UpdateTaskHandler); MainFormHandler.Instance.RegisterGlobalHotkey(_config, OnHotkeyHandler, UpdateTaskHandler); Reload(); ChangeSystemProxyStatus(_config.sysProxyType, true); } private void OnProgramStarted(object state, bool timeout) { Application.Current.Dispatcher.Invoke((Action)(() => { ShowHideWindow(true); })); } #endregion Init #region Actions private void UpdateHandler(bool notify, string msg) { _noticeHandler?.SendMessage(msg); } private void UpdateTaskHandler(bool success, string msg) { _noticeHandler?.SendMessage(msg); if (success) { var indexIdOld = _config.indexId; RefreshServers(); if (indexIdOld != _config.indexId) { Reload(); } if (_config.uiItem.enableAutoAdjustMainLvColWidth) { _updateView(EViewAction.AdjustMainLvColWidth); } } Loading = false; } private void UpdateStatisticsHandler(ServerSpeedItem update) { try { Application.Current.Dispatcher.Invoke((Action)(() => { if (!Global.ShowInTaskbar) { return; } SpeedProxyDisplay = string.Format(ResUI.SpeedDisplayText, Global.agentTag, Utils.HumanFy(update.proxyUp), Utils.HumanFy(update.proxyDown)); SpeedDirectDisplay = string.Format(ResUI.SpeedDisplayText, Global.directTag, Utils.HumanFy(update.directUp), Utils.HumanFy(update.directDown)); if (update.proxyUp + update.proxyDown > 0) { var second = DateTime.Now.Second; if (second % 3 == 0) { var item = _profileItems.Where(it => it.indexId == update.indexId).FirstOrDefault(); if (item != null) { item.todayDown = Utils.HumanFy(update.todayDown); item.todayUp = Utils.HumanFy(update.todayUp); item.totalDown = Utils.HumanFy(update.totalDown); item.totalUp = Utils.HumanFy(update.totalUp); if (SelectedProfile?.indexId == item.indexId) { var temp = Utils.DeepCopy(item); _profileItems.Replace(item, temp); SelectedProfile = temp; } else { _profileItems.Replace(item, Utils.DeepCopy(item)); } } } } })); } catch (Exception ex) { Utils.SaveLog(ex.Message, ex); } } private void UpdateSpeedtestHandler(string indexId, string delay, string speed) { Application.Current.Dispatcher.Invoke((Action)(() => { SetTestResult(indexId, delay, speed); })); } private void SetTestResult(string indexId, string delay, string speed) { if (Utils.IsNullOrEmpty(indexId)) { _noticeHandler?.SendMessage(delay, true); _noticeHandler?.Enqueue(delay); return; } var item = _profileItems.Where(it => it.indexId == indexId).FirstOrDefault(); if (item != null) { if (!Utils.IsNullOrEmpty(delay)) { int.TryParse(delay, out int temp); item.delay = temp; item.delayVal = $"{delay} {Global.DelayUnit}"; } if (!Utils.IsNullOrEmpty(speed)) { item.speedVal = $"{speed} {Global.SpeedUnit}"; } _profileItems.Replace(item, Utils.DeepCopy(item)); } } private void OnHotkeyHandler(EGlobalHotkey e) { switch (e) { case EGlobalHotkey.ShowForm: ShowHideWindow(null); break; case EGlobalHotkey.SystemProxyClear: SetListenerType(ESysProxyType.ForcedClear); break; case EGlobalHotkey.SystemProxySet: SetListenerType(ESysProxyType.ForcedChange); break; case EGlobalHotkey.SystemProxyUnchanged: SetListenerType(ESysProxyType.Unchanged); break; case EGlobalHotkey.SystemProxyPac: SetListenerType(ESysProxyType.Pac); break; } } public void PreExit(bool blWindowsShutDown) { Utils.SaveLog("PreExit Begin"); StorageUI(); ConfigHandler.SaveConfig(ref _config); //HttpProxyHandle.CloseHttpAgent(config); if (blWindowsShutDown) { SysProxyHandle.ResetIEProxy4WindowsShutDown(); } else { SysProxyHandle.UpdateSysProxy(_config, true); } ProfileExHandler.Instance.SaveTo(); _statistics?.SaveTo(); _statistics?.Close(); _coreHandler.CoreStop(); Utils.SaveLog("PreExit End"); } public void MyAppExit(bool blWindowsShutDown) { try { PreExit(blWindowsShutDown); } catch { } finally { Utils.ExitSuccess(); } } #endregion Actions #region Servers && Groups public void SubSelectedChanged(bool c) { ProfileExpanded = false; if (!c) { return; } string subID = GetSubIdByRemark(SelectedSub?.remarks); if (subID == null) { // throw new Exception("Selected a sub that we couldn't find its id"); } _subId = subID; _config.subIndexId = _subId; RefreshServers(); _updateView(EViewAction.ProfilesFocus); } // It selects appropiate server by selected sub and proxy mode // It actually change config.IndexId private void SelectAppropiateServer() { if (SelectedSub == null) { _noticeHandler.Enqueue("Please select a sub"); return; } // User selected a proxy mode if (HomeSelectedProxyMode != null) { // Handle manual mode if (HomeSelectedProxyMode == ProxyModeEnum.Manual) { if (Utils.IsNullOrEmpty(_config.indexId)) { //TODO: Send message to user about what happend _noticeHandler.Enqueue("Please select a server to connect"); ConnectColor = "#FFE0E0E0"; ConnectProgress = false; return; } SetDefaultServer(_config.indexId); } else { // Now the selected proxy mode is auto either load balance ProfileItem server = GetSelectedServer(SelectedSub.id, HomeSelectedProxyMode); if (server == null) { //TODO: Send message to user about what happend ConnectColor = "#FFE0E0E0"; ConnectProgress = false; return; } SetDefaultServer(server.indexId); } } // There is no selected proxy mode (we use default proxy setting) else { ProfileItem? server = null; // Just set a default mode var subServers = LazyConfig.Instance.ProfileItems(SelectedSub.id); if (DefaultProxyMode == "Auto") server = subServers.FirstOrDefault(s => s.remarks == "Lowest Ping"); else if (DefaultProxyMode == "Load Balance") server = subServers.FirstOrDefault(s => s.remarks == DefaultProxyMode); if (server == null) { //TODO Send message to user about what happend ConnectColor = "#FFE0E0E0"; ConnectProgress = false; return; } SetDefaultServer(server.indexId); } } private string? GetSubIdByRemark(string remarks) { foreach (SubItem item in _subItems) { if (item.remarks == remarks) return item.id; } return null; } private void ServerFilterChanged(bool c) { if (!c) { return; } _serverFilter = ServerFilter; if (Utils.IsNullOrEmpty(_serverFilter)) { RefreshServers(); } } public void RefreshServers() { List lstModel = LazyConfig.Instance.ProfileItems(_subId, _serverFilter); ConfigHandler.SetDefaultServer(_config, lstModel); List lstServerStat = new(); if (_statistics != null && _statistics.Enable) { lstServerStat = _statistics.ServerStat; } var lstProfileExs = ProfileExHandler.Instance.ProfileExs; lstModel = (from t in lstModel join t2 in lstServerStat on t.indexId equals t2.indexId into t2b from t22 in t2b.DefaultIfEmpty() join t3 in lstProfileExs on t.indexId equals t3.indexId into t3b from t33 in t3b.DefaultIfEmpty() select new ProfileItemModel { indexId = t.indexId, configType = t.configType, remarks = t.remarks, address = t.address, port = t.port, security = t.security, network = t.network, streamSecurity = t.streamSecurity, subid = t.subid, subRemarks = t.subRemarks, isActive = t.indexId == _config.indexId, sort = t33 == null ? 0 : t33.sort, delay = t33 == null ? 0 : t33.delay, delayVal = t33?.delay != 0 ? $"{t33?.delay} {Global.DelayUnit}" : string.Empty, speedVal = t33?.speed != 0 ? $"{t33?.speed} {Global.SpeedUnit}" : string.Empty, todayDown = t22 == null ? "" : Utils.HumanFy(t22.todayDown), todayUp = t22 == null ? "" : Utils.HumanFy(t22.todayUp), totalDown = t22 == null ? "" : Utils.HumanFy(t22.totalDown), totalUp = t22 == null ? "" : Utils.HumanFy(t22.totalUp) }).OrderBy(t => t.sort).ToList(); _lstProfile = Utils.FromJson>(Utils.ToJson(lstModel)); Application.Current.Dispatcher.Invoke((Action)(() => { _profileItems.Clear(); _profileItems.AddRange(lstModel); if (lstModel.Count > 0) { var selected = lstModel.FirstOrDefault(t => t.indexId == _config.indexId); if (selected != null) { SelectedProfile = selected; } else { SelectedProfile = lstModel[0]; } } RefreshServersMenu(); //display running server var running = ConfigHandler.GetDefaultServer(ref _config); if (running != null) { var runningSummary = running.GetSummary(); RunningServerDisplay = $"{ResUI.menuServers}:{runningSummary}"; RunningServerToolTipText = runningSummary; } else { RunningServerDisplay = RunningServerToolTipText = ResUI.CheckServerSettings; } })); } private void RefreshServersMenu() { _servers.Clear(); if (_lstProfile.Count > _config.guiItem.trayMenuServersLimit) { BlServers = false; return; } BlServers = true; for (int k = 0; k < _lstProfile.Count; k++) { ProfileItem it = _lstProfile[k]; string name = it.GetSummary(); var item = new ComboItem() { ID = it.indexId, Text = name }; _servers.Add(item); if (_config.indexId == it.indexId) { SelectedServer = item; } } } public void InitSubscriptionView() { _subItems.Clear(); //_subItems.Add(new SubItem { remarks = ResUI.AllGroupServers }); foreach (var item in LazyConfig.Instance.SubItems().OrderByDescending(t => t.sort)) { _subItems.Add(item); } if (_subId != null && _subItems.FirstOrDefault(t => t.id == _subId) != null) { SelectedSub = _subItems.FirstOrDefault(t => t.id == _subId); } else { SelectedSub = _subItems.Count>0?_subItems[0]:null; } } #endregion Servers && Groups #region Add Servers private int GetProfileItems(out List lstSelecteds, bool latest) { lstSelecteds = new List(); if (SelectedProfiles == null || SelectedProfiles.Count <= 0) { return -1; } var orderProfiles = SelectedProfiles?.OrderBy(t => t.sort); if (latest) { foreach (var profile in orderProfiles) { var item = LazyConfig.Instance.GetProfileItem(profile.indexId); if (item is not null) { lstSelecteds.Add(item); } } } else { lstSelecteds = Utils.FromJson>(Utils.ToJson(orderProfiles)); } return 0; } public void EditServer(bool blNew, EConfigType eConfigType) { ProfileItem item; if (blNew) { item = new() { subid = _subId, configType = eConfigType, isSub = false, }; } else { if (Utils.IsNullOrEmpty(SelectedProfile?.indexId)) { return; } item = LazyConfig.Instance.GetProfileItem(SelectedProfile.indexId); if (item is null) { _noticeHandler?.Enqueue(ResUI.PleaseSelectServer); return; } eConfigType = item.configType; } bool? ret = false; if (eConfigType == EConfigType.Custom) { ret = (new AddServer2Window(item)).ShowDialog(); } else { ret = (new AddServerWindow(item)).ShowDialog(); } if (ret == true) { RefreshServers(); if (item.indexId == _config.indexId) { Reload(); } } } public (int, List) HomeAddServerOrSubViaClipboard(string cData) { Loading = true; var (addedServersCount, addedSubIds) = ConfigHandler.HomeAddBatchServers(ref _config, cData, _subId, false, null); if (addedSubIds.Count > 0) { foreach (string id in addedSubIds) { //if (Utils.IsSystemProxyEnabled(_config.sysProxyType)) //{ // UpdateSubscriptionProcess(id, true); //} //else //{ //TODO: we should first get the sub link without proxy if not working use proxy UpdateSubscriptionProcess(id, false); //} } } else { Loading = false; } return (addedServersCount, addedSubIds); } public void AddServerOrSubViaClipboard() { string clipboardData = Utils.GetClipboardData(); HomeAddServerOrSubViaClipboard(clipboardData); return; int ret = ConfigHandler.AddBatchServers(ref _config, clipboardData, _subId, false); if (ret > 0) { InitSubscriptionView(); RefreshServers(); _noticeHandler?.Enqueue(string.Format(ResUI.SuccessfullyImportedServerViaClipboard, ret)); // This update all subscriptions // TODO: update just added sub, if was a sub added UpdateSubscriptionProcess("", Utils.IsSystemProxyEnabled(_config.sysProxyType)); } } public void AddServerOrSubViaDeepLink(string url) { HomeAddServerOrSubViaClipboard(url); return; int ret = ConfigHandler.AddBatchServers(ref _config, url, _subId, false); if (ret > 0) { InitSubscriptionView(); RefreshServers(); _noticeHandler?.Enqueue(string.Format(ResUI.SuccessfullyImportedServerViaClipboard, ret)); // This update all subscriptions // TODO: update just added sub, if was a sub added UpdateSubscriptionProcess("", Utils.IsSystemProxyEnabled(_config.sysProxyType)); } } public void AddServersViaDeeplink(string servers_link) { } public void AddSubViaDeeplink(string sub_url) { } public void AddSubAndServerViaDeeplink(string data) { } public async Task ScanScreenTaskAsync() { ShowHideWindow(false); var dpiXY = Utils.GetDpiXY(Application.Current.MainWindow); string result = await Task.Run(() => { return Utils.ScanScreen(dpiXY.Item1, dpiXY.Item2); }); ShowHideWindow(true); if (Utils.IsNullOrEmpty(result)) { _noticeHandler?.Enqueue(ResUI.NoValidQRcodeFound); } else { int ret = ConfigHandler.AddBatchServers(ref _config, result, _subId, false); if (ret > 0) { InitSubscriptionView(); RefreshServers(); _noticeHandler?.Enqueue(ResUI.SuccessfullyImportedServerViaScan); } } } public void RemoveServer() { if (GetProfileItems(out List lstSelecteds, true) < 0) { return; } if (UI.ShowYesNo(ResUI.RemoveServer) == MessageBoxResult.No) { return; } var exists = lstSelecteds.Exists(t => t.indexId == _config.indexId); ConfigHandler.RemoveServer(_config, lstSelecteds); _noticeHandler?.Enqueue(ResUI.OperationSuccess); RefreshServers(); if (exists) { Reload(); } } private void RemoveDuplicateServer() { var tuple = ConfigHandler.DedupServerList(_config, _subId); RefreshServers(); Reload(); _noticeHandler?.Enqueue(string.Format(ResUI.RemoveDuplicateServerResult, tuple.Item1, tuple.Item2)); } private void CopyServer() { if (GetProfileItems(out List lstSelecteds, false) < 0) { return; } if (ConfigHandler.CopyServer(ref _config, lstSelecteds) == 0) { RefreshServers(); _noticeHandler?.Enqueue(ResUI.OperationSuccess); } } public void SetDefaultServer() { if (Utils.IsNullOrEmpty(SelectedProfile?.indexId)) { return; } SetDefaultServer(SelectedProfile.indexId); } private void SetDefaultServer(string indexId) { if (Utils.IsNullOrEmpty(indexId)) { return; } if (indexId == _config.indexId) { return; } var item = LazyConfig.Instance.GetProfileItem(indexId); if (item is null) { _noticeHandler?.Enqueue(ResUI.PleaseSelectServer); return; } if (ConfigHandler.SetDefaultServerIndex(ref _config, indexId) == 0) { RefreshServers(); Reload(); } } private void ServerSelectedChanged(bool c) { if (!c) { return; } if (SelectedServer == null) { return; } if (Utils.IsNullOrEmpty(SelectedServer.ID)) { return; } SetDefaultServer(SelectedServer.ID); } public async void ShareServer() { var item = LazyConfig.Instance.GetProfileItem(SelectedProfile.indexId); if (item is null) { _noticeHandler?.Enqueue(ResUI.PleaseSelectServer); return; } string url = ShareHandler.GetShareUrl(item); if (Utils.IsNullOrEmpty(url)) { return; } var img = QRCodeHelper.GetQRCode(url); var dialog = new QrcodeView() { imgQrcode = { Source = img }, txtContent = { Text = url }, }; await DialogHost.Show(dialog, "RootDialog"); } public void SortServer(string colName) { if (Utils.IsNullOrEmpty(colName)) { return; } _dicHeaderSort.TryAdd(colName, true); _dicHeaderSort.TryGetValue(colName, out bool asc); if (ConfigHandler.SortServers(ref _config, _subId, colName, asc) != 0) { return; } _dicHeaderSort[colName] = !asc; RefreshServers(); } public void TestServerAvailability() { var item = ConfigHandler.GetDefaultServer(ref _config); if (item == null || item.configType == EConfigType.Custom) { return; } (new UpdateHandle()).RunAvailabilityCheck((bool success, string msg) => { _noticeHandler?.SendMessage(msg, true); Application.Current.Dispatcher.Invoke((Action)(() => { if (!Global.ShowInTaskbar) { return; } RunningInfoDisplay = msg; })); }); } //move server private void MoveToGroup(bool c) { if (!c) { return; } if (GetProfileItems(out List lstSelecteds, true) < 0) { return; } ConfigHandler.MoveToGroup(_config, lstSelecteds, SelectedMoveToGroup.id); _noticeHandler?.Enqueue(ResUI.OperationSuccess); RefreshServers(); SelectedMoveToGroup = new(); //Reload(); } public void MoveServer(EMove eMove) { var item = _lstProfile.FirstOrDefault(t => t.indexId == SelectedProfile.indexId); if (item is null) { _noticeHandler?.Enqueue(ResUI.PleaseSelectServer); return; } int index = _lstProfile.IndexOf(item); if (index < 0) { return; } if (ConfigHandler.MoveServer(ref _config, ref _lstProfile, index, eMove) == 0) { RefreshServers(); } } public void MoveServerTo(int startIndex, ProfileItemModel targetItem) { var targetIndex = _profileItems.IndexOf(targetItem); if (startIndex >= 0 && targetIndex >= 0 && startIndex != targetIndex) { if (ConfigHandler.MoveServer(ref _config, ref _lstProfile, startIndex, EMove.Position, targetIndex) == 0) { RefreshServers(); } } } public void ServerSpeedtest(ESpeedActionType actionType) { if (actionType == ESpeedActionType.Mixedtest) { SelectedProfiles = _profileItems; } if (GetProfileItems(out List lstSelecteds, false) < 0) { return; } //ClearTestResult(); new SpeedtestHandler(_config, _coreHandler, lstSelecteds, actionType, UpdateSpeedtestHandler); } private void Export2ClientConfig() { var item = LazyConfig.Instance.GetProfileItem(SelectedProfile.indexId); if (item is null) { _noticeHandler?.Enqueue(ResUI.PleaseSelectServer); return; } MainFormHandler.Instance.Export2ClientConfig(item, _config); } public void Export2ShareUrl() { if (GetProfileItems(out List lstSelecteds, true) < 0) { return; } StringBuilder sb = new(); foreach (var it in lstSelecteds) { string url = ShareHandler.GetShareUrl(it); if (Utils.IsNullOrEmpty(url)) { continue; } sb.Append(url); sb.AppendLine(); } if (sb.Length > 0) { Utils.SetClipboardData(sb.ToString()); _noticeHandler?.SendMessage(ResUI.BatchExportURLSuccessfully); } } private void Export2SubContent() { if (GetProfileItems(out List lstSelecteds, true) < 0) { return; } StringBuilder sb = new(); foreach (var it in lstSelecteds) { string? url = ShareHandler.GetShareUrl(it); if (Utils.IsNullOrEmpty(url)) { continue; } sb.Append(url); sb.AppendLine(); } if (sb.Length > 0) { Utils.SetClipboardData(Utils.Base64Encode(sb.ToString())); _noticeHandler?.SendMessage(ResUI.BatchExportSubscriptionSuccessfully); } } #endregion Add Servers #region Subscription private void SubSetting() { if ((new SubSettingWindow()).ShowDialog() == true) { // Update view InitSubscriptionView(); SubSelectedChanged(true); // Update Subscription after add SubItem latestSubItem = LazyConfig.Instance.GetLastSubItem(); if (latestSubItem != null) { UpdateSubscriptionProcess(latestSubItem.id, true); } } } private void AddSub() { SubItem item = new(); var ret = (new SubEditWindow(item)).ShowDialog(); if (ret == true) { // Update view InitSubscriptionView(); SubSelectedChanged(true); // Update Subscription after add SubItem latestSubItem = LazyConfig.Instance.GetLastSubItem(); if (latestSubItem != null) { UpdateSubscriptionProcess(latestSubItem.id, true); } } } public void UpdateSubscriptionProcess(string subId, bool blProxy) { (new UpdateHandle()).UpdateSubscriptionProcess(_config, subId, blProxy, UpdateTaskHandler); } #endregion Subscription #region Setting private void OptionSetting() { var ret = (new OptionSettingWindow()).ShowDialog(); if (ret == true) { //RefreshServers(); Reload(); } } private void RoutingSetting() { var ret = (new RoutingSettingWindow()).ShowDialog(); if (ret == true) { ConfigHandler.InitBuiltinRouting(ref _config); RefreshRoutingsMenu(); //RefreshServers(); Reload(); } } private void DNSSetting() { var ret = (new DNSSettingWindow()).ShowDialog(); if (ret == true) { Reload(); } } private void RebootAsAdmin() { ProcessStartInfo startInfo = new() { UseShellExecute = true, Arguments = Global.RebootAs, WorkingDirectory = Utils.StartupPath(), FileName = Utils.GetExePath(), Verb = "runas", }; try { Process.Start(startInfo); MyAppExit(false); } catch { } } private void ImportOldGuiConfig() { OpenFileDialog fileDialog = new() { Multiselect = false, Filter = "guiNConfig|*.json|All|*.*" }; if (fileDialog.ShowDialog() != true) { return; } string fileName = fileDialog.FileName; if (Utils.IsNullOrEmpty(fileName)) { return; } var ret = ConfigHandler.ImportOldGuiConfig(ref _config, fileName); if (ret == 0) { RefreshRoutingsMenu(); InitSubscriptionView(); RefreshServers(); Reload(); UI.Show(ResUI.OperationSuccess); } else { _noticeHandler.Enqueue(ResUI.OperationFailed); } } #endregion Setting #region CheckUpdate private void CheckUpdateN() { void _updateUI(bool success, string msg) { _noticeHandler?.SendMessage(msg); if (success) { MyAppExit(false); } } (new UpdateHandle()).CheckUpdateGuiN(_config, _updateUI, _config.guiItem.checkPreReleaseUpdate); } private void CheckUpdateCore(ECoreType type) { void _updateUI(bool success, string msg) { _noticeHandler?.SendMessage(msg); if (success) { CloseV2ray(); string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(msg)); string toPath = Utils.GetBinPath("", type); FileManager.ZipExtractToFile(fileName, toPath, _config.guiItem.ignoreGeoUpdateCore ? "geo" : ""); _noticeHandler?.SendMessage(ResUI.MsgUpdateV2rayCoreSuccessfullyMore); Reload(); _noticeHandler?.SendMessage(ResUI.MsgUpdateV2rayCoreSuccessfully); if (File.Exists(fileName)) { File.Delete(fileName); } } } (new UpdateHandle()).CheckUpdateCore(type, _config, _updateUI, _config.guiItem.checkPreReleaseUpdate); } private void CheckUpdateGeo() { (new UpdateHandle()).UpdateGeoFileAll(_config, UpdateTaskHandler); } #endregion CheckUpdate #region v2ray job public void Reload() { _ = LoadV2ray(); } private async Task LoadV2ray() { Application.Current.Dispatcher.Invoke((Action)(() => { BlReloadEnabled = false; })); await Task.Run(() => { _coreHandler.LoadCore(); //ConfigHandler.SaveConfig(ref _config, false); ChangeSystemProxyStatus(_config.sysProxyType, false); }); TestServerAvailability(); Application.Current.Dispatcher.Invoke((Action)(() => { BlReloadEnabled = true; })); ServerSpeedtest(ESpeedActionType.Realping); } private void CloseV2ray() { ConfigHandler.SaveConfig(ref _config, false); ChangeSystemProxyStatus(ESysProxyType.ForcedClear, false); _coreHandler.CoreStop(); } #endregion v2ray job #region System proxy and Routings public void SetListenerType(ESysProxyType type) { if (_config.sysProxyType == type) { return; } _config.sysProxyType = type; ChangeSystemProxyStatus(type, true); SystemProxySelected = (int)_config.sysProxyType; ConfigHandler.SaveConfig(ref _config, false); } private void ChangeSystemProxyStatus(ESysProxyType type, bool blChange) { SysProxyHandle.UpdateSysProxy(_config, false); _noticeHandler?.SendMessage(ResUI.TipChangeSystemProxy, true); Application.Current.Dispatcher.Invoke((Action)(() => { BlSystemProxyClear = (type == ESysProxyType.ForcedClear); BlSystemProxySet = (type == ESysProxyType.ForcedChange); BlSystemProxyNothing = (type == ESysProxyType.Unchanged); BlSystemProxyPac = (type == ESysProxyType.Pac); InboundDisplayStaus(); if (blChange) { NotifyIcon = MainFormHandler.Instance.GetNotifyIcon(_config); AppIcon = MainFormHandler.Instance.GetAppIcon(_config); } if (BlSystemProxySet || BlSystemProxyPac) { SysProxyState = true; } else { SysProxyState = false; } })); } private void RefreshRoutingsMenu() { _routingItems.Clear(); if (!_config.routingBasicItem.enableRoutingAdvanced) { BlRouting = false; return; } BlRouting = true; var routings = LazyConfig.Instance.RoutingItems(); foreach (var item in routings) { _routingItems.Add(item); if (item.id == _config.routingBasicItem.routingIndexId) { SelectedRouting = item; } } } private void RoutingSelectedChanged(bool c) { if (!c) { return; } if (SelectedRouting == null) { return; } var item = LazyConfig.Instance.GetRoutingItem(SelectedRouting?.id); if (item is null) { return; } if (_config.routingBasicItem.routingIndexId == item.id) { return; } if (ConfigHandler.SetDefaultRouting(ref _config, item) == 0) { _noticeHandler?.SendMessage(ResUI.TipChangeRouting, true); Reload(); } } private void DoSystemProxySelected(bool c) { if (!c) { return; } if (_config.sysProxyType == (ESysProxyType)SystemProxySelected) { return; } SetListenerType((ESysProxyType)SystemProxySelected); } private void SetSysProxy() { SetListenerType(ESysProxyType.ForcedChange); SysProxyState = true; _config.sysProxyType= ESysProxyType.ForcedChange; } private void UnsetSysProxy() { SetListenerType(ESysProxyType.ForcedClear); SysProxyState = false; _config.sysProxyType = ESysProxyType.ForcedClear; } public void ToggleSysProxy() { // The "SysProxyState" variable will be change in the UI // that means when it's off and user clicks on that we will have "SysProxyState" true, cause it was changed when user clicked if (SysProxyState) { SetSysProxy(); } else { UnsetSysProxy(); } } private void DoEnableTun(bool c) { // If it's for initiation, we ignore (user didn't change the value) if (ForInitiationTun) { ForInitiationTun = false; return; Reload(); } if (Utils.IsAdministrator()) { if (_config.tunModeItem.enableTun != EnableTun) { _config.tunModeItem.enableTun = EnableTun; } TunModeSwitch(); } } private void TunModeSwitch() { if (EnableTun) { TunHandler.Instance.Start(); } else { TunHandler.Instance.Stop(); } } #endregion System proxy and Routings #region UI public void ShowHideWindow(bool? blShow) { var bl = blShow ?? !Global.ShowInTaskbar; if (bl) { //Application.Current.MainWindow.ShowInTaskbar = true; Application.Current.MainWindow.Show(); if (Application.Current.MainWindow.WindowState == WindowState.Minimized) { Application.Current.MainWindow.WindowState = WindowState.Normal; } Application.Current.MainWindow.Activate(); Application.Current.MainWindow.Focus(); } else { Application.Current.MainWindow.Hide(); //Application.Current.MainWindow.ShowInTaskbar = false; //IntPtr windowHandle = new WindowInteropHelper(Application.Current.MainWindow).Handle; //Utils.RegWriteValue(Global.MyRegPath, Utils.WindowHwndKey, Convert.ToString((long)windowHandle)); } Global.ShowInTaskbar = bl; } private void RestoreUI() { ModifyTheme(_config.uiItem.colorModeDark); if (!_config.uiItem.colorPrimaryName.IsNullOrEmpty()) { var swatch = new SwatchesProvider().Swatches.FirstOrDefault(t => t.Name == _config.uiItem.colorPrimaryName); if (swatch != null && swatch.ExemplarHue != null && swatch.ExemplarHue?.Color != null) { ChangePrimaryColor(swatch.ExemplarHue.Color); } } } private void StorageUI() { } private void BindingUI() { ColorModeDark = _config.uiItem.colorModeDark; _swatches.AddRange(new SwatchesProvider().Swatches); if (!_config.uiItem.colorPrimaryName.IsNullOrEmpty()) { SelectedSwatch = _swatches.FirstOrDefault(t => t.Name == _config.uiItem.colorPrimaryName); } CurrentFontSize = _config.uiItem.currentFontSize; CurrentLanguage = _config.uiItem.currentLanguage; BlShowTrayTip = _config.uiItem.showTrayTip; this.WhenAnyValue( x => x.ColorModeDark, y => y == true) .Subscribe(c => { if (_config.uiItem.colorModeDark != ColorModeDark) { _config.uiItem.colorModeDark = ColorModeDark; ModifyTheme(ColorModeDark); ConfigHandler.SaveConfig(ref _config); } }); this.WhenAnyValue( x => x.SelectedSwatch, y => y != null && !y.Name.IsNullOrEmpty()) .Subscribe(c => { if (SelectedSwatch == null || SelectedSwatch.Name.IsNullOrEmpty() || SelectedSwatch.ExemplarHue == null || SelectedSwatch.ExemplarHue?.Color == null) { return; } if (_config.uiItem.colorPrimaryName != SelectedSwatch?.Name) { _config.uiItem.colorPrimaryName = SelectedSwatch?.Name; ChangePrimaryColor(SelectedSwatch.ExemplarHue.Color); ConfigHandler.SaveConfig(ref _config); } }); this.WhenAnyValue( x => x.CurrentFontSize, y => y > 0) .Subscribe(c => { if (CurrentFontSize >= Global.MinFontSize) { _config.uiItem.currentFontSize = CurrentFontSize; double size = (long)CurrentFontSize; Application.Current.Resources["StdFontSize"] = size; Application.Current.Resources["StdFontSize1"] = size + 1; Application.Current.Resources["StdFontSize2"] = size + 2; Application.Current.Resources["StdFontSizeMsg"] = size - 1; ConfigHandler.SaveConfig(ref _config); } }); this.WhenAnyValue( x => x.CurrentLanguage, y => y != null && !y.IsNullOrEmpty()) .Subscribe(c => { if (!Utils.IsNullOrEmpty(CurrentLanguage)) { if (ForInitiationLanguage) { ForInitiationLanguage = false; } else { if (IsForSettingBackLanguage) { IsForSettingBackLanguage = false; return; } //var userRes = UI.ShowYesNo(ResUI.MsgProgramNeedsRestarting); //if (userRes == DialogResult.Yes) { Thread.CurrentThread.CurrentUICulture = new(CurrentLanguage); CultureInfo.DefaultThreadCurrentUICulture = new(_config.uiItem.currentLanguage); _config.uiItem.currentLanguage = CurrentLanguage; ConfigHandler.SaveConfig(ref _config); // Restart program // PreExit(true); //Utils.RestartProgram(); Thread.CurrentThread.CurrentUICulture = new(_config.uiItem.currentLanguage); var newWindow = new MainWindow(); // copy over any necessary properties from the old window newWindow.DataContext = this; // show the new window and close the old window var old = Application.Current.MainWindow; newWindow.Show(); newWindow.WindowState = WindowState.Minimized; newWindow.WindowState = WindowState.Normal; newWindow.Activate(); newWindow.Topmost = true; newWindow.Topmost = false; newWindow.Focus(); newWindow.Show(); old.Close(); Application.Current.MainWindow = newWindow; // Refresh subs information when language changed InitSubscriptionView(); // Exit the current instance of the application //Application.Current.Shutdown(); } /*else { //TODO: it doesn't setting back language, in fact it does for variable but in ui doesn't IsForSettingBackLanguage = true; CurrentLanguage = _config.uiItem.currentLanguage; }*/ } } }); } public void InboundDisplayStaus() { StringBuilder sb = new(); sb.Append($"[{Global.InboundSocks}:{LazyConfig.Instance.GetLocalPort(Global.InboundSocks)}]"); sb.Append(" | "); //if (_config.sysProxyType == ESysProxyType.ForcedChange) //{ // sb.Append($"[{Global.InboundHttp}({ResUI.SystemProxy}):{LazyConfig.Instance.GetLocalPort(Global.InboundHttp)}]"); //} //else //{ sb.Append($"[{Global.InboundHttp}:{LazyConfig.Instance.GetLocalPort(Global.InboundHttp)}]"); //} InboundDisplay = $"{ResUI.LabLocal}:{sb}"; if (_config.inbound[0].allowLANConn) { if (_config.inbound[0].newPort4LAN) { StringBuilder sb2 = new(); sb2.Append($"[{Global.InboundSocks}:{LazyConfig.Instance.GetLocalPort(Global.InboundSocks2)}]"); sb2.Append(" | "); sb2.Append($"[{Global.InboundHttp}:{LazyConfig.Instance.GetLocalPort(Global.InboundHttp2)}]"); InboundLanDisplay = $"{ResUI.LabLAN}:{sb2}"; } else { InboundLanDisplay = $"{ResUI.LabLAN}:{sb}"; } } else { InboundLanDisplay = $"{ResUI.LabLAN}:None"; } } public void ModifyTheme(bool isDarkTheme) { var theme = _paletteHelper.GetTheme(); theme.SetBaseTheme(isDarkTheme ? Theme.Dark : Theme.Light); _paletteHelper.SetTheme(theme); Utils.SetDarkBorder(Application.Current.MainWindow, isDarkTheme); } public void ChangePrimaryColor(System.Windows.Media.Color color) { var theme = _paletteHelper.GetTheme(); theme.PrimaryLight = new ColorPair(color.Lighten()); theme.PrimaryMid = new ColorPair(color); theme.PrimaryDark = new ColorPair(color.Darken()); _paletteHelper.SetTheme(theme); } private void AutoHideStartup() { if (_config.uiItem.autoHideStartup) { Observable.Range(1, 1) .Delay(TimeSpan.FromSeconds(2)) .Subscribe(x => { Application.Current.Dispatcher.Invoke(() => { ShowHideWindow(false); }); }); } } #endregion UI #region Home public void HomeNewProfile() { // Get clipboard data string? cData = Utils.GetClipboardData(); if (cData == null) { // TODO @everyone: translate this response UI.ShowError("There's no config/url/link"); } else { var (addedServersCount, addedSubsIds) = HomeAddServerOrSubViaClipboard(cData); // If nothing added, we show some error to user if (addedServersCount == 0 && (addedSubsIds == null || addedSubsIds.Count < 1)) { // TODO @everyone: translate this response UI.ShowError("There's invalid config/url/link"); } else { string msg = ""; if (addedServersCount > 0) { msg = $"Added servers: {addedServersCount}"; } if (addedSubsIds?.Count > 0) { SelectedSub= LazyConfig.Instance.GetSubItem(addedSubsIds[0]); msg += $"\nAdded subscription: {addedSubsIds?.Count}"; } UI.Show(msg); } } } public void HomeUpdateUsage(SubItem sub) { if (sub != null) { var headers = Utils.GetUrlResponseHeader(sub.url,false); if (headers != null) { var subInfo = Utils.GetSubscriptionInfoFromHeaders(headers); if (subInfo != null) { sub.upload = subInfo.Upload; sub.download = subInfo.Download; sub.total = subInfo.Total; sub.expireDate = subInfo.ExpireDate; sub.remaningExpireDays = sub.DaysLeftToExpire(); sub.UsedDataGB = sub.UsedDataGigaBytes(); sub.TotalDataGB = sub.TotalDataGigaBytes(); sub.profileWebPageUrl = subInfo.ProfileWebPageUrl; // Replace the sub with new information if (ConfigHandler.AddSubItem(ref _config, sub,true) == 0) { //successed } else { //failed } } } } } public async Task HomeConnect(bool forceConnect = false) { //var result = DialogHost.Show("hi!", "RootDialog"); if (SelectedSub == null) { _noticeHandler.Enqueue("Please select a sub"); return; } // It's disconnected or it should be connected again if (forceConnect || !IsConnected) { // Change connectVPN button color ConnectProgress = true; ConnectColor = "#eab676"; SelectAppropiateServer(); //await HomeRealPingServer(_config.indexId); // Till now, we started a server // Now we calculate real ping of the server to make sure, it's working // If user selected load balance/auto we can't get "real ping" (i don't know why?!) // So, Insted of "real ping", we just send a request and check the http response status if (HomeSelectedProxyMode != null && (HomeSelectedProxyMode== ProxyModeEnum.Smart || HomeSelectedProxyMode==ProxyModeEnum.Loadbalance)) { DelayProgress = true; ConnectVPNLabel = ResUI.HomeConnecting; bool useProxy = Utils.IsSystemProxyEnabled(_config.sysProxyType); var startTime = DateTime.Now; var isStatusCode204 = await Utils.IsUrlStatusCode204(Global.SpeedPingTestUrlCloadFlare,useProxy); var delay = (DateTime.Now - startTime).Milliseconds; // Check returned status code if (isStatusCode204) { // Set server delay SelectedProfileDelay = delay; // The server works DelayProgress = false; ConnectProgress = false; ConnectVPNLabelColor = "#7CFC0000"; ConnectVPNLabel = ResUI.HomeConnected; ConnectColor = "#33d91a"; IsConnected = true; SetSysProxy(); return; } else { SelectedProfileDelay = -1; // The server doesn't work DelayProgress = false; ConnectProgress = false; ConnectColor = "#d6003b"; ConnectVPNLabel = ResUI.HomeNotConnected; IsConnected = false; return; } } // the "Manual" mode is selected; neither "Auto" or "Load Balance" else { DelayProgress = true; HomeRealPingServer(_config.indexId); // Wait for delay calculation (10 seconds) ConnectVPNLabel = ResUI.HomeConnecting; short count = 1; while (!IsDelayCalculationFinished) { // We don't want to stuck in a infinite loop if (count == 25) break; await Task.Delay(400).ConfigureAwait(false); count += 1; } ConnectProgress = false; DelayProgress = false; //DialogHost.CloseDialogCommand.Execute("",null); // Check delay if (SelectedProfileDelay > 0 && SelectedProfileDelay != -1) { // The server works //TODO: @hiddify1; change the connectVPN color to whatever should be ConnectVPNLabelColor = "#7CFC0000"; ConnectVPNLabel = ResUI.HomeConnected; ConnectColor = "#33d91a"; IsConnected = true; SetSysProxy(); return; } else { // The server doesn't work ConnectColor = "#d6003b"; ConnectVPNLabel = ResUI.HomeNotConnected; IsConnected = false; return; } } } // It's connected, should be disconnected { //TODO: @hiddify1; change the connectVPN color to whatever should be //ConnectColor = "#FFFF0000"; ConnectColor = "#d6003b"; ConnectVPNLabel = ResUI.HomeDisconnected; ConnectVPNLabelColor = "#FFFF0000"; IsConnected = false; UnsetSysProxy(); } } public void HomeGotoProfile(string subId) { SubItem sub = LazyConfig.Instance.GetSubItem(subId); var ret = (new SubEditWindow(sub)).ShowDialog(); if (ret == true) { InitSubscriptionView(); } } private void HomeDeleteSub() { if (SelectedSub != null) { if (UI.ShowYesNo(ResUI.RemoveServer) == MessageBoxResult.No) return; else { ConfigHandler.DeleteSubItem(ref _config, SelectedSub.id); InitSubscriptionView(); } } } public void HomeSelectedRouteChanged() { Console.WriteLine(HomeSelectedRoutingItem); } public async Task HomeSelectedProxyChanged() { ProfileExpanded = false; if (HomeSelectedProxyMode== ProxyModeEnum.Manual) { ToggleV2rayPanel(); return; } else if (V2RayNPanelVisible) { ToggleV2rayPanel(); } if (IsConnected) { await HomeConnect(true).ConfigureAwait(false); } } #endregion private void ToggleV2rayPanel() { V2RayNPanelVisible = !V2RayNPanelVisible; MaxWindowWidth = V2RayNPanelVisible ? 2100 : 420; WindowWidth = V2RayNPanelVisible ? 1200 : 420; ColorModeDark = !ColorModeDark; ColorModeDark = !ColorModeDark; } private ProfileItem? GetSelectedServer(string subId,ProxyModeEnum proxyMode) { if (subId.IsNullOrEmpty() || proxyMode==null) return null; // Get selected sub items proxies/servers var subServers = LazyConfig.Instance.ProfileItems(SelectedSub.id); if (subServers.Count < 1) { return null; } if (proxyMode == ProxyModeEnum.Manual) return null; ProfileItem server = null; if (proxyMode == ProxyModeEnum.Smart) { server = subServers.FirstOrDefault(s => s.remarks == "Lowest Ping"); } else if (proxyMode == ProxyModeEnum.Loadbalance) { server = subServers.FirstOrDefault(s => s.remarks == "Load Balance"); } else { return null; } return server; } private async Task HomeRealPingServer(string serverIndexId) { SelectedProfileDelay = 0; IsDelayCalculationFinished = false; //DelayProgress = true; ProfileItem server = LazyConfig.Instance.GetProfileItem(serverIndexId); if (server != null) { //ClearTestResult(); await Task.Run(() => { new SpeedtestHandler(_config, _coreHandler, new List() { server }, ESpeedActionType.Realping, UpdateHomeRealPingServer); }); } } private void UpdateHomeRealPingServer(string indexId, string delay, string speed) { bool isNumberic = int.TryParse(delay, out int res); if (isNumberic) { SelectedProfileDelay = Convert.ToInt32(res); IsDelayCalculationFinished = true; //DelayProgress = false; } } } } ================================================ FILE: v2rayN/v2rayN/ViewModels/OptionSettingViewModel.cs ================================================ using ReactiveUI; using ReactiveUI.Fody.Helpers; using Splat; using System.Reactive; using System.Windows; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; namespace v2rayN.ViewModels { public class OptionSettingViewModel : ReactiveObject { private static Config _config; private NoticeHandler? _noticeHandler; private Window _view; #region Core [Reactive] public int localPort { get; set; } [Reactive] public bool udpEnabled { get; set; } [Reactive] public bool sniffingEnabled { get; set; } [Reactive] public bool routeOnly { get; set; } [Reactive] public bool allowLANConn { get; set; } [Reactive] public bool newPort4LAN { get; set; } [Reactive] public string user { get; set; } [Reactive] public string pass { get; set; } [Reactive] public bool muxEnabled { get; set; } [Reactive] public bool logEnabled { get; set; } [Reactive] public string loglevel { get; set; } [Reactive] public bool defAllowInsecure { get; set; } [Reactive] public string defFingerprint { get; set; } [Reactive] public string defUserAgent { get; set; } #endregion Core #region Core KCP //[Reactive] public int Kcpmtu { get; set; } //[Reactive] public int Kcptti { get; set; } //[Reactive] public int KcpuplinkCapacity { get; set; } //[Reactive] public int KcpdownlinkCapacity { get; set; } //[Reactive] public int KcpreadBufferSize { get; set; } //[Reactive] public int KcpwriteBufferSize { get; set; } //[Reactive] public bool Kcpcongestion { get; set; } #endregion Core KCP #region UI [Reactive] public bool AutoRun { get; set; } [Reactive] public bool EnableStatistics { get; set; } [Reactive] public int StatisticsFreshRate { get; set; } [Reactive] public bool KeepOlderDedupl { get; set; } [Reactive] public bool IgnoreGeoUpdateCore { get; set; } [Reactive] public bool EnableAutoAdjustMainLvColWidth { get; set; } [Reactive] public bool EnableSecurityProtocolTls13 { get; set; } = true; [Reactive] public bool AutoHideStartup { get; set; } [Reactive] public bool EnableCheckPreReleaseUpdate { get; set; } [Reactive] public bool EnableDragDropSort { get; set; } [Reactive] public bool DoubleClick2Activate { get; set; } [Reactive] public int autoUpdateInterval { get; set; } [Reactive] public int trayMenuServersLimit { get; set; } [Reactive] public string currentFontFamily { get; set; } [Reactive] public int SpeedTestTimeout { get; set; } [Reactive] public string SpeedTestUrl { get; set; } [Reactive] public bool EnableHWA { get; set; } [Reactive] public string SubConvertUrl { get; set; } #endregion UI #region System proxy [Reactive] public string systemProxyAdvancedProtocol { get; set; } [Reactive] public string systemProxyExceptions { get; set; } #endregion System proxy #region Tun mode [Reactive] public bool TunShowWindow { get; set; } [Reactive] public bool TunEnabledLog { get; set; } [Reactive] public bool TunStrictRoute { get; set; } [Reactive] public string TunStack { get; set; } [Reactive] public int TunMtu { get; set; } [Reactive] public string TunCustomTemplate { get; set; } [Reactive] public bool TunBypassMode { get; set; } [Reactive] public bool TunBypassMode2 { get; set; } [Reactive] public string TunDirectIP { get; set; } [Reactive] public string TunDirectProcess { get; set; } [Reactive] public string TunDirectDNS { get; set; } [Reactive] public string TunProxyIP { get; set; } [Reactive] public string TunProxyProcess { get; set; } [Reactive] public string TunProxyDNS { get; set; } #endregion Tun mode #region CoreType [Reactive] public string CoreType1 { get; set; } [Reactive] public string CoreType2 { get; set; } [Reactive] public string CoreType3 { get; set; } [Reactive] public string CoreType4 { get; set; } [Reactive] public string CoreType5 { get; set; } [Reactive] public string CoreType6 { get; set; } #endregion CoreType public ReactiveCommand SaveCmd { get; } public OptionSettingViewModel(Window view) { _config = LazyConfig.Instance.GetConfig(); _noticeHandler = Locator.Current.GetService(); _view = view; #region Core var inbound = _config.inbound[0]; localPort = inbound.localPort; udpEnabled = inbound.udpEnabled; sniffingEnabled = inbound.sniffingEnabled; routeOnly = inbound.routeOnly; allowLANConn = inbound.allowLANConn; newPort4LAN = inbound.newPort4LAN; user = inbound.user; pass = inbound.pass; muxEnabled = _config.coreBasicItem.muxEnabled; logEnabled = _config.coreBasicItem.logEnabled; loglevel = _config.coreBasicItem.loglevel; defAllowInsecure = _config.coreBasicItem.defAllowInsecure; defFingerprint = _config.coreBasicItem.defFingerprint; defUserAgent = _config.coreBasicItem.defUserAgent; #endregion Core #region Core KCP //Kcpmtu = _config.kcpItem.mtu; //Kcptti = _config.kcpItem.tti; //KcpuplinkCapacity = _config.kcpItem.uplinkCapacity; //KcpdownlinkCapacity = _config.kcpItem.downlinkCapacity; //KcpreadBufferSize = _config.kcpItem.readBufferSize; //KcpwriteBufferSize = _config.kcpItem.writeBufferSize; //Kcpcongestion = _config.kcpItem.congestion; #endregion Core KCP #region UI AutoRun = _config.guiItem.autoRun; EnableStatistics = _config.guiItem.enableStatistics; StatisticsFreshRate = _config.guiItem.statisticsFreshRate; KeepOlderDedupl = _config.guiItem.keepOlderDedupl; IgnoreGeoUpdateCore = _config.guiItem.ignoreGeoUpdateCore; EnableAutoAdjustMainLvColWidth = _config.uiItem.enableAutoAdjustMainLvColWidth; EnableSecurityProtocolTls13 = _config.guiItem.enableSecurityProtocolTls13; AutoHideStartup = _config.uiItem.autoHideStartup; EnableCheckPreReleaseUpdate = _config.guiItem.checkPreReleaseUpdate; EnableDragDropSort = _config.uiItem.enableDragDropSort; DoubleClick2Activate = _config.uiItem.doubleClick2Activate; autoUpdateInterval = _config.guiItem.autoUpdateInterval; trayMenuServersLimit = _config.guiItem.trayMenuServersLimit; currentFontFamily = _config.uiItem.currentFontFamily; SpeedTestTimeout = _config.speedTestItem.speedTestTimeout; SpeedTestUrl = _config.speedTestItem.speedTestUrl; EnableHWA = _config.guiItem.enableHWA; SubConvertUrl = _config.constItem.subConvertUrl; #endregion UI #region System proxy systemProxyAdvancedProtocol = _config.systemProxyAdvancedProtocol; systemProxyExceptions = _config.systemProxyExceptions; #endregion System proxy #region Tun mode TunShowWindow = _config.tunModeItem.showWindow; TunEnabledLog = _config.tunModeItem.enabledLog; TunStrictRoute = _config.tunModeItem.strictRoute; TunStack = _config.tunModeItem.stack; TunMtu = _config.tunModeItem.mtu; TunCustomTemplate = _config.tunModeItem.customTemplate; TunBypassMode = _config.tunModeItem.bypassMode; TunDirectIP = Utils.List2String(_config.tunModeItem.directIP, true); TunDirectProcess = Utils.List2String(_config.tunModeItem.directProcess, true); TunDirectDNS = _config.tunModeItem.directDNS; TunProxyIP = Utils.List2String(_config.tunModeItem.proxyIP, true); TunProxyProcess = Utils.List2String(_config.tunModeItem.proxyProcess, true); TunProxyDNS = _config.tunModeItem.proxyDNS; this.WhenAnyValue( x => x.TunBypassMode) .Subscribe(c => TunBypassMode2 = !TunBypassMode); #endregion Tun mode InitCoreType(); SaveCmd = ReactiveCommand.Create(() => { SaveSetting(); }); Utils.SetDarkBorder(view, _config.uiItem.colorModeDark); } private void InitCoreType() { if (_config.coreTypeItem == null) { _config.coreTypeItem = new List(); } foreach (EConfigType it in Enum.GetValues(typeof(EConfigType))) { if (_config.coreTypeItem.FindIndex(t => t.configType == it) >= 0) { continue; } _config.coreTypeItem.Add(new CoreTypeItem() { configType = it, coreType = ECoreType.Xray }); } _config.coreTypeItem.ForEach(it => { var type = it.coreType.ToString(); switch ((int)it.configType) { case 1: CoreType1 = type; break; case 2: CoreType2 = type; break; case 3: CoreType3 = type; break; case 4: CoreType4 = type; break; case 5: CoreType5 = type; break; case 6: CoreType6 = type; break; } }); } private void SaveSetting() { if (Utils.IsNullOrEmpty(localPort.ToString()) || !Utils.IsNumberic(localPort.ToString()) || localPort <= 0 || localPort >= Global.MaxPort) { UI.Show(ResUI.FillLocalListeningPort); return; } //if (Utils.IsNullOrEmpty(Kcpmtu.ToString()) || !Utils.IsNumberic(Kcpmtu.ToString()) // || Utils.IsNullOrEmpty(Kcptti.ToString()) || !Utils.IsNumberic(Kcptti.ToString()) // || Utils.IsNullOrEmpty(KcpuplinkCapacity.ToString()) || !Utils.IsNumberic(KcpuplinkCapacity.ToString()) // || Utils.IsNullOrEmpty(KcpdownlinkCapacity.ToString()) || !Utils.IsNumberic(KcpdownlinkCapacity.ToString()) // || Utils.IsNullOrEmpty(KcpreadBufferSize.ToString()) || !Utils.IsNumberic(KcpreadBufferSize.ToString()) // || Utils.IsNullOrEmpty(KcpwriteBufferSize.ToString()) || !Utils.IsNumberic(KcpwriteBufferSize.ToString())) //{ // UI.Show(ResUI.FillKcpParameters); // return; //} //Core _config.inbound[0].localPort = localPort; _config.inbound[0].udpEnabled = udpEnabled; _config.inbound[0].sniffingEnabled = sniffingEnabled; _config.inbound[0].routeOnly = routeOnly; _config.inbound[0].allowLANConn = allowLANConn; _config.inbound[0].newPort4LAN = newPort4LAN; _config.inbound[0].user = user; _config.inbound[0].pass = pass; if (_config.inbound.Count > 1) { _config.inbound.RemoveAt(1); } _config.coreBasicItem.logEnabled = logEnabled; _config.coreBasicItem.loglevel = loglevel; _config.coreBasicItem.muxEnabled = muxEnabled; _config.coreBasicItem.defAllowInsecure = defAllowInsecure; _config.coreBasicItem.defFingerprint = defFingerprint; _config.coreBasicItem.defUserAgent = defUserAgent; //Kcp //_config.kcpItem.mtu = Kcpmtu; //_config.kcpItem.tti = Kcptti; //_config.kcpItem.uplinkCapacity = KcpuplinkCapacity; //_config.kcpItem.downlinkCapacity = KcpdownlinkCapacity; //_config.kcpItem.readBufferSize = KcpreadBufferSize; //_config.kcpItem.writeBufferSize = KcpwriteBufferSize; //_config.kcpItem.congestion = Kcpcongestion; //UI Utils.SetAutoRun(AutoRun); _config.guiItem.autoRun = AutoRun; _config.guiItem.enableStatistics = EnableStatistics; _config.guiItem.statisticsFreshRate = StatisticsFreshRate; if (_config.guiItem.statisticsFreshRate > 100 || _config.guiItem.statisticsFreshRate < 1) { _config.guiItem.statisticsFreshRate = 1; } _config.guiItem.keepOlderDedupl = KeepOlderDedupl; _config.guiItem.ignoreGeoUpdateCore = IgnoreGeoUpdateCore; _config.uiItem.enableAutoAdjustMainLvColWidth = EnableAutoAdjustMainLvColWidth; _config.guiItem.enableSecurityProtocolTls13 = EnableSecurityProtocolTls13; _config.uiItem.autoHideStartup = AutoHideStartup; _config.guiItem.autoUpdateInterval = autoUpdateInterval; _config.guiItem.checkPreReleaseUpdate = EnableCheckPreReleaseUpdate; _config.uiItem.enableDragDropSort = EnableDragDropSort; _config.uiItem.doubleClick2Activate = DoubleClick2Activate; _config.guiItem.trayMenuServersLimit = trayMenuServersLimit; _config.uiItem.currentFontFamily = currentFontFamily; _config.speedTestItem.speedTestTimeout = SpeedTestTimeout; _config.speedTestItem.speedTestUrl = SpeedTestUrl; _config.guiItem.enableHWA = EnableHWA; _config.constItem.subConvertUrl = SubConvertUrl; //systemProxy _config.systemProxyExceptions = systemProxyExceptions; _config.systemProxyAdvancedProtocol = systemProxyAdvancedProtocol; //tun mode _config.tunModeItem.showWindow = TunShowWindow; _config.tunModeItem.enabledLog = TunEnabledLog; _config.tunModeItem.strictRoute = TunStrictRoute; _config.tunModeItem.stack = TunStack; _config.tunModeItem.mtu = TunMtu; _config.tunModeItem.customTemplate = TunCustomTemplate; _config.tunModeItem.bypassMode = TunBypassMode; _config.tunModeItem.directIP = Utils.String2List(Utils.Convert2Comma(TunDirectIP)); _config.tunModeItem.directProcess = Utils.String2List(Utils.Convert2Comma(TunDirectProcess)); _config.tunModeItem.directDNS = Utils.ToJson(Utils.ParseJson(TunDirectDNS)); _config.tunModeItem.proxyIP = Utils.String2List(Utils.Convert2Comma(TunProxyIP)); _config.tunModeItem.proxyProcess = Utils.String2List(Utils.Convert2Comma(TunProxyProcess)); _config.tunModeItem.proxyDNS = Utils.ToJson(Utils.ParseJson(TunProxyDNS)); //coreType SaveCoreType(); if (ConfigHandler.SaveConfig(ref _config) == 0) { _noticeHandler?.Enqueue(ResUI.OperationSuccess); _view.DialogResult = true; } else { UI.ShowWarning(ResUI.OperationFailed); } } private int SaveCoreType() { for (int k = 1; k <= _config.coreTypeItem.Count; k++) { var item = _config.coreTypeItem[k - 1]; var type = string.Empty; switch ((int)item.configType) { case 1: type = CoreType1; break; case 2: type = CoreType2; break; case 3: type = CoreType3; break; case 4: type = CoreType4; break; case 5: type = CoreType5; break; case 6: type = CoreType6; break; case 101: case 102: case 103: type = CoreType2; break; } item.coreType = (ECoreType)Enum.Parse(typeof(ECoreType), type); } return 0; } } } ================================================ FILE: v2rayN/v2rayN/ViewModels/RoutingRuleDetailsViewModel.cs ================================================ using ReactiveUI; using ReactiveUI.Fody.Helpers; using Splat; using System.Reactive; using System.Windows; using v2rayN.Base; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; namespace v2rayN.ViewModels { public class RoutingRuleDetailsViewModel : ReactiveObject { private static Config _config; private NoticeHandler? _noticeHandler; private Window _view; public IList ProtocolItems { get; set; } public IList InboundTagItems { get; set; } [Reactive] public RulesItem SelectedSource { get; set; } [Reactive] public string Domain { get; set; } [Reactive] public string IP { get; set; } [Reactive] public bool AutoSort { get; set; } public ReactiveCommand SaveCmd { get; } public RoutingRuleDetailsViewModel(RulesItem rulesItem, Window view) { _config = LazyConfig.Instance.GetConfig(); _noticeHandler = Locator.Current.GetService(); _view = view; if (rulesItem.id.IsNullOrEmpty()) { rulesItem.id = Utils.GetGUID(false); rulesItem.outboundTag = Global.agentTag; rulesItem.enabled = true; SelectedSource = rulesItem; } else { SelectedSource = rulesItem; } Domain = Utils.List2String(SelectedSource.domain, true); IP = Utils.List2String(SelectedSource.ip, true); SaveCmd = ReactiveCommand.Create(() => { SaveRules(); }); Utils.SetDarkBorder(view, _config.uiItem.colorModeDark); } private void SaveRules() { Domain = Utils.Convert2Comma(Domain); IP = Utils.Convert2Comma(IP); if (AutoSort) { SelectedSource.domain = Utils.String2ListSorted(Domain); SelectedSource.ip = Utils.String2ListSorted(IP); } else { SelectedSource.domain = Utils.String2List(Domain); SelectedSource.ip = Utils.String2List(IP); } SelectedSource.protocol = ProtocolItems?.ToList(); SelectedSource.inboundTag = InboundTagItems?.ToList(); bool hasRule = SelectedSource.domain != null && SelectedSource.domain.Count > 0 || SelectedSource.ip != null && SelectedSource.ip.Count > 0 || SelectedSource.protocol != null && SelectedSource.protocol.Count > 0 || !Utils.IsNullOrEmpty(SelectedSource.port); if (!hasRule) { UI.ShowWarning(string.Format(ResUI.RoutingRuleDetailRequiredTips, "Port/Protocol/Domain/IP")); return; } //_noticeHandler?.Enqueue(ResUI.OperationSuccess); _view.DialogResult = true; } } } ================================================ FILE: v2rayN/v2rayN/ViewModels/RoutingRuleSettingViewModel.cs ================================================ using DynamicData.Binding; using Microsoft.Win32; using ReactiveUI; using ReactiveUI.Fody.Helpers; using Splat; using System.Reactive; using System.Windows; using v2rayN.Base; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; using v2rayN.Views; using Application = System.Windows.Application; namespace v2rayN.ViewModels { public class RoutingRuleSettingViewModel : ReactiveObject { private static Config _config; private NoticeHandler? _noticeHandler; private Window _view; private List _rules; [Reactive] public RoutingItem SelectedRouting { get; set; } private IObservableCollection _rulesItems = new ObservableCollectionExtended(); public IObservableCollection RulesItems => _rulesItems; [Reactive] public RulesItemModel SelectedSource { get; set; } public IList SelectedSources { get; set; } public ReactiveCommand RuleAddCmd { get; } public ReactiveCommand ImportRulesFromFileCmd { get; } public ReactiveCommand ImportRulesFromClipboardCmd { get; } public ReactiveCommand ImportRulesFromUrlCmd { get; } public ReactiveCommand RuleRemoveCmd { get; } public ReactiveCommand RuleExportSelectedCmd { get; } public ReactiveCommand MoveTopCmd { get; } public ReactiveCommand MoveUpCmd { get; } public ReactiveCommand MoveDownCmd { get; } public ReactiveCommand MoveBottomCmd { get; } public ReactiveCommand SaveCmd { get; } public RoutingRuleSettingViewModel(RoutingItem routingItem, Window view) { _config = LazyConfig.Instance.GetConfig(); _noticeHandler = Locator.Current.GetService(); _view = view; SelectedSource = new(); if (routingItem.id.IsNullOrEmpty()) { SelectedRouting = routingItem; _rules = new(); } else { SelectedRouting = routingItem; _rules = Utils.FromJson>(SelectedRouting.ruleSet); } RefreshRulesItems(); var canEditRemove = this.WhenAnyValue( x => x.SelectedSource, selectedSource => selectedSource != null && !selectedSource.outboundTag.IsNullOrEmpty()); RuleAddCmd = ReactiveCommand.Create(() => { RuleEdit(true); }); ImportRulesFromFileCmd = ReactiveCommand.Create(() => { ImportRulesFromFile(); }); ImportRulesFromClipboardCmd = ReactiveCommand.Create(() => { ImportRulesFromClipboard(); }); ImportRulesFromUrlCmd = ReactiveCommand.Create(() => { ImportRulesFromUrl(); }); RuleRemoveCmd = ReactiveCommand.Create(() => { RuleRemove(); }, canEditRemove); RuleExportSelectedCmd = ReactiveCommand.Create(() => { RuleExportSelected(); }, canEditRemove); MoveTopCmd = ReactiveCommand.Create(() => { MoveRule(EMove.Top); }, canEditRemove); MoveUpCmd = ReactiveCommand.Create(() => { MoveRule(EMove.Up); }, canEditRemove); MoveDownCmd = ReactiveCommand.Create(() => { MoveRule(EMove.Down); }, canEditRemove); MoveBottomCmd = ReactiveCommand.Create(() => { MoveRule(EMove.Bottom); }, canEditRemove); SaveCmd = ReactiveCommand.Create(() => { SaveRouting(); }); Utils.SetDarkBorder(view, _config.uiItem.colorModeDark); } public void RefreshRulesItems() { _rulesItems.Clear(); foreach (var item in _rules) { var it = new RulesItemModel() { id = item.id, outboundTag = item.outboundTag, port = item.port, protocols = Utils.List2String(item.protocol), inboundTags = Utils.List2String(item.inboundTag), domains = Utils.List2String(item.domain), ips = Utils.List2String(item.ip), enabled = item.enabled, }; _rulesItems.Add(it); } } public void RuleEdit(bool blNew) { RulesItem item; if (blNew) { item = new(); } else { item = _rules.FirstOrDefault(t => t.id == SelectedSource?.id); if (item is null) { return; } } var ret = (new RoutingRuleDetailsWindow(item)).ShowDialog(); if (ret == true) { if (blNew) { _rules.Add(item); } RefreshRulesItems(); } } public void RuleRemove() { if (SelectedSource is null || SelectedSource.outboundTag.IsNullOrEmpty()) { UI.Show(ResUI.PleaseSelectRules); return; } if (UI.ShowYesNo(ResUI.RemoveRules) == MessageBoxResult.No) { return; } foreach (var it in SelectedSources) { var item = _rules.FirstOrDefault(t => t.id == it?.id); if (item != null) { _rules.Remove(item); } } RefreshRulesItems(); } public void RuleExportSelected() { if (SelectedSource is null || SelectedSource.outboundTag.IsNullOrEmpty()) { UI.Show(ResUI.PleaseSelectRules); return; } var lst = new List(); foreach (var it in SelectedSources) { var item = _rules.FirstOrDefault(t => t.id == it?.id); if (item != null) { lst.Add(item); } } if (lst.Count > 0) { Utils.SetClipboardData(Utils.ToJson(lst)); //UI.Show(ResUI.OperationSuccess")); } } public void MoveRule(EMove eMove) { if (SelectedSource is null || SelectedSource.outboundTag.IsNullOrEmpty()) { UI.Show(ResUI.PleaseSelectRules); return; } var item = _rules.FirstOrDefault(t => t.id == SelectedSource?.id); if (item == null) { return; } var index = _rules.IndexOf(item); if (ConfigHandler.MoveRoutingRule(_rules, index, eMove) == 0) { RefreshRulesItems(); } } private void SaveRouting() { string remarks = SelectedRouting.remarks; if (Utils.IsNullOrEmpty(remarks)) { UI.Show(ResUI.PleaseFillRemarks); return; } var item = SelectedRouting; foreach (var it in _rules) { it.id = Utils.GetGUID(false); } item.ruleNum = _rules.Count; item.ruleSet = Utils.ToJson(_rules, false); if (ConfigHandler.SaveRoutingItem(ref _config, item) == 0) { _noticeHandler?.Enqueue(ResUI.OperationSuccess); _view.DialogResult = true; } else { UI.ShowWarning(ResUI.OperationFailed); } } #region Import rules private void ImportRulesFromFile() { OpenFileDialog fileDialog = new OpenFileDialog { Multiselect = false, Filter = "Rules|*.json|All|*.*" }; if (fileDialog.ShowDialog() != true) { return; } string fileName = fileDialog.FileName; if (Utils.IsNullOrEmpty(fileName)) { return; } string result = Utils.LoadResource(fileName); if (Utils.IsNullOrEmpty(result)) { return; } if (AddBatchRoutingRules(SelectedRouting, result) == 0) { RefreshRulesItems(); UI.Show(ResUI.OperationSuccess); } } private void ImportRulesFromClipboard() { string clipboardData = Utils.GetClipboardData(); if (AddBatchRoutingRules(SelectedRouting, clipboardData) == 0) { RefreshRulesItems(); UI.Show(ResUI.OperationSuccess); } } private async Task ImportRulesFromUrl() { var url = SelectedRouting.url; if (Utils.IsNullOrEmpty(url)) { UI.Show(ResUI.MsgNeedUrl); return; } DownloadHandle downloadHandle = new DownloadHandle(); string result = await downloadHandle.TryDownloadString(url, true, ""); if (AddBatchRoutingRules(SelectedRouting, result) == 0) { Application.Current.Dispatcher.Invoke((Action)(() => { RefreshRulesItems(); })); UI.Show(ResUI.OperationSuccess); } } private int AddBatchRoutingRules(RoutingItem routingItem, string clipboardData) { bool blReplace = false; if (UI.ShowYesNo(ResUI.AddBatchRoutingRulesYesNo) == MessageBoxResult.No) { blReplace = true; } if (Utils.IsNullOrEmpty(clipboardData)) { return -1; } var lstRules = Utils.FromJson>(clipboardData); if (lstRules == null) { return -1; } foreach (var rule in lstRules) { rule.id = Utils.GetGUID(false); } if (blReplace) { _rules = lstRules; } else { _rules.AddRange(lstRules); } return 0; } #endregion Import rules } } ================================================ FILE: v2rayN/v2rayN/ViewModels/RoutingSettingViewModel.cs ================================================ using DynamicData.Binding; using ReactiveUI; using ReactiveUI.Fody.Helpers; using Splat; using System.Reactive; using System.Windows; using v2rayN.Base; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; using v2rayN.Views; namespace v2rayN.ViewModels { public class RoutingSettingViewModel : ReactiveObject { private static Config _config; private NoticeHandler? _noticeHandler; private Window _view; private RoutingItem _lockedItem; private List _lockedRules; #region Reactive private IObservableCollection _routingItems = new ObservableCollectionExtended(); public IObservableCollection RoutingItems => _routingItems; [Reactive] public RoutingItemModel SelectedSource { get; set; } public IList SelectedSources { get; set; } [Reactive] public bool enableRoutingAdvanced { get; set; } [Reactive] public bool enableRoutingBasic { get; set; } [Reactive] public string domainStrategy { get; set; } [Reactive] public string domainMatcher { get; set; } [Reactive] public string domainStrategy4Singbox { get; set; } [Reactive] public string ProxyDomain { get; set; } [Reactive] public string ProxyIP { get; set; } [Reactive] public string DirectDomain { get; set; } [Reactive] public string DirectIP { get; set; } [Reactive] public string BlockDomain { get; set; } [Reactive] public string BlockIP { get; set; } public ReactiveCommand RoutingBasicImportRulesCmd { get; } public ReactiveCommand RoutingAdvancedAddCmd { get; } public ReactiveCommand RoutingAdvancedRemoveCmd { get; } public ReactiveCommand RoutingAdvancedSetDefaultCmd { get; } public ReactiveCommand RoutingAdvancedImportRulesCmd { get; } public ReactiveCommand SaveCmd { get; } public bool IsModified { get; set; } #endregion Reactive public RoutingSettingViewModel(Window view) { _config = LazyConfig.Instance.GetConfig(); _noticeHandler = Locator.Current.GetService(); _view = view; SelectedSource = new(); ConfigHandler.InitBuiltinRouting(ref _config); enableRoutingAdvanced = _config.routingBasicItem.enableRoutingAdvanced; domainStrategy = _config.routingBasicItem.domainStrategy; domainMatcher = _config.routingBasicItem.domainMatcher; domainStrategy4Singbox = _config.routingBasicItem.domainStrategy4Singbox; RefreshRoutingItems(); BindingLockedData(); var canEditRemove = this.WhenAnyValue( x => x.SelectedSource, selectedSource => selectedSource != null && !selectedSource.remarks.IsNullOrEmpty()); this.WhenAnyValue( x => x.enableRoutingAdvanced) .Subscribe(c => enableRoutingBasic = !enableRoutingAdvanced); RoutingBasicImportRulesCmd = ReactiveCommand.Create(() => { RoutingBasicImportRules(); }); RoutingAdvancedAddCmd = ReactiveCommand.Create(() => { RoutingAdvancedEdit(true); }); RoutingAdvancedRemoveCmd = ReactiveCommand.Create(() => { RoutingAdvancedRemove(); }, canEditRemove); RoutingAdvancedSetDefaultCmd = ReactiveCommand.Create(() => { RoutingAdvancedSetDefault(); }, canEditRemove); RoutingAdvancedImportRulesCmd = ReactiveCommand.Create(() => { RoutingAdvancedImportRules(); }); SaveCmd = ReactiveCommand.Create(() => { SaveRouting(); }); Utils.SetDarkBorder(view, _config.uiItem.colorModeDark); } #region locked private void BindingLockedData() { _lockedItem = ConfigHandler.GetLockedRoutingItem(ref _config); if (_lockedItem != null) { _lockedRules = Utils.FromJson>(_lockedItem.ruleSet); ProxyDomain = Utils.List2String(_lockedRules[0].domain, true); ProxyIP = Utils.List2String(_lockedRules[0].ip, true); DirectDomain = Utils.List2String(_lockedRules[1].domain, true); DirectIP = Utils.List2String(_lockedRules[1].ip, true); BlockDomain = Utils.List2String(_lockedRules[2].domain, true); BlockIP = Utils.List2String(_lockedRules[2].ip, true); } } private void EndBindingLockedData() { if (_lockedItem != null) { _lockedRules[0].domain = Utils.String2List(Utils.Convert2Comma(ProxyDomain.TrimEx())); _lockedRules[0].ip = Utils.String2List(Utils.Convert2Comma(ProxyIP.TrimEx())); _lockedRules[1].domain = Utils.String2List(Utils.Convert2Comma(DirectDomain.TrimEx())); _lockedRules[1].ip = Utils.String2List(Utils.Convert2Comma(DirectIP.TrimEx())); _lockedRules[2].domain = Utils.String2List(Utils.Convert2Comma(BlockDomain.TrimEx())); _lockedRules[2].ip = Utils.String2List(Utils.Convert2Comma(BlockIP.TrimEx())); _lockedItem.ruleSet = Utils.ToJson(_lockedRules, false); ConfigHandler.SaveRoutingItem(ref _config, _lockedItem); } } #endregion locked #region Refresh Save public void RefreshRoutingItems() { _routingItems.Clear(); var routings = LazyConfig.Instance.RoutingItems(); foreach (var item in routings) { bool def = false; if (item.id == _config.routingBasicItem.routingIndexId) { def = true; } var it = new RoutingItemModel() { isActive = def, ruleNum = item.ruleNum, id = item.id, remarks = item.remarks, url = item.url, customIcon = item.customIcon, sort = item.sort, }; _routingItems.Add(it); } } private void SaveRouting() { _config.routingBasicItem.domainStrategy = domainStrategy; _config.routingBasicItem.enableRoutingAdvanced = enableRoutingAdvanced; _config.routingBasicItem.domainMatcher = domainMatcher; _config.routingBasicItem.domainStrategy4Singbox = domainStrategy4Singbox; EndBindingLockedData(); if (ConfigHandler.SaveConfig(ref _config) == 0) { _noticeHandler?.Enqueue(ResUI.OperationSuccess); _view.DialogResult = true; } else { UI.ShowWarning(ResUI.OperationFailed); } } #endregion Refresh Save private void RoutingBasicImportRules() { //Extra to bypass the mainland ProxyDomain = "geosite:google"; DirectDomain = "geosite:cn"; DirectIP = "geoip:private,geoip:cn"; BlockDomain = "geosite:category-ads-all"; //_noticeHandler?.Enqueue(ResUI.OperationSuccess); UI.Show(ResUI.OperationSuccess); } public void RoutingAdvancedEdit(bool blNew) { RoutingItem item; if (blNew) { item = new(); } else { item = LazyConfig.Instance.GetRoutingItem(SelectedSource?.id); if (item is null) { return; } } var ret = (new RoutingRuleSettingWindow(item)).ShowDialog(); if (ret == true) { RefreshRoutingItems(); IsModified = true; } } public void RoutingAdvancedRemove() { if (SelectedSource is null || SelectedSource.remarks.IsNullOrEmpty()) { UI.Show(ResUI.PleaseSelectRules); return; } if (UI.ShowYesNo(ResUI.RemoveRules) == MessageBoxResult.No) { return; } foreach (var it in SelectedSources) { var item = LazyConfig.Instance.GetRoutingItem(it?.id); if (item != null) { ConfigHandler.RemoveRoutingItem(item); } } RefreshRoutingItems(); IsModified = true; } public void RoutingAdvancedSetDefault() { var item = LazyConfig.Instance.GetRoutingItem(SelectedSource?.id); if (item is null) { UI.Show(ResUI.PleaseSelectRules); return; } if (ConfigHandler.SetDefaultRouting(ref _config, item) == 0) { RefreshRoutingItems(); IsModified = true; } } private void RoutingAdvancedImportRules() { if (ConfigHandler.InitBuiltinRouting(ref _config, true) == 0) { RefreshRoutingItems(); IsModified = true; } } } } ================================================ FILE: v2rayN/v2rayN/ViewModels/SubEditViewModel.cs ================================================ using ReactiveUI; using ReactiveUI.Fody.Helpers; using Splat; using System.Reactive; using System.Windows; using v2rayN.Base; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; namespace v2rayN.ViewModels { public class SubEditViewModel : ReactiveObject { private static Config _config; private NoticeHandler? _noticeHandler; private Window _view; [Reactive] public SubItem SelectedSource { get; set; } public ReactiveCommand SaveCmd { get; } public SubEditViewModel(SubItem subItem, Window view) { _config = LazyConfig.Instance.GetConfig(); _noticeHandler = Locator.Current.GetService(); _view = view; if (subItem.id.IsNullOrEmpty()) { SelectedSource = subItem; } else { SelectedSource = Utils.DeepCopy(subItem); } SaveCmd = ReactiveCommand.Create(() => { SaveSub(); }); Utils.SetDarkBorder(view, _config.uiItem.colorModeDark); } private void SaveSub() { string remarks = SelectedSource.remarks; if (Utils.IsNullOrEmpty(remarks)) { UI.Show(ResUI.PleaseFillRemarks); return; } var item = LazyConfig.Instance.GetSubItem(SelectedSource.id); if (item is null) { item = SelectedSource; } else { item.remarks = SelectedSource.remarks; item.url = SelectedSource.url; item.moreUrl = SelectedSource.moreUrl; item.enabled = SelectedSource.enabled; item.profileUpdateInterval = SelectedSource.profileUpdateInterval; item.userAgent = SelectedSource.userAgent; item.sort = SelectedSource.sort; item.filter = SelectedSource.filter; item.convertTarget = SelectedSource.convertTarget; } if (ConfigHandler.AddSubItem(ref _config, item) == 0) { _noticeHandler?.Enqueue(ResUI.OperationSuccess); if (_view.IsActive) { _view.DialogResult = true; } //_view?.Close(); } else { _noticeHandler?.Enqueue(ResUI.OperationFailed); } } } } ================================================ FILE: v2rayN/v2rayN/ViewModels/SubSettingViewModel.cs ================================================ using DynamicData; using DynamicData.Binding; using MaterialDesignThemes.Wpf; using ReactiveUI; using ReactiveUI.Fody.Helpers; using Splat; using System.Reactive; using System.Windows; using v2rayN.Base; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; using v2rayN.Views; namespace v2rayN.ViewModels { public class SubSettingViewModel : ReactiveObject { private static Config _config; private NoticeHandler? _noticeHandler; private IObservableCollection _subItems = new ObservableCollectionExtended(); public IObservableCollection SubItems => _subItems; [Reactive] public SubItem SelectedSource { get; set; } public IList SelectedSources { get; set; } public ReactiveCommand SubAddCmd { get; } public ReactiveCommand SubDeleteCmd { get; } public ReactiveCommand SubEditCmd { get; } public ReactiveCommand SubShareCmd { get; } public bool IsModified { get; set; } public SubSettingViewModel(Window view) { _config = LazyConfig.Instance.GetConfig(); _noticeHandler = Locator.Current.GetService(); SelectedSource = new(); RefreshSubItems(); var canEditRemove = this.WhenAnyValue( x => x.SelectedSource, selectedSource => selectedSource != null && !selectedSource.id.IsNullOrEmpty()); SubAddCmd = ReactiveCommand.Create(() => { EditSub(true); }); SubDeleteCmd = ReactiveCommand.Create(() => { DeleteSub(); }, canEditRemove); SubEditCmd = ReactiveCommand.Create(() => { EditSub(false); }, canEditRemove); SubShareCmd = ReactiveCommand.Create(() => { SubShare(); }, canEditRemove); Utils.SetDarkBorder(view, _config.uiItem.colorModeDark); } public void RefreshSubItems() { _subItems.Clear(); _subItems.AddRange(LazyConfig.Instance.SubItems().OrderByDescending(t => t.sort)); } public void EditSub(bool blNew) { SubItem item; if (blNew) { item = new(); } else { item = LazyConfig.Instance.GetSubItem(SelectedSource?.id); if (item is null) { return; } } var ret = (new SubEditWindow(item)).ShowDialog(); if (ret == true) { RefreshSubItems(); IsModified = true; } } private void DeleteSub() { if (UI.ShowYesNo(ResUI.RemoveServer) == MessageBoxResult.No) { return; } foreach (var it in SelectedSources) { ConfigHandler.DeleteSubItem(ref _config, it?.id); } RefreshSubItems(); _noticeHandler?.Enqueue(ResUI.OperationSuccess); IsModified = true; } private async void SubShare() { if (Utils.IsNullOrEmpty(SelectedSource?.url)) { return; } var img = QRCodeHelper.GetQRCode(SelectedSource?.url); var dialog = new QrcodeView() { imgQrcode = { Source = img }, txtContent = { Text = SelectedSource?.url }, }; await DialogHost.Show(dialog, "SubDialog"); } } } ================================================ FILE: v2rayN/v2rayN/ViewModels/ViewModelBase.cs ================================================ using ReactiveUI; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; namespace v2rayN.ViewModels { public abstract class ViewModelBase : ReactiveObject, INotifyPropertyChanged { public event PropertyChangedEventHandler? PropertyChanged; /// /// Sets property if it does not equal existing value. Notifies listeners if change occurs. /// /// Type of property. /// The property's backing field. /// The new value. /// Name of the property used to notify listeners. This /// value is optional and can be provided automatically when invoked from compilers /// that support . protected virtual bool SetProperty(ref T member, T value, [CallerMemberName] string? propertyName = null) { if (EqualityComparer.Default.Equals(member, value)) { return false; } member = value; OnPropertyChanged(propertyName); return true; } /// /// Notifies listeners that a property value has changed. /// /// Name of the property, used to notify listeners. protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } ================================================ FILE: v2rayN/v2rayN/Views/AddServer2Window.xaml ================================================  Use For ================================================ FILE: v2rayN/v2rayN/Views/MainSubInfoView.xaml.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace v2rayN.Views { /// /// Interaction logic for MainSubInfoView.xaml /// public partial class MainSubInfoView : UserControl { public MainSubInfoView() { InitializeComponent(); } } } ================================================ FILE: v2rayN/v2rayN/Views/MainWindow.xaml ================================================ ================================================ FILE: v2rayN/v2rayN/Views/MainWindow.xaml.cs ================================================ using DynamicData; using DynamicData.Binding; using ReactiveUI; using Splat; using System.ComponentModel; using System.IO; using System.IO.Pipes; using System.Reactive.Disposables; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Input; using System.Windows.Interop; using System.Windows.Media; using v2rayN.Base; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; using v2rayN.Tool; using v2rayN.ViewModels; using Point = System.Windows.Point; namespace v2rayN.Views { public partial class MainWindow { private NamedPipeServerStream _pipeServer; private static Config _config; private void HandleClientConnection(IAsyncResult ar) { using (var reader = new StreamReader(_pipeServer)) { string message = reader.ReadLine()??""; HandleDeepLink(message); } // Disconnect the client and start listening for another connection try { _pipeServer.Disconnect(); _pipeServer.Dispose(); } catch (Exception e){ } _pipeServer = new NamedPipeServerStream("HiddifyPipe"); _pipeServer.BeginWaitForConnection(HandleClientConnection, null); } public MainWindow() { _pipeServer = new NamedPipeServerStream("HiddifyPipe"); _pipeServer.BeginWaitForConnection(HandleClientConnection, PipeDirection.InOut); InitializeComponent(); _config = LazyConfig.Instance.GetConfig(); App.Current.SessionEnding += Current_SessionEnding; this.Closing += MainWindow_Closing; this.PreviewKeyDown += MainWindow_PreviewKeyDown; btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click; txtServerFilter.PreviewKeyDown += TxtServerFilter_PreviewKeyDown; lstProfiles.PreviewKeyDown += LstProfiles_PreviewKeyDown; lstProfiles.SelectionChanged += lstProfiles_SelectionChanged; lstProfiles.LoadingRow += LstProfiles_LoadingRow; if (_config.uiItem.enableDragDropSort) { lstProfiles.AllowDrop = true; lstProfiles.PreviewMouseLeftButtonDown += LstProfiles_PreviewMouseLeftButtonDown; lstProfiles.MouseMove += LstProfiles_MouseMove; lstProfiles.DragEnter += LstProfiles_DragEnter; lstProfiles.Drop += LstProfiles_Drop; } ViewModel = new MainWindowViewModel(MainSnackbar.MessageQueue!, UpdateViewHandler); if (ViewModel.CurrentLanguage == "fa-Ir") FlowDirection = FlowDirection.RightToLeft; DataContext = ViewModel; // Handle URI scheme(Deep link), If there is any HandleDeepLink(); if (App.IsNewInstance) { App.Current.Shutdown(); Environment.Exit(0); return; } // Declare and start a thread to handle reloading main page whenever need new Thread(delegate () { HandlePageReloading(); }).Start(); Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel)); for (int i = Global.MinFontSize; i <= Global.MinFontSize + 8; i++) { //cmbCurrentFontSize.Items.Add(i.ToString()); } Global.Languages.ForEach(it => { //cmbCurrentLanguage.Items.Add(it); }); this.WhenActivated(disposables => { //home this.OneWayBind(ViewModel, vm => vm.ProfileItems, v => v.lstProfiles.ItemsSource).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedProfile, v => v.lstProfiles.SelectedItem).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.lstGroup.ItemsSource).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSub, v => v.lstGroup.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.ServerFilter, v => v.txtServerFilter.Text).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddSubCmd, v => v.btnAddSub).DisposeWith(disposables); //servers this.BindCommand(ViewModel, vm => vm.AddVmessServerCmd, v => v.menuAddVmessServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddVlessServerCmd, v => v.menuAddVlessServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddShadowsocksServerCmd, v => v.menuAddShadowsocksServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddSocksServerCmd, v => v.menuAddSocksServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddTrojanServerCmd, v => v.menuAddTrojanServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan).DisposeWith(disposables); //servers delete this.BindCommand(ViewModel, vm => vm.EditServerCmd, v => v.menuEditServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.RemoveServerCmd, v => v.menuRemoveServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.RemoveDuplicateServerCmd, v => v.menuRemoveDuplicateServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.CopyServerCmd, v => v.menuCopyServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SetDefaultServerCmd, v => v.menuSetDefaultServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.ShareServerCmd, v => v.menuShareServer).DisposeWith(disposables); //servers move this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.cmbMoveToGroup.ItemsSource).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedMoveToGroup, v => v.cmbMoveToGroup.SelectedItem).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.MoveTopCmd, v => v.menuMoveTop).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.MoveUpCmd, v => v.menuMoveUp).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.MoveDownCmd, v => v.menuMoveDown).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.MoveBottomCmd, v => v.menuMoveBottom).DisposeWith(disposables); //servers ping this.BindCommand(ViewModel, vm => vm.MixedTestServerCmd, v => v.menuMixedTestServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.PingServerCmd, v => v.menuPingServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.TcpingServerCmd, v => v.menuTcpingServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.RealPingServerCmd, v => v.menuRealPingServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SpeedServerCmd, v => v.menuSpeedServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SortServerResultCmd, v => v.menuSortServerResult).DisposeWith(disposables); //servers export this.BindCommand(ViewModel, vm => vm.Export2ClientConfigCmd, v => v.menuExport2ClientConfig).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.Export2ShareUrlCmd, v => v.menuExport2ShareUrl).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.Export2SubContentCmd, v => v.menuExport2SubContent).DisposeWith(disposables); //sub this.BindCommand(ViewModel, vm => vm.SubSettingCmd, v => v.menuSubSetting).DisposeWith(disposables); //this.BindCommand(ViewModel, vm => vm.SubUpdateCmd, v => v.menuSubUpdate).DisposeWith(disposables); //this.BindCommand(ViewModel, vm => vm.SubUpdateViaProxyCmd, v => v.menuSubUpdateViaProxy).DisposeWith(disposables); //this.BindCommand(ViewModel, vm => vm.SubGroupUpdateCmd, v => v.menuSubGroupUpdate).DisposeWith(disposables); //this.BindCommand(ViewModel, vm => vm.SubGroupUpdateViaProxyCmd, v => v.menuSubGroupUpdateViaProxy).DisposeWith(disposables); //setting this.BindCommand(ViewModel, vm => vm.OptionSettingCmd, v => v.menuOptionSetting).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.RoutingSettingCmd, v => v.menuRoutingSetting).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.DNSSettingCmd, v => v.menuDNSSetting).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.GlobalHotkeySettingCmd, v => v.menuGlobalHotkeySetting).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.RebootAsAdminCmd, v => v.menuRebootAsAdmin).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.ClearServerStatisticsCmd, v => v.menuClearServerStatistics).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.ImportOldGuiConfigCmd, v => v.menuImportOldGuiConfig).DisposeWith(disposables); //checkupdate this.BindCommand(ViewModel, vm => vm.CheckUpdateNCmd, v => v.menuCheckUpdateN).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.CheckUpdateV2flyCoreCmd, v => v.menuCheckUpdateV2flyCore).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.CheckUpdateSagerNetCoreCmd, v => v.menuCheckUpdateSagerNetCore).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.CheckUpdateXrayCoreCmd, v => v.menuCheckUpdateXrayCore).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.CheckUpdateClashCoreCmd, v => v.menuCheckUpdateClashCore).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.CheckUpdateClashMetaCoreCmd, v => v.menuCheckUpdateClashMetaCore).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.CheckUpdateSingBoxCoreCmd, v => v.menuCheckUpdateSingBoxCore).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.CheckUpdateGeoCmd, v => v.menuCheckUpdateGeo).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.ReloadCmd, v => v.menuReload).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.BlReloadEnabled, v => v.menuReload.IsEnabled).DisposeWith(disposables); //system proxy //this.OneWayBind(ViewModel, vm => vm.BlSystemProxyClear, v => v.menuSystemProxyClear2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); //this.OneWayBind(ViewModel, vm => vm.BlSystemProxySet, v => v.menuSystemProxySet2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); //this.OneWayBind(ViewModel, vm => vm.BlSystemProxyNothing, v => v.menuSystemProxyNothing2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); //this.OneWayBind(ViewModel, vm => vm.BlSystemProxyPac, v => v.menuSystemProxyPac2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); //this.BindCommand(ViewModel, vm => vm.SystemProxyClearCmd, v => v.menuSystemProxyClear).DisposeWith(disposables); //this.BindCommand(ViewModel, vm => vm.SystemProxySetCmd, v => v.menuSystemProxySet).DisposeWith(disposables); //this.BindCommand(ViewModel, vm => vm.SystemProxyPacCmd, v => v.menuSystemProxyPac).DisposeWith(disposables); //this.BindCommand(ViewModel, vm => vm.SystemProxyNothingCmd, v => v.menuSystemProxyNothing).DisposeWith(disposables); //routings and servers this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.cmbRoutings.ItemsSource).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings.SelectedItem).DisposeWith(disposables); //this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.menuRoutings.Visibility).DisposeWith(disposables); //this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.sepRoutings.Visibility).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.Servers, v => v.cmbServers.ItemsSource).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedServer, v => v.cmbServers.SelectedItem).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.BlServers, v => v.cmbServers.Visibility).DisposeWith(disposables); //tray menu this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard2).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan2).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubUpdateCmd, v => v.menuSubUpdate2).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubUpdateViaProxyCmd, v => v.menuSubUpdateViaProxy2).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.NotifyIcon, v => v.tbNotify.Icon).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.RunningServerToolTipText, v => v.tbNotify.ToolTipText).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.NotifyLeftClickCmd, v => v.tbNotify.LeftClickCommand).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.AppIcon, v => v.Icon).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.BlShowTrayTip, v => v.borTrayToolTip.Visibility).DisposeWith(disposables); //status bar this.OneWayBind(ViewModel, vm => vm.InboundDisplay, v => v.txtInboundDisplay.Text).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.InboundLanDisplay, v => v.txtInboundLanDisplay.Text).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.RunningServerDisplay, v => v.txtRunningServerDisplay.Text).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.RunningInfoDisplay, v => v.txtRunningInfoDisplay.Text).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.SpeedProxyDisplay, v => v.txtSpeedProxyDisplay.Text).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.SpeedDirectDisplay, v => v.txtSpeedDirectDisplay.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.EnableTun, v => v.togEnableTun.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SystemProxySelected, v => v.cmbSystemProxy.SelectedIndex).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.cmbRoutings2.ItemsSource).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings2.SelectedItem).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.cmbRoutings2.Visibility).DisposeWith(disposables); //UI //this.Bind(ViewModel, vm => vm.ColorModeDark, v => v.togDarkMode.IsChecked).DisposeWith(disposables); //this.OneWayBind(ViewModel, vm => vm.Swatches, v => v.cmbSwatches.ItemsSource).DisposeWith(disposables); //this.Bind(ViewModel, vm => vm.SelectedSwatch, v => v.cmbSwatches.SelectedItem).DisposeWith(disposables); //this.Bind(ViewModel, vm => vm.CurrentFontSize, v => v.cmbCurrentFontSize.Text).DisposeWith(disposables); //this.Bind(ViewModel, vm => vm.CurrentLanguage, v => v.cmbCurrentLanguage.Text).DisposeWith(disposables); }); RestoreUI(); AddHelpMenuItem(); var IsAdministrator = Utils.IsAdministrator(); this.Title = $"{Utils.GetVersion()} - {(IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}"; //spEnableTun.IsEnabled = IsAdministrator ? Visibility.Visible : Visibility.Collapsed; //if (_config.uiItem.autoHideStartup) //{ // WindowState = WindowState.Minimized; //} if (!_config.guiItem.enableHWA) { RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly; } App.Current.MainWindow.Show(); Application.Current.MainWindow.Show(); if (Application.Current.MainWindow.WindowState == WindowState.Minimized) { Application.Current.MainWindow.WindowState = WindowState.Normal; } Application.Current.MainWindow.Activate(); } private void HandlePageReloading() { while (true) { if (Utils.DoesMainPageNeedReload()) { this.Dispatcher.Invoke(() => { ViewModel?.InitSubscriptionView(); ViewModel?.SubSelectedChanged(true); if (this.IsVisible) { this.Show(); } if (this.WindowState == WindowState.Minimized) { this.WindowState = WindowState.Normal; } this.Activate(); this.Topmost = true; this.Topmost = false; this.Focus(); Utils.UnsetMainPageReload(); }); } Thread.Sleep(666); } } public void HandleDeepLink(String? message=null) { if (message != null) this.Dispatcher.Invoke(Activate); string[] Args = Environment.GetCommandLineArgs(); if (Args.Length > 1|| message!=null) { var uri = message??Args[1]; var (isValidUri, scheme) = DeepLinking.IsUriForProgram(uri); if (isValidUri) { this.Dispatcher.Invoke(() => { // Parse uri var item = DeepLinking.ParseUri(uri); // Error handling if (item.err != null && item.err != "" && item.res == null) { // Notice error ViewModel?._noticeHandler?.SendMessage(ResUI.MsgDeepLinkIsInvalid); } // Add server or subscription to the program else { if (item.res.protocol != null) { ViewModel?.AddServerOrSubViaDeepLink(item.res.protocol.Uri); Utils.SetMainPageReload(); } else if (item.res.subscription != null) { ViewModel?.AddServerOrSubViaDeepLink(item.res.subscription.Url); Utils.SetMainPageReload(); } else { // WTF is happening here ! } } }); } } } #region Event private void UpdateViewHandler(EViewAction action) { if (action == EViewAction.AdjustMainLvColWidth) { Application.Current.Dispatcher.Invoke(() => { AutofitColumnWidth(); }); } else if (action == EViewAction.ProfilesFocus) { lstProfiles.Focus(); } } private void MainWindow_Closing(object? sender, CancelEventArgs e) { e.Cancel = true; ViewModel?.ShowHideWindow(false); } private void update_sub_click(object sender, RoutedEventArgs e) { var item = (MenuItem)sender; //MessageBox.Show(item.Uid); ViewModel?.UpdateSubscriptionProcess(item.Uid, false);//without proxy ViewModel?.UpdateSubscriptionProcess(item.Uid, true);//with proxy } private void menuExit_Click(object sender, RoutedEventArgs e) { tbNotify.Dispose(); StorageUI(); ViewModel?.MyAppExit(false); if (_pipeServer != null) { _pipeServer.Dispose(); _pipeServer = null; } } private void Current_SessionEnding(object sender, SessionEndingCancelEventArgs e) { Utils.SaveLog("Current_SessionEnding"); StorageUI(); ViewModel?.MyAppExit(true); } private void lstProfiles_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) { ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast().ToList(); } private void LstProfiles_LoadingRow(object? sender, DataGridRowEventArgs e) { e.Row.Header = $" {e.Row.GetIndex() + 1}"; } private void LstProfiles_MouseDoubleClick(object sender, MouseButtonEventArgs e) { if (ViewModel?.SelectedProfile?.configType == EConfigType.Usage) { Utils.ProcessStart($"{ViewModel?.SelectedProfile?.address}"); return; } //if (_config.uiItem.doubleClick2Activate) if (ViewModel?.SelectedProfile?.isActive==false) { ViewModel?.SetDefaultServer(); } else { if (((int)ViewModel?.SelectedProfile?.configType) >100 ) return; ViewModel?.EditServer(false, EConfigType.Custom); } ViewModel?.ServerSpeedtest(ESpeedActionType.Realping); } private void LstProfiles_ColumnHeader_Click(object sender, RoutedEventArgs e) { var colHeader = sender as DataGridColumnHeader; if (colHeader == null || colHeader.TabIndex < 0 || colHeader.Column == null) { return; } var colName = ((MyDGTextColumn)colHeader.Column).ExName; ViewModel?.SortServer(colName); } private void menuSelectAll_Click(object sender, RoutedEventArgs e) { lstProfiles.SelectAll(); } private void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e) { if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) { if (e.Key == Key.V) { ViewModel?.AddServerOrSubViaClipboard(); } else if (e.Key == Key.P) { ViewModel?.ServerSpeedtest(ESpeedActionType.Ping); } else if (e.Key == Key.O) { ViewModel?.ServerSpeedtest(ESpeedActionType.Tcping); } else if (e.Key == Key.R) { ViewModel?.ServerSpeedtest(ESpeedActionType.Realping); } else if (e.Key == Key.S) { _ = ViewModel?.ScanScreenTaskAsync(); } else if (e.Key == Key.T) { ViewModel?.ServerSpeedtest(ESpeedActionType.Speedtest); } else if (e.Key == Key.E) { ViewModel?.ServerSpeedtest(ESpeedActionType.Mixedtest); } } else { if (e.Key == Key.F5) { ViewModel?.Reload(); } } } private void LstProfiles_PreviewKeyDown(object sender, KeyEventArgs e) { if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) { if (e.Key == Key.A) { menuSelectAll_Click(null, null); } else if (e.Key == Key.C) { ViewModel?.Export2ShareUrl(); } else if (e.Key == Key.D) { ViewModel?.EditServer(false, EConfigType.Custom); } else if (e.Key == Key.F) { ViewModel?.ShareServer(); } } else { if (e.Key is Key.Enter or Key.Return) { ViewModel?.SetDefaultServer(); } else if (e.Key == Key.Delete) { ViewModel?.RemoveServer(); } else if (e.Key == Key.T) { ViewModel?.MoveServer(EMove.Top); } else if (e.Key == Key.U) { ViewModel?.MoveServer(EMove.Up); } else if (e.Key == Key.D) { ViewModel?.MoveServer(EMove.Down); } else if (e.Key == Key.B) { ViewModel?.MoveServer(EMove.Bottom); } } } private void menuClose_Click(object sender, RoutedEventArgs e) { StorageUI(); ViewModel?.ShowHideWindow(false); } private void menuPromotion_Click(object sender, RoutedEventArgs e) { Utils.ProcessStart($"{Utils.Base64Decode(Global.PromotionUrl)}"); } private void txtRunningInfoDisplay_MouseDoubleClick(object sender, MouseButtonEventArgs e) { ViewModel?.TestServerAvailability(); } private void menuSettingsSetUWP_Click(object sender, RoutedEventArgs e) { Utils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe")); } private void BtnAutofitColumnWidth_Click(object sender, RoutedEventArgs e) { AutofitColumnWidth(); } private void AutofitColumnWidth() { foreach (var it in lstProfiles.Columns) { it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto); } } private void TxtServerFilter_PreviewKeyDown(object sender, KeyEventArgs e) { if (e.Key is Key.Enter or Key.Return) { ViewModel?.RefreshServers(); } } #endregion Event #region UI private void RestoreUI() { if (_config.uiItem.mainWidth > 0 && _config.uiItem.mainHeight > 0) { Width = _config.uiItem.mainWidth; Height = _config.uiItem.mainHeight; } var maxWidth = SystemParameters.WorkArea.Width; var maxHeight = SystemParameters.WorkArea.Height; if (Width > maxWidth) Width = maxWidth; if (Height > maxHeight) Height = maxHeight; if (_config.uiItem.mainGirdHeight1 > 0 && _config.uiItem.mainGirdHeight2 > 0) { gridMain.RowDefinitions[0].Height = new GridLength(_config.uiItem.mainGirdHeight1, GridUnitType.Star); gridMain.RowDefinitions[2].Height = new GridLength(_config.uiItem.mainGirdHeight2, GridUnitType.Star); } var lvColumnItem = _config.uiItem.mainColumnItem.OrderBy(t => t.Index).ToList(); for (int i = 0; i < lvColumnItem.Count; i++) { var item = lvColumnItem[i]; for (int k = 1; k < lstProfiles.Columns.Count; k++) { var item2 = (MyDGTextColumn)lstProfiles.Columns[k]; if (item2.ExName == item.Name) { if (item.Width < 0) { item2.Visibility = Visibility.Hidden; } else { item2.Width = item.Width; item2.DisplayIndex = i; } } } } if (!_config.guiItem.enableStatistics) { colTodayUp.Visibility = Visibility.Hidden; colTodayDown.Visibility = Visibility.Hidden; colTotalUp.Visibility = Visibility.Hidden; colTotalDown.Visibility = Visibility.Hidden; } } private void StorageUI() { _config.uiItem.mainWidth = this.Width; _config.uiItem.mainHeight = this.Height; List lvColumnItem = new(); for (int k = 0; k < lstProfiles.Columns.Count; k++) { var item2 = (MyDGTextColumn)lstProfiles.Columns[k]; lvColumnItem.Add(new() { Name = item2.ExName, Width = item2.Visibility == Visibility.Visible ? Convert.ToInt32(item2.ActualWidth) : -1, Index = item2.DisplayIndex }); } _config.uiItem.mainColumnItem = lvColumnItem; _config.uiItem.mainGirdHeight1 = Math.Ceiling(gridMain.RowDefinitions[0].ActualHeight + 0.1); _config.uiItem.mainGirdHeight2 = Math.Ceiling(gridMain.RowDefinitions[2].ActualHeight + 0.1); } private void AddHelpMenuItem() { var coreInfos = LazyConfig.Instance.GetCoreInfos(); foreach (var it in coreInfos) { var item = new MenuItem() { Tag = it.coreUrl.Replace(@"/releases", ""), Header = string.Format(Resx.ResUI.menuWebsiteItem, it.coreType.ToString().Replace("_", " ")) }; item.Click += MenuItem_Click; menuHelp.Items.Add(item); } } private void MenuItem_Click(object sender, RoutedEventArgs e) { if (sender is MenuItem item) { Utils.ProcessStart(item.Tag.ToString()); } } #endregion UI #region Drag and Drop private Point startPoint = new(); private int startIndex = -1; private string formatData = "ProfileItemModel"; /// /// Helper to search up the VisualTree /// /// /// /// private static T? FindAnchestor(DependencyObject current) where T : DependencyObject { do { if (current is T) { return (T)current; } current = VisualTreeHelper.GetParent(current); } while (current != null); return null; } private void LstProfiles_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { // Get current mouse position startPoint = e.GetPosition(null); } private void LstProfiles_MouseMove(object sender, MouseEventArgs e) { // Get the current mouse position Point mousePos = e.GetPosition(null); Vector diff = startPoint - mousePos; if (e.LeftButton == MouseButtonState.Pressed && (Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance || Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance)) { // Get the dragged Item if (sender is not DataGrid listView) return; var listViewItem = FindAnchestor((DependencyObject)e.OriginalSource); if (listViewItem == null) return; // Abort // Find the data behind the ListViewItem ProfileItemModel item = (ProfileItemModel)listView.ItemContainerGenerator.ItemFromContainer(listViewItem); if (item == null) return; // Abort // Initialize the drag & drop operation startIndex = lstProfiles.SelectedIndex; DataObject dragData = new(formatData, item); DragDrop.DoDragDrop(listViewItem, dragData, DragDropEffects.Copy | DragDropEffects.Move); } } private void LstProfiles_DragEnter(object sender, DragEventArgs e) { if (!e.Data.GetDataPresent(formatData) || sender != e.Source) { e.Effects = DragDropEffects.None; } } private void LstProfiles_Drop(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(formatData) && sender == e.Source) { // Get the drop Item destination if (sender is not DataGrid listView) return; var listViewItem = FindAnchestor((DependencyObject)e.OriginalSource); if (listViewItem == null) { // Abort e.Effects = DragDropEffects.None; return; } // Find the data behind the Item ProfileItemModel item = (ProfileItemModel)listView.ItemContainerGenerator.ItemFromContainer(listViewItem); if (item == null) return; // Move item into observable collection // (this will be automatically reflected to lstView.ItemsSource) e.Effects = DragDropEffects.Move; ViewModel?.MoveServerTo(startIndex, item); startIndex = -1; } } #endregion private void togEnableTun_Click(object sender, RoutedEventArgs e) { if (Utils.IsAdministrator()) { togEnableProxy.IsChecked = togEnableTun.IsChecked; } else { UI.ShowError(ResUI.MsgStartProgramAsAdmin); togEnableTun.IsChecked = false; } } private void togEnableProxy_Click(object sender, RoutedEventArgs e) { // @hiddify it's just for proxy, i think we shoudn't check for Administrator right (it will work anyway) //if (Utils.IsAdministrator()) //{ // togEnableTun.IsChecked = togEnableProxy.IsChecked; //} //else //{ //} ViewModel.ToggleSysProxy(); //cmbSystemProxy.SelectedIndex = togEnableProxy.IsChecked==true ? 1 : 0; } private void ResizeWindowToFirstColumn() { // Get the actual width of the first column double firstColumnWidth = HiddifyUI.ActualWidth; // Add some padding to the width (optional) double padding = 20; double newWidth = firstColumnWidth + padding; // Set the new window size this.Width = newWidth; } // Example usage: resize the window to fit the first column private void HideBtn_Click(object sender, RoutedEventArgs e) { //V2rayNPanel.Visibility=Visibility.Collapsed; //ResizeWindowToFirstColumn(); } private void HiddifyUI_Loaded(object sender, RoutedEventArgs e) { } } } ================================================ FILE: v2rayN/v2rayN/Views/MsgView.xaml ================================================ ================================================ FILE: v2rayN/v2rayN/Views/MsgView.xaml.cs ================================================ using ReactiveUI; using System.Reactive.Linq; using System.Text.RegularExpressions; using System.Windows.Threading; using v2rayN.Base; using v2rayN.Handler; using v2rayN.Mode; namespace v2rayN.Views { public partial class MsgView { private static Config _config; private string lastMsgFilter; private bool lastMsgFilterNotAvailable; public MsgView() { InitializeComponent(); _config = LazyConfig.Instance.GetConfig(); MessageBus.Current.Listen("MsgView").Subscribe(x => DelegateAppendText(x)); Global.PresetMsgFilters.ForEach(it => { cmbMsgFilter.Items.Add(it); }); if (!_config.uiItem.mainMsgFilter.IsNullOrEmpty()) { cmbMsgFilter.Text = _config.uiItem.mainMsgFilter; } } private void DelegateAppendText(string msg) { Dispatcher.BeginInvoke(AppendText, DispatcherPriority.Send, msg); } public void AppendText(string msg) { if (msg == Global.CommandClearMsg) { ClearMsg(); return; } if (togAutoRefresh.IsChecked == false) { return; } var MsgFilter = cmbMsgFilter.Text.TrimEx(); if (MsgFilter != lastMsgFilter) lastMsgFilterNotAvailable = false; if (!string.IsNullOrEmpty(MsgFilter) && !lastMsgFilterNotAvailable) { try { if (!Regex.IsMatch(msg, MsgFilter)) // ʽ쳣 { return; } } catch (Exception) { lastMsgFilterNotAvailable = true; } } lastMsgFilter = MsgFilter; ShowMsg(msg); } private void ShowMsg(string msg) { if (txtMsg.LineCount > 999) { ClearMsg(); } this.txtMsg.AppendText(msg); if (!msg.EndsWith(Environment.NewLine)) { this.txtMsg.AppendText(Environment.NewLine); } txtMsg.ScrollToEnd(); } public void ClearMsg() { txtMsg.Clear(); } private void menuMsgViewSelectAll_Click(object sender, System.Windows.RoutedEventArgs e) { txtMsg.Focus(); txtMsg.SelectAll(); } private void menuMsgViewCopy_Click(object sender, System.Windows.RoutedEventArgs e) { var data = txtMsg.SelectedText.TrimEx(); Utils.SetClipboardData(data); } private void menuMsgViewCopyAll_Click(object sender, System.Windows.RoutedEventArgs e) { var data = txtMsg.Text; Utils.SetClipboardData(data); } private void menuMsgViewClear_Click(object sender, System.Windows.RoutedEventArgs e) { ClearMsg(); } private void cmbMsgFilter_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e) { _config.uiItem.mainMsgFilter = cmbMsgFilter.Text.TrimEx(); } } } ================================================ FILE: v2rayN/v2rayN/Views/OptionSettingWindow.xaml ================================================  ================================================ FILE: v2rayN/v2rayN/Views/SubSettingWindow.xaml.cs ================================================ using ReactiveUI; using System.ComponentModel; using System.Reactive.Disposables; using System.Windows; using System.Windows.Input; using v2rayN.Mode; using v2rayN.ViewModels; namespace v2rayN.Views { public partial class SubSettingWindow { public SubSettingWindow() { InitializeComponent(); this.Owner = Application.Current.MainWindow; ViewModel = new SubSettingViewModel(this); this.Closing += SubSettingWindow_Closing; lstSubscription.MouseDoubleClick += LstSubscription_MouseDoubleClick; lstSubscription.SelectionChanged += LstSubscription_SelectionChanged; this.WhenActivated(disposables => { this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.lstSubscription.ItemsSource).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource, v => v.lstSubscription.SelectedItem).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubAddCmd, v => v.menuSubAdd).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubDeleteCmd, v => v.menuSubDelete).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubEditCmd, v => v.menuSubEdit).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubShareCmd, v => v.menuSubShare).DisposeWith(disposables); }); } private void SubSettingWindow_Closing(object? sender, CancelEventArgs e) { if (ViewModel?.IsModified == true) { this.DialogResult = true; } } private void LstSubscription_MouseDoubleClick(object sender, MouseButtonEventArgs e) { ViewModel?.EditSub(false); } private void LstSubscription_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) { ViewModel.SelectedSources = lstSubscription.SelectedItems.Cast().ToList(); } private void menuClose_Click(object sender, System.Windows.RoutedEventArgs e) { if (ViewModel?.IsModified == true) { this.DialogResult = true; } else { this.Close(); } } } } ================================================ FILE: v2rayN/v2rayN/app.manifest ================================================  true PerMonitorV2 ================================================ FILE: v2rayN/v2rayN/v2rayN.csproj ================================================  true WinExe net6.0-windows enable true app.manifest enable v2rayN.ico Copyright © 2017-2023 (GPLv3) 6.23 HiddifyN Never Never Never Never Never Never Never Never Never Never Never Never Never Never Never Never Never Always True True Hiddify.resx True True ResUI.resx ResXFileCodeGenerator Hiddify.Designer.cs PublicResXFileCodeGenerator ResUI.Designer.cs PublicResXFileCodeGenerator PublicResXFileCodeGenerator PublicResXFileCodeGenerator ================================================ FILE: v2rayN/v2rayN.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.3.32811.315 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "v2rayN", "v2rayN\v2rayN.csproj", "{6DE127CA-1763-4236-B297-D2EF9CB2EC9B}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtosLib", "ProtosLib\ProtosLib.csproj", "{C5F24BB0-9CC1-44DD-82FF-D545F081819B}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PacLib", "PacLib\PacLib.csproj", "{EE4E6CD8-8353-446B-8F29-A841A02AE5EC}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HiddifyUpgradeN", "HiddifyUpgradeN\HiddifyUpgradeN.csproj", "{3CD0B9E8-331B-42C6-A395-4DA0FD4BC8EB}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HiddifyRestartN", "HiddifyRestartN\HiddifyRestartN.csproj", "{89185DF9-A4F2-4A1E-A290-EA02959C37DA}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Debug|Any CPU.Build.0 = Debug|Any CPU {6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Release|Any CPU.ActiveCfg = Release|Any CPU {6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Release|Any CPU.Build.0 = Release|Any CPU {C5F24BB0-9CC1-44DD-82FF-D545F081819B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C5F24BB0-9CC1-44DD-82FF-D545F081819B}.Debug|Any CPU.Build.0 = Debug|Any CPU {C5F24BB0-9CC1-44DD-82FF-D545F081819B}.Release|Any CPU.ActiveCfg = Release|Any CPU {C5F24BB0-9CC1-44DD-82FF-D545F081819B}.Release|Any CPU.Build.0 = Release|Any CPU {EE4E6CD8-8353-446B-8F29-A841A02AE5EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EE4E6CD8-8353-446B-8F29-A841A02AE5EC}.Debug|Any CPU.Build.0 = Debug|Any CPU {EE4E6CD8-8353-446B-8F29-A841A02AE5EC}.Release|Any CPU.ActiveCfg = Release|Any CPU {EE4E6CD8-8353-446B-8F29-A841A02AE5EC}.Release|Any CPU.Build.0 = Release|Any CPU {3CD0B9E8-331B-42C6-A395-4DA0FD4BC8EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3CD0B9E8-331B-42C6-A395-4DA0FD4BC8EB}.Debug|Any CPU.Build.0 = Debug|Any CPU {3CD0B9E8-331B-42C6-A395-4DA0FD4BC8EB}.Release|Any CPU.ActiveCfg = Release|Any CPU {3CD0B9E8-331B-42C6-A395-4DA0FD4BC8EB}.Release|Any CPU.Build.0 = Release|Any CPU {89185DF9-A4F2-4A1E-A290-EA02959C37DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {89185DF9-A4F2-4A1E-A290-EA02959C37DA}.Debug|Any CPU.Build.0 = Debug|Any CPU {89185DF9-A4F2-4A1E-A290-EA02959C37DA}.Release|Any CPU.ActiveCfg = Release|Any CPU {89185DF9-A4F2-4A1E-A290-EA02959C37DA}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {43E06CBD-3DA9-40A3-8E4D-F0943CB0DD32} EndGlobalSection EndGlobal