diff --git a/.build/default.Manifest.xml b/.build/default.Manifest.xml new file mode 100644 index 0000000..916d05f --- /dev/null +++ b/.build/default.Manifest.xml @@ -0,0 +1,60 @@ + + + + winXray + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True/PM + + + \ No newline at end of file diff --git a/.build/default.init.aardio b/.build/default.init.aardio new file mode 100644 index 0000000..2b00a05 --- /dev/null +++ b/.build/default.init.aardio @@ -0,0 +1,5 @@ +//发布前触发 +import ide; +io.remove("\..\v2ray-core\config.json") +io.remove("\..\WinXray\v2ray-core\config.json") + \ No newline at end of file diff --git a/.build/default.main.aardio b/.build/default.main.aardio new file mode 100644 index 0000000..6f69530 --- /dev/null +++ b/.build/default.main.aardio @@ -0,0 +1,40 @@ +//此触发器在生成EXE以后执行 + +import ide; +import fsys; +import console; +if( !console.askYesNo('是否生成 winXray.7z,winXray32.7z ? 按Y键继续,按N键取消') ){ + return console.close(); +} + +//获取生成的EXE文件路径 +var publishFile = ide.getPublishPath(); +var projectDir = ide.getProjectDir(); + +var tempDir = io.joinpath(projectDir,"release/7z-temp"); +fsys.createDir(tempDir,true) + +fsys.copy(publishFile,io.joinpath(tempDir,ide.getPublishName())); +fsys.copy(io.joinpath(projectDir,"v2ray-core\*.*"),io.joinpath(tempDir,"v2ray-core")); + +import console; +import sevenZip.cmd; + +console.open() +console.showLoading(" 正在生成 winXray.7z, winXray32.7z"); + +fsys.delete(io.joinpath(projectDir,"release/winXray.7z")); +sevenZip.cmd.compress( io.joinpath(tempDir,"*") + ,io.joinpath(projectDir,"release/winXray.7z") + ,console.log //这里可以设置一个回调函数,输出回显结果 + ) + +fsys.delete(io.joinpath(projectDir,"release/winXray32.7z")); +fsys.copy(io.joinpath(projectDir,"v2ray-core-32\*.*"),io.joinpath(tempDir,"v2ray-core")); +sevenZip.cmd.compress( io.joinpath(tempDir,"*") + ,io.joinpath(projectDir,"release/winXray32.7z") + ,console.log //这里可以设置一个回调函数,输出回显结果 + ) + +fsys.delete(tempDir); +console.close(); \ No newline at end of file diff --git a/.build/update-maker.table b/.build/update-maker.table new file mode 100644 index 0000000..ded4862 --- /dev/null +++ b/.build/update-maker.table @@ -0,0 +1,6 @@ +{ +updateUrl="https://raw.githubusercontent.com/winXray/winXray/master/release/update/"; +singleFile=1; +description="发布 v3.8, 优化代码修正已知问题。"; +outputDir="/release/update/" +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..66c7d4e --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +/v2ray-core/config.json +/v2ray-core-32/config.json +/v2ray-core/ssr-core/ +/winXray/v2ray-core/config.json +/winXray/ +/release/winXray/ +/release/winXray32/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3c577b0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..33ad3d2 --- /dev/null +++ b/README.md @@ -0,0 +1,140 @@ + +# WinXray +WinXray[:loud_sound:](http://dict.youdao.com/dictvoice?audio=winxray&type=2) 是最简洁轻快的 V2Ray、XRay、Trojan、Trojan-go、Shadowsocks、SSR(ShadowsocksR)、SSRoT、NaïveProxy,SOCKS,HTTP,HTTPS 全能通用客户端(Windows系统),支持并发检测大量服务器并迅速找到当前最快的服务器,服务器连接异常时可自动寻找其他速度最快的服务器 - 切换速度快如闪电,自订阅源获取的服务器异常时可自动刷新订阅,并且自带一键自动部署服务端工具。 + +**本软件源码已放弃版权贡献到公共域** ,源码可使用 [aardio](http://www.aardio.com) 编译生成单文件绿色EXE,**[点这里下载](./../../raw/master/release/winXray.7z)** ( [64位版本](./../../raw/master/release/winXray.7z) / [32位版本](./../../raw/master/release/winXray32.7z) ),解压即可直接使用( 体积很小仅 **[6.1 MB](./../../raw/master/release/winXray.7z)** - 已自带 V2Ray Core )。 + +# WinXray 未注册任何域名,谨防钓鱼网站 +WinXray 分为原版、抄袭版。 +抄袭版没有贡献任何功能,仅添加了假冒官网推广链接,然后原版更新任何功能,抄袭版都会复制粘贴改成他自己的名字重新提交,并且乱改版本号,日常踩原作者吹捧自己。原版作者估计是受不了那货已经失踪很久了。 + +本项目基于原版 WinXray v3.7 基础上继续更新 ,并将保持原版干净、纯净。本项目严禁上述假冒官网的抄袭版抄袭本项目的任何一句代码 。 + +# 免费服务器 +[网络免费 vmess 服务器订阅链接](https://proxypool.ga/vmess/sub) +[网络免费 Shadowsocks 服务器订阅链接](https://proxypool.ga/ss/sub) +[网络免费 clash 服务器订阅链接](https://proxypoolss.tk/clash/proxies?speed=100&type=vmess,trojan) +可复制上面各种格式订阅链接,在 winXray 中点击「批量导入链接」体验 winXray 有强大的兼容性。 +免费的服务器仅供测试(一定要走 PAC,不要开全局代理不要登录账号更不要长时间使用 )。 + +# 关于误报 +现在大多杀毒软件都是白名单查杀,所以新生的EXE都会乱报病毒,因为我更新的速度太快,所以不断的推新EXE上来,所以你可能遇到误报,但是你完全可以使用源代码自己编译出一模一样的EXE,还有人吹牛说其他翻墙软件不误报 - 你去 issues 里以及网上搜一下有多少误报好不好?!遇到误报可以提交给你的杀毒厂商核实,也可以自己编译源码生成EXE后使用,解决和核实问题很容易 - 其他套路都是多余的。 + + +# PAC 代理模式 / 全局代理 + 路由模式 对比 + +winXray 的 PAC 代理稳定、流畅、易用。 在 PAC 模式下,winXray 会优先启用高效安全的 SOCKS5 协议,并且可以自动兼容在 PAC 模式下仅支持 HTTP代理的应用。winXray 也可以在 PAC 模式下完美支持 Telegram IP 地址库 。 + +SOCKS5 支持对比: +- [ ] 全局路由模式: 不支持 SOCKS5 +- [x] PAC模式: 支持 高效安全的SOCKS5 + +UWP 应用支持对比: +- [ ] 全局路由模式: UWP 应用全部无法联网。 +- [x] PAC模式: UWP 应用可以正常联网,使用 winXray 自带工具也可以为UWP应用开启本地代理。 + +DNS 解析对比: +- [ ] 全局路由模式: 使用本机发起 DNS 解析,即使设为国外 DNS 服务器,仍然会返回适用于国内线路地址。 +- [x] PAC模式: 使用服务器上的 DNS 解析,安全可靠。 + +根据客户端自动切换代理协议: +- [ ] 全局路由模式: 不支持 +- [x] PAC模式: winXray 里的 PAC 代理可以让目标应用(例如浏览器)优先选择高效安全的 SOCKS5 代理协议,对于不支持 SOCKS 代理的应用(例如谷歌地球),winXray 在 PAC 模式下会自动为这些应用提供 HTTP 代理。 + +IP 段代理规则: +- [x] 全局路由模式: 比较好的支持 IP 段代理规则 +- [x] PAC模式: winXray 里 PAC 可以支持IP 段代理规则( 完美支持 Telegram )。 + +独立性 +- [ ] 全局路由模式: 不独立,代理规则集成在翻墙软件内核中 +- [x] PAC模式: 完全独立,PAC 代理服务完全独立于翻墙软件,只有 PAC 指定的域名或IP才会与翻墙软件发生交互。 + +兼容性 +- [ ] 全局路由模式: 不是由系统实现的规则,一旦设置全局代理,不管适不适合走代理的软件都被强制使用代理,所以兼容性不太好,会导致上述的 UWP 无法联网等问题。 +- [x] PAC模式: 由系统提供的PAC有良好的兼容性,因为历史悠久,一般的软件都会对PAC有良好的兼容,PAC 主要为适合走代理的浏览器等软件而设计,所以其他软件可以较好的识别并判断是不是要使用 PAC 指定的代理还是直连。 + +简易度 +- [ ] 全局路由模式: 配置复杂,有一定门槛。 +- [x] PAC模式: 配置非常简单。 + + +一般不建议普通用户去编辑路由规则 - 错误的配置可能会导致敏感的流量误走代理服务器。 +专业的事请交给专业的人去做,使用 winXray 可以一键启用、更新 [v2ray-rules-dat](https://github.com/Loyalsoldier/v2ray-rules-dat) 提供的最新路由规则。 + +注意在 winXray 里无论使用 NaïveProxy 还是 SSR,SSRoT 都支持 V2Ray 路由规则。 + +# 设置系统代理失败怎么办 +如果设置代理以后不能正常生效:请首先右键点击 winXray 任务栏的托盘图标,在弹出的右键菜单中点击【查看 Internet 代理设置】,并检查代理设置是否正常。如果 winXray 不能修改代理设置,但是可以手动修改成功,这一般是被安全软件错误地拦截了( 而且安全软件没有正常弹出确认对话框,或者误点了阻止设置 )。这时候请到安全软件的相关设置中将 winXray 添加到信任列表即可。 + +如果不是上面的原因,请按下【Win + R】组合键打开系统运行对话框,输入 regedit 点击确定打开注册表路径 +HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections +然后将“Connections”项删除,注销一下系统即可正常使用代理了。 + +如果上面的方法仍然不行,请在注册表中打开打开路径 +Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinHttpAutoProxySvc +将 start 的值改为 2, 也就是将 WinHttpAutoProxySvc 服务改为自动启动,然后重启计算机即可。 + +# Core 默认路径: + +可在「 winXray/ 配置 / Core配置 」 下载更新 V2Ray Core / Xray Core / SSR Core , +下载更新 V2Ray Core(或 Xray Core)完成后会自动切换 V2Ray 内核。 + +默认会在以下目录查找 V2Ray Core(或 Xray Core): + + ./v2ray-core/ + %localappdata%\winXray\core + +默认会在以下目录查找 SSR Core: + + ./v2ray-core/ssr-core + %localappdata%\winXray\ssr-core + +默认会在以下目录查找 NaïveProxy Core: + + ./v2ray-core/naive-core + %localappdata%\winXray\naive-core + +找不到会自动下载,没有代理访问 Github 会很慢很慢,有时可能根本打不开,建议经常运行一下 winXray 工具里自带的 【Github 网速优化工具】 + +注意不同的代理协议连接时会调用不同的 Core, +例如 NaïveProxy 连接时会启动 naive.exe,这时候系统防火墙会有提示, +如果这时候没看清就点了拒绝,那么就无法正常使用相应的 Core 了, +所以请看清楚再点,点错了到系统防火墙里再打开一下就可以了。 + +# 安装 NaïveProxy 服务端 + +参考:https://github.com/klzgrad/naiveproxy 以 CentOS 为例: + +```sh +yum intall golang +yum install git +go get -u github.com/caddyserver/xcaddy/cmd/xcaddy +~/go/bin/xcaddy build --with github.com/caddyserver/forwardproxy@caddy2=github.com/klzgrad/forwardproxy@naive +sudo setcap cap_net_bind_service=+ep ./caddy +wget -O naive.tar.xz https://github.com/klzgrad/naiveproxy/releases/download/v88.0.4324.96-1/naiveproxy-v88.0.4324.96-1-linux-x64.tar.xz +tar -xf ./naive.tar.xz + +mv naiveproxy-v88.0.4324.96-1-linux-x64 naive +echo -e "{\n \"listen\": \"socks://127.0.0.1:1080\",\n \"proxy\": \"https://user:pass@example.com\"\n}" > ./naive/config.json + +cat << EOF > ./Caddyfile +:443, example.com +tls me@example.com +route { + forward_proxy { + basic_auth user pass + hide_ip + hide_via + probe_resistance + } + file_server { root /var/www/html } +} +EOF + +iptables -A INPUT -p tcp --dport 80 -j ACCEPT;iptables -A INPUT -p tcp --dport 443 -j ACCEPT;firewall-cmd --permanent --add-port=80/tcp;firewall-cmd --permanent --add-port=443/tcp;firewall-cmd --reload; + +./naive/naive --config ./naive/config.json & +./caddy run # 后台运行改成 ./caddy start +``` + +安装以前需要提前准备一个域名,并将上面脚本中的 example.com 替换为你的域名,user:pass 改为代理登录用户名与密码。 \ No newline at end of file diff --git a/default.aproj b/default.aproj new file mode 100644 index 0000000..81b1507 --- /dev/null +++ b/default.aproj @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/forms/ico/app-direct.ico b/forms/ico/app-direct.ico new file mode 100644 index 0000000..5de600e Binary files /dev/null and b/forms/ico/app-direct.ico differ diff --git a/forms/ico/app-pac.ico b/forms/ico/app-pac.ico new file mode 100644 index 0000000..95d7a0d Binary files /dev/null and b/forms/ico/app-pac.ico differ diff --git a/forms/ico/app.ico b/forms/ico/app.ico new file mode 100644 index 0000000..1b9402b Binary files /dev/null and b/forms/ico/app.ico differ diff --git a/forms/main/config/advancedConfig.aardio b/forms/main/config/advancedConfig.aardio new file mode 100644 index 0000000..f050347 --- /dev/null +++ b/forms/main/config/advancedConfig.aardio @@ -0,0 +1,396 @@ +import fonts.fontAwesome; +import win.ui; +/*DSG{{*/ +var winform = win.form(text="aardio form";right=892;bottom=573;bgcolor=16777215) +winform.add( +btnOpenFirewall={cls="plus";text="设置防火墙";left=485;top=398;right=615;bottom=428;align="left";db=1;dl=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=12}};iconText='\uF09C';notify=1;textPadding={left=30};z=7}; +btnUpdate={cls="plus";text="保 存";left=516;top=514;right=619;bottom=550;align="left";bgcolor=11580047;db=1;dl=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=22}};iconText='\uF0C7';notify=1;textPadding={left=40};z=5}; +chkEnableGitConfigGithub={cls="plus";text="设置 git 客户端启用 github.com 代理提速(支持https、ssh协议)";left=276;top=437;right=792;bottom=468;align="left";bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-16;name='FontAwesome')};iconText='\uF0C8';notify=1;textPadding={left=19};z=13}; +chkLan={cls="plus";text="允许来自局域网的连接";left=276;top=397;right=483;bottom=428;align="left";bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-16;name='FontAwesome')};iconText='\uF0C8';notify=1;textPadding={left=19};z=1}; +chkSystemStart={cls="plus";text="允许开机启动 winXray";left=276;top=476;right=792;bottom=507;align="left";bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-16;name='FontAwesome')};iconText='\uF0C8';notify=1;textPadding={left=19};z=17}; +editHttpPort={cls="plus";left=278;top=126;right=358;bottom=150;align="left";bgcolor=16777215;border={bottom=1;color=-8355712};db=1;dl=1;editable="edit";font=LOGFONT(h=-16);textPadding={bottom=1};z=14}; +editLanPacUrl={cls="plus";left=280;top=357;right=699;bottom=381;align="left";bgcolor=16777215;border={bottom=1;color=-8355712};db=1;dl=1;editable="edit";font=LOGFONT(h=-16);textPadding={bottom=1};z=11}; +editPacPort={cls="plus";left=278;top=281;right=358;bottom=305;align="left";bgcolor=16777215;border={bottom=1;color=-8355712};db=1;dl=1;editable="edit";font=LOGFONT(h=-16);textPadding={bottom=1};z=2}; +editPacUrl={cls="plus";left=278;top=318;right=697;bottom=342;align="left";bgcolor=16777215;border={bottom=1;color=-8355712};db=1;dl=1;editable="edit";font=LOGFONT(h=-16);textPadding={bottom=1};z=8}; +editSocksPort={cls="plus";left=278;top=91;right=358;bottom=115;align="left";bgcolor=16777215;border={bottom=1;color=-8355712};db=1;dl=1;editable="edit";font=LOGFONT(h=-16);textPadding={bottom=1};z=3}; +hotkey={cls="hotkey";left=227;top=249;right=367;bottom=269;clip=1;db=1;dl=1;edge=1;z=26}; +lbMaxTestServers={cls="static";text="100";left=564;top=62;right=880;bottom=88;bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-13);transparent=1;z=25}; +lbTestInterval={cls="static";text="15秒";left=564;top=26;right=823;bottom=52;bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-13);transparent=1;z=20}; +lnkVersion={cls="plus";text="正在检查新版本";left=15;top=533;right=376;bottom=564;align="left";color=8388608;db=1;dl=1;font=LOGFONT(h=-13);iconColor=2960685;iconStyle={align="left";font=LOGFONT(h=-16;name='FontAwesome')};iconText='\uF021';notify=1;paddingLeft=20;z=10}; +plus={cls="plus";text="全局/PAC 代理切换热键";left=368;top=248;right=702;bottom=270;align="left";db=1;dl=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(name='FontAwesome');padding={left=9}};iconText='\uF11C ';notify=1;tabstop=1;textPadding={left=25};z=27}; +radioHttpPac={cls="plus";text="仅 HTTP";left=273;top=167;right=365;bottom=198;align="left";bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-16;name='FontAwesome')};iconText='\uF111 ';notify=1;textPadding={left=19};z=21}; +radioHttpProxy={cls="plus";text="HTTP( 推荐 )";left=378;top=205;right=537;bottom=236;align="left";bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-16;name='FontAwesome')};iconText='\uF111 ';notify=1;textPadding={left=19};z=29}; +radioSocksPac={cls="plus";text="SOCKS5/SOCKS4/HTTP 自动兼容( 推荐 ) ";left=378;top=167;right=727;bottom=198;align="left";bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-16;name='FontAwesome')};iconText='\uF111 ';notify=1;textPadding={left=19};z=22}; +radioSocksProxy={cls="plus";text="SOCKS4";left=273;top=205;right=371;bottom=236;align="left";bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-16;name='FontAwesome')};iconText='\uF111 ';notify=1;textPadding={left=19};z=28}; +static={cls="static";text="SOCKS 代理服务端口:";left=68;top=95;right=266;bottom=121;align="right";bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-16);transparent=1;z=4}; +static10={cls="static";text="PAC代理模式:";left=8;top=170;right=266;bottom=196;align="right";bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-16);transparent=1;z=30}; +static11={cls="static";text="全局代理模式:";left=8;top=208;right=266;bottom=234;align="right";bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-16);transparent=1;z=31}; +static2={cls="static";text="PAC 端口:";left=136;top=286;right=266;bottom=312;align="right";bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-16);transparent=1;z=6}; +static3={cls="static";text="本机 PAC 地址:";left=108;top=325;right=266;bottom=351;align="right";bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-16);transparent=1;z=9}; +static4={cls="static";text="局域网 PAC 地址:";left=108;top=364;right=266;bottom=390;align="right";bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-16);transparent=1;z=12}; +static5={cls="static";text="HTTP 代理服务端口:";left=8;top=132;right=266;bottom=158;align="right";bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-16);transparent=1;z=15}; +static6={cls="static";text="支持 SOCKS4、SOCKS4A、SOCKS5";left=366;top=96;right=653;bottom=122;bgcolor=16777215;color=5921370;db=1;dl=1;font=LOGFONT(h=-13);transparent=1;z=16}; +static7={cls="static";text="检测服务器异常间隔时间:";left=21;top=19;right=266;bottom=45;align="right";bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-16);transparent=1;z=19}; +static8={cls="static";text="允许同时测速的服务器数目:";left=21;top=57;right=266;bottom=83;align="right";bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-16);transparent=1;z=24}; +tbMaxTestServers={cls="plus";left=278;top=64;right=559;bottom=76;bgcolor=-2512093;border={radius=-1};color=23807;db=1;dl=1;foreRight=13;forecolor=-14911489;notify=1;paddingBottom=5;paddingTop=5;z=23}; +tbTestInterval={cls="plus";left=278;top=27;right=559;bottom=39;bgcolor=-2512093;border={radius=-1};color=23807;db=1;dl=1;foreRight=13;forecolor=-14911489;notify=1;paddingBottom=5;paddingTop=5;z=18} +) +/*}}*/ + +import style; +winform.chkLan.skin(style.checkBox); +winform.chkEnableGitConfigGithub.skin(style.checkBox); +winform.chkSystemStart.skin(style.checkBox); +winform.radioHttpProxy.skin(style.radio) +winform.radioSocksProxy.skin(style.radio) +winform.radioHttpPac.skin(style.radio) +winform.radioSocksPac.skin(style.radio) +winform.btnUpdate.skin(style.primaryButton); +winform.editSocksPort.skin(style.edit); +winform.editPacPort.skin(style.edit); +winform.editPacUrl.editBox.readonly = true; + +import win.ui.tooltip; +var tooltipCtrl = win.ui.tooltip( winform ); +tooltipCtrl.addTool(winform.editSocksPort,"点击右键可以复制IP:端口" ); +tooltipCtrl.addTool(winform.radioHttpProxy,"全局代理使用 HTTP 代理端口可以避免使用本机 DNS 解析域名。" ); +tooltipCtrl.addTool(winform.radioSocksProxy,'全局代理使用 SOCKS 代理端口时,Chrome 浏览器等会默认选用 SOCKS4 协议,SOCKS4 会使用本机 DNS 解析域名。' ); +tooltipCtrl.addTool(winform.radioHttpPac,"PAC 仅使用使用 HTTP 代理端口,不推荐此选项。" ); +tooltipCtrl.addTool(winform.radioSocksPac,'开启此选项以后:\nChrome 浏览器会优先使用高效安全的 SOCKS 5 协议。\n也可以自动兼容仅支持 SOCKS4 或 HTTP代理的应用' ); + +import v2ray.pacServer; +onPacUpdated = function(){ + winform.editPacPort.text = v2ray.pacServer.getPort() || config.proxy.pacPort || 1083; + + var pac = v2ray.pacServer.getUrl(); + winform.editPacUrl.text = pac ? string.match(pac,"[^?]+"); + pac = v2ray.pacServer.getUrl(true); + winform.editLanPacUrl.text = pac ? string.match(pac,"[^?]+"); + + winform.editLanPacUrl.disabled = !winform.chkLan.checked; +} + +subscribe("pacServer.restarted",function(pacPort){ + onPacUpdated() +}) + +subscribe("sysProxy.modeChanged",function(mode){ + if(mode==="pac"){ + var pac = v2ray.pacServer.getUrl(); + winform.editPacUrl.text = pac ? string.match(pac,"[^?]+"); + pac = v2ray.pacServer.getUrl(true); + winform.editLanPacUrl.text = pac ? string.match(pac,"[^?]+"); + } +}) + +import v2ray.core; +var onInboundsUpdated = function(){ + var inbounds = ..config.core.default[["inbounds"]]; + var socksInbounds,httpInbounds; + for(k,ib in inbounds){ + if(ib.tag == "proxy"){ + socksInbounds = ib; + } + elseif(ib.tag == "http_proxy"){ + httpInbounds = ib; + } + } + + winform.editSocksPort.text = v2ray.core.socksProxyPort || socksInbounds[["port"]] || 1081; + winform.editHttpPort.text = v2ray.core.httpProxyPort || httpInbounds[["port"]] || 1082; + winform.chkLan.checked = socksInbounds[["listen"]] !== "127.0.0.1"; + winform.btnOpenFirewall.disabled = !winform.chkLan.checked; +} + +subscribe("config.core.changed",function(){ + onInboundsUpdated(); +}) + +subscribe("v2RayCore.restarted",function(socksProxyPort,httpProxPort){ + onInboundsUpdated(); +}) + +import win.reg; +var reg = win.reg("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run\"); +winform.chkSystemStart.checked = reg.queryValue("winXray"); +reg.close(); + +winform.chkEnableGitConfigGithub.checked = config.proxy.enableGitConfigGithub; +winform.radioSocksProxy.radioGroup = "proxy.mode"; +winform.radioHttpProxy.radioGroup = "proxy.mode"; +winform.radioHttpPac.radioGroup = "pac.mode"; +winform.radioSocksPac.radioGroup = "pac.mode"; +winform.radioHttpProxy.checked = config.proxy.useHttpGlobal; +winform.radioSocksProxy.checked = !config.proxy.useHttpGlobal; +winform.radioHttpPac.checked = !config.proxy.useSocksPac; +winform.radioSocksPac.checked = config.proxy.useSocksPac; +winform.hotkey.sethotkey(config.proxy.hotkey[1],config.proxy.hotkey[2]) +onInboundsUpdated(); +onPacUpdated(); + +import wsock.tcp.client; +winform.btnUpdate.oncommand = function(id,event){ + winform.btnUpdate.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'}; + config.proxy.useHttpGlobal = winform.radioHttpProxy.checked; + config.proxy.useSocksPac = winform.radioSocksPac.checked; + v2ray.pacServer.updateUseHttpProxy(!config.proxy.useSocksPac); + + var client = wsock.tcp.client(); + var oldPort = v2ray.core.socksProxyPort; + if( tonumber(winform.editSocksPort.text) + && tonumber(winform.editSocksPort.text) != oldPort + && client.connectTimeout("127.0.0.1",tonumber(winform.editSocksPort.text) ,0.5) ){ + winform.editSocksPort.editBox.showErrorTip(,"端口已被占用"); + winform.btnUpdate.disabledText = null; + return client.close(); + } + client.close(); + + var client = wsock.tcp.client(); + var oldHttpPort = v2ray.core.httpProxPort; + if( tonumber(winform.editHttpPort.text) + && tonumber(winform.editHttpPort.text) != oldHttpPort + && client.connectTimeout("127.0.0.1",tonumber(winform.editHttpPort.text) ,0.5) ){ + winform.editHttpPort.editBox.showErrorTip(,"端口已被占用"); + winform.btnUpdate.disabledText = null; + return client.close(); + } + client.close(); + + var client = wsock.tcp.client(); + var oldPacPort = v2ray.pacServer.getPort(); + if( tonumber(winform.editPacPort.text) + && tonumber(winform.editPacPort.text) != oldPacPort + && client.connectTimeout("127.0.0.1",tonumber(winform.editPacPort.text) ,0.5) ){ + winform.editPacPort.editBox.showErrorTip(,"PAC端口已被占用"); + winform.btnUpdate.disabledText = null; + return client.close(); + } + client.close(); + + + if(winform.chkEnableGitConfigGithub.checked!=config.proxy.enableGitConfigGithub){ + config.proxy.enableGitConfigGithub = winform.chkEnableGitConfigGithub.checked; + + import v2ray.github; + if(!config.proxy.enableGitConfigGithub){ + v2ray.github.setProxy(false); + } + else { + v2ray.github.setProxy(null); + } + } + + var restartCore = false; + + var socksInbounds,httpInbounds; + for(k,ib in config.core.default.inbounds){ + if(ib.tag == "proxy"){ + socksInbounds = ib; + } + elseif(ib.tag == "http_proxy"){ + httpInbounds = ib; + } + } + + var port = tonumber(winform.editSocksPort.text) + socksInbounds["port"] = port; + if(port!=oldPort){ + restartCore = true; + } + + var port = tonumber(winform.editHttpPort.text) + httpInbounds["port"] = port; + if(port!=oldHttpPort){ + restartCore = true; + } + + var listen = winform.chkLan.checked ? "0.0.0.0" : "127.0.0.1"; + if(listen!=socksInbounds["listen"]){ + socksInbounds["listen"]= listen; + restartCore = true; + } + + if(listen!=config.core.default.inbounds[2]["listen"]){ + httpInbounds["listen"]= listen; + restartCore = true; + } + + config.core.save(); + publish("config.inbounds.changed"); + if(restartCore) { + publish("uiCommand.restartV2RayCore"); + } + + config.proxy.pacPort = tonumber(winform.editPacPort.text) + if(oldPacPort!=tonumber(winform.editPacPort.text)){ + v2ray.pacServer.restart(); + } + + config.proxy.save(); + sysProxy.reset(true); + + import win.reg; + var reg = win.reg("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run\"); + if(!_STUDIO_INVOKED){ + if(winform.chkSystemStart.checked){ + reg.setSzValue("winXray",`"`+io._exepath+`" /tray`); + } + else { + reg.delValue("winXray"); + } + } + reg.close(); + + var hotmod,hotkey = winform.hotkey.gethotkey() + config.proxy.hotkey = {hotmod;hotkey}; + config.proxy.save(); + + publish("uiCommand.HotkeyChanged"); + + winform.btnUpdate.disabledText = null; + winform.msgOk("配置已更新",1200); +} + +winform.editPacUrl.editBox.readonly = true; +winform.editLanPacUrl.editBox.readonly = true; + +import win.clip; +import wsock.tcp.client; +winform.editSocksPort.editBox.enablePopMenu(function(){ + var lanIp = wsock.tcp.client.getLocalIp("www.baidu.com"); + return { + { "复制端口" + winform.editSocksPort.text; + function(id){ + win.clip.write("" + winform.editSocksPort.text) + } + }; + { "复制本机IP与端口 127.0.0.1:" + winform.editSocksPort.text; + function(id){ + win.clip.write("127.0.0.1:" + winform.editSocksPort.text) + } + }; + { "复制局域网IP与端口 "+lanIp+":" + winform.editSocksPort.text; + function(id){ + win.clip.write(lanIp+":" + winform.editSocksPort.text) + } + }; + } +} ) + +winform.editHttpPort.editBox.enablePopMenu(function(){ + var lanIp = wsock.tcp.client.getLocalIp("www.baidu.com"); + return { + { "复制端口" + winform.editHttpPort.text; + function(id){ + win.clip.write("" + winform.editHttpPort.text) + } + }; + { "复制本机IP与端口 127.0.0.1:" + winform.editHttpPort.text; + function(id){ + win.clip.write("127.0.0.1:" + winform.editHttpPort.text) + } + }; + { "复制局域网IP与端口 "+lanIp+":" + winform.editHttpPort.text; + function(id){ + win.clip.write(lanIp+":" + winform.editHttpPort.text) + } + }; + } +} ) + +winform.editPacUrl.setCueBannerText("当前未启用本机PAC代理"); +winform.editLanPacUrl.setCueBannerText("当前未启用局域网PAC代理"); + +winform.chkLan.oncommand = function(id,event){ + winform.editLanPacUrl.editBox.setsel(0); + winform.editLanPacUrl.disabled = !winform.chkLan.checked; + winform.btnOpenFirewall.disabled = !winform.chkLan.checked; +} + +winform.tbTestInterval.setTrackbarRange(1,30); +winform.tbTestInterval.skin(style.trackbar); +winform.tbTestInterval.progressPos = config.proxy.testInterval; +winform.lbTestInterval.text = config.proxy.testInterval+"秒"; +winform.tbTestInterval.onPosChanged = function( pos,thumbTrack ){ + winform.lbTestInterval.text = pos+"秒"; + config.proxy.testInterval = pos; + config.proxy.save(); +} + +winform.tbMaxTestServers.setTrackbarRange(50,1000); +winform.tbMaxTestServers.skin(style.trackbar); +winform.tbMaxTestServers.progressPos = config.proxy.maxTestServers; +winform.lbMaxTestServers.text = config.proxy.maxTestServers+"个服务器"; +winform.tbMaxTestServers.onPosChanged = function( pos,thumbTrack ){ + if(pos>300){ + winform.lbMaxTestServers.color = 0xFF; + winform.lbMaxTestServers.text = pos+"个服务器( 数值太大可能导致卡顿 )"; + } + else { + winform.lbMaxTestServers.color = 0; + winform.lbMaxTestServers.text = pos+"个服务器"; + } + + config.proxy.maxTestServers = pos; + config.proxy.save(); +} + +if(table.getByNamespace("fsys.update.simpleMain")){ + fsys.update.simpleMain.onStatusChanged(function(version,description,status){ + /*注意此回调可捕获到调用前或调用后的更新状态变更*/ + if(status=="ready"){ + winform.lnkVersion.disabledText = null; + winform.lnkVersion.text = "点这里重新启动软件更新到新版本:" + version + tooltipCtrl.addTool(winform.lnkVersion,description); + } + elseif(status=="complete"){ + winform.lnkVersion.text = "已更新到最新版本:" + version; + tooltipCtrl.addTool(winform.lnkVersion,description); + ..publish("uiCommand.print",winform.lnkVersion.text ); + } + elseif(status=="latest"){ + winform.lnkVersion.disabledText = null; + winform.lnkVersion.text = "已经是最新版本"; + + } + elseif(status=="failed"){ + winform.lnkVersion.disabledText = null; + ..publish("uiCommand.print",description); + ..publish("uiCommand.print","建议在「工具」中运行「github优化工具」修复无法访问 raw.githubusercontent.com 的问题。"); + } + }) + + winform.lnkVersion.skin(style.link) + tooltipCtrl.addTool(winform.lnkVersion,"点击检测更新" ); + winform.lnkVersion.oncommand = function(id,event){ + + winform.lnkVersion.text = fsys.update.simpleMain.getReadyStatusInfo() ? "正在启动自动更新" : "正在检查新版本"; + winform.lnkVersion.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} + if(fsys.update.simpleMain.checkUpdate(true)){ + win.quitMessage(); + } + } +} +else { + winform.lnkVersion.iconText = '\uF09B'; + winform.lnkVersion.text = "github.com/win-xray/win-xray"; + tooltipCtrl.addTool(winform.lnkVersion,"访问项目主页,友情提醒:WinXray未注册任何域名,谨防钓鱼网站" ); + + winform.lnkVersion.oncommand = function(id,event){ + + import process; + process.openUrl("https://github.com/win-xray/win-xray"); + } +} + + +winform.btnOpenFirewall.skin(style.plainButton) +winform.btnOpenFirewall.oncommand = function(id,event){ + import process.control; + process.control("firewall.cpl") +} + +winform.show(); +win.loopMessage(); +return winform; \ No newline at end of file diff --git a/forms/main/config/coreConfigs/default.json b/forms/main/config/coreConfigs/default.json new file mode 100644 index 0000000..75489b2 --- /dev/null +++ b/forms/main/config/coreConfigs/default.json @@ -0,0 +1,71 @@ +{ + "inbounds": [ // 入站节点,也就是本地代理端口配置 + { + "listen": "127.0.0.1", // 本机 SOCKS 代理端口,设为 0 时由 winXray 重置为合适的默认端口 + "port": 0, // 本机 SOCKS 代理端口,设为 0 时由 winXray 重置为合适的默认端口 + "protocol": "socks", // 入站代理协议 + "settings": { + "auth": "noauth", + "udp": true + }, + "sniffing": { + "destOverride": [ + "http", + "tls" + ], + "enabled": true + }, + "tag": "proxy" // 名称为"proxy"的节点由 winXray 自动维护并添加用户配置 + }, + { + "listen": "127.0.0.1", + "port": 0, + "protocol": "http", + "settings": {}, + "sniffing": { + "destOverride": [ + "http", + "tls" + ], + "enabled": true + }, + "tag": "http_proxy" // 名称为"http_proxy"的入站节点由 winXray 自动维护并添加用户配置 + } + ], + "log": { + "access": "", + "error": "", + "loglevel": "warning" + }, + "outbounds": [ + { + "tag": "proxy" // 名称为"proxy"的节点由 winXray 自动维护并添加用户配置 + }, + { + "protocol": "freedom", + "settings": {}, + "tag": "direct" + }, + { + "protocol": "blackhole", + "settings": { + "response": { + "type": "http" + } + }, + "tag": "block" + } + ], + "routing": { + "domainStrategy": "IPIfNonMatch", + "rules": [ + { + "inboundTag": [ + "api" + ], + "outboundTag": "api", + "type": "field" + } + ] + } +} \ No newline at end of file diff --git a/forms/main/config/coreConfigs/v2ray.rules.json b/forms/main/config/coreConfigs/v2ray.rules.json new file mode 100644 index 0000000..a9a301e --- /dev/null +++ b/forms/main/config/coreConfigs/v2ray.rules.json @@ -0,0 +1,164 @@ +{ + "inbounds": [ // 入站节点,也就是本地代理端口配置 + { + "listen": "127.0.0.1", // 本机监听IP,允许局域网时需要设为 "0.0.0,0" + "port": 1081, // 本机 SOCKS 代理端口,设为 0 时由 winXray 重置为合适的默认端口 + "protocol": "socks", // 入站代理协议 + "settings": { + "auth": "noauth", + "udp": true + }, + "sniffing": { + "destOverride": [ + "http", + "tls" + ], + "enabled": true + }, + "tag": "proxy" // 名称为"proxy"的节点由 winXray 自动维护并添加用户配置 + }, + { + "listen": "127.0.0.1", + "port": 1082, + "protocol": "http", + "settings": {}, + "sniffing": { + "destOverride": [ + "http", + "tls" + ], + "enabled": true + }, + "tag": "http_proxy" // 名称为"http_proxy"的入站节点由 winXray 自动维护并添加用户配置 + } + ], + "log": { + "access": "", + "error": "", + "loglevel": "warning" + }, + "outbounds": [ + { + "tag": "proxy" // 作为第一个节点表示默认走代理,名称为"proxy"的节点由 winXray 自动维护并添加用户配置 + }, + { + "protocol": "dns", + "tag": "Dns-Out" + }, + { + "protocol": "freedom", // 直连出站节点 + "tag": "Direct", // 如果移动到第一个节点表示默认走直连 + "settings": { + "domainStrategy": "UseIPv4" + } + }, + { + "protocol": "blackhole", + "tag": "Reject", + "settings": { + "response": { + "type": "http" + } + } + } + ], + "dns": { + "hosts": { + "dns.google": "8.8.8.8", + "doh.pub": "119.29.29.29" + }, + "servers": [ + "https://dns.google/dns-query", + { + "address": "https+local://223.5.5.5/dns-query", + "domains": [ + "geosite:cn", + "geosite:icloud" + ], + "expectIPs": [ + "geoip:cn" + ] + }, + { + "address": "https://1.1.1.1/dns-query", + "domains": [ + "geosite:geolocation-!cn" + ] + } + ] + }, + "routing": { + "domainStrategy": "IPIfNonMatch", + "rules": [ + { + "type": "field", + "outboundTag": "Direct", + "protocol": [ + "bittorrent" + ] + }, + { + "type": "field", + "outboundTag": "Dns-Out", + "inboundTag": [ + "Socks-In", + "Http-In" + ], + "network": "udp", + "port": 53 + }, + { + "type": "field", + "outboundTag": "Reject", + "domain": [ + "geosite:category-ads-all", + "geosite:win-spy" + ] + }, + { + "type": "field", + "outboundTag": "proxy", + "domain": [ + "full:www.icloud.com", + "domain:icloud-content.com" + ] + }, + { + "type": "field", + "outboundTag": "Direct", + "domain": [ + "geosite:tld-cn", + "geosite:icloud" + ] + }, + { + "type": "field", + "outboundTag": "proxy", + "domain": [ + "geosite:geolocation-!cn" + ] + }, + { + "type": "field", + "outboundTag": "Direct", + "domain": [ + "geosite:cn", + "geosite:private" + ] + }, + { + "type": "field", + "outboundTag": "Direct", + "ip": [ + "geoip:cn", + "geoip:private" + ] + }, + { + "type": "field", + "outboundTag": "proxy", + "network": "tcp,udp" + } + ] + } +} \ No newline at end of file diff --git a/forms/main/config/jsonConfig.aardio b/forms/main/config/jsonConfig.aardio new file mode 100644 index 0000000..0873209 --- /dev/null +++ b/forms/main/config/jsonConfig.aardio @@ -0,0 +1,771 @@ +import fonts.fontAwesome; +import win.ui; +/*DSG{{*/ +var winform = win.form(text="aardio form";right=938;bottom=638;bgcolor=16777215) +winform.add( +advancedConfig={cls="\forms\main\config\advancedConfig.aardio";left=9;top=20;right=930;bottom=594;bgcolor=16777215;db=1;dl=1;dr=1;dt=1;edge=1;z=12}; +btnUpdate={cls="plus";text="更新服务器配置";left=699;top=604;right=868;bottom=635;align="left";bgcolor=11580047;db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=22}};iconText='\uF0C7';notify=1;textPadding={left=40};z=6}; +btnUpdateNaiveCore={cls="plus";text="下载 / 更新 NaÏveProxy Core";left=448;top=7;right=709;bottom=35;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-17;name='FontAwesome');padding={left=18}};iconText='\uF1A0';notify=1;textPadding={left=50};z=17}; +btnUpdateRules={cls="plus";text="下载 / 更新 路由规则";left=227;top=39;right=425;bottom=67;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-19;name='FontAwesome');padding={left=18}};iconText='\uF041';notify=1;textPadding={left=50};z=15}; +btnUpdateSsrCore={cls="plus";text="下载 / 更新 SSR Core";left=16;top=39;right=214;bottom=67;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-17;name='FontAwesome');padding={left=18}};iconText='\uF1D8';notify=1;textPadding={left=50};z=16}; +btnUpdateV2RayCore={cls="plus";text="下载 / 更新 V2Ray Core";left=16;top=5;right=223;bottom=33;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-19;name='FontAwesome');padding={left=18}};iconText='\uF27D';notify=1;textPadding={left=50};z=13}; +btnUpdateXrayCore={cls="plus";text="下载 / 更新 Xray Core";left=227;top=5;right=425;bottom=33;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-19;name='FontAwesome');padding={left=18}};iconText='\uF0E7';notify=1;textPadding={left=50};z=14}; +editCoreConfig={cls="edit";left=9;top=72;right=930;bottom=594;db=1;dl=1;dr=1;dt=1;edge=1;hide=1;hscroll=1;multiline=1;vscroll=1;z=7}; +editOutbounds={cls="edit";left=9;top=29;right=930;bottom=594;db=1;dl=1;dr=1;dt=1;edge=1;hscroll=1;multiline=1;vscroll=1;z=8}; +lbTip={cls="static";text="可在下面输入多行服务器分享链接,或JSON数组( 点击字段名会显示用法说明 ):";left=11;top=9;right=899;bottom=29;color=3947580;dl=1;dr=1;dt=1;font=LOGFONT(h=-13);transparent=1;z=9}; +lbTipForCoreJson={cls="static";text="tag 指定为 proxy,http_proxy 的节点属于自动维护节点 - 不可删除";left=468;top=45;right=849;bottom=68;color=4964352;dl=1;dt=1;transparent=1;z=19}; +navAdvancedConfig={cls="plus";text="代理端口 / 高级配置";left=359;top=600;right=493;bottom=632;border={top=1;color=-16744448};db=1;dl=1;z=10}; +navCoreConfig={cls="plus";text="Core 配置 ( JSON )";left=162;top=600;right=293;bottom=632;border={top=1;color=-16744448};db=1;dl=1;z=3}; +navOutbounds={cls="plus";text="服务器配置( JSON )";left=31;top=600;right=162;bottom=632;border={top=1;color=-16744448};db=1;dl=1;z=2}; +navRight={cls="plus";left=493;top=600;right=762;bottom=601;bgcolor=16777215;border={top=1;color=-16744448};db=1;dl=1;dr=1;linearGradient=180;z=4}; +navSubscription={cls="plus";text="订阅";left=293;top=600;right=359;bottom=632;border={top=1;color=-16744448};db=1;dl=1;z=11}; +navUwpExemption={cls="plus";text="UWP 应用配置";left=499;top=600;right=633;bottom=632;border={top=1;color=-16744448};db=1;dl=1;notify=1;z=18}; +plus={cls="plus";left=9;top=600;right=31;bottom=601;border={top=1;color=-16744448};db=1;dl=1;z=5}; +subscription={cls="\forms\main\config\subscription.aardio";left=9;top=19;right=930;bottom=594;bgcolor=16777215;db=1;dl=1;dr=1;dt=1;edge=1;z=1} +) +/*}}*/ + +import config; +import web.json; +import win.ui.tabs; +var tbs = win.ui.tabs(winform.navOutbounds,winform.navCoreConfig,winform.navSubscription,winform.navAdvancedConfig); +tbs.margin = 0; + +tbs.skin({ + foreground={ + active=0xFFFFFFFF; + default=0x00FFFFFF; + hover=0xFFCCCCCC; + }; + checked={ + foreground={ + default=0x00FFFFFF; + }; + border = { + default = {left=1;right=1;bottom=1;color=0xFF008000} + }; + } +}); + +tbs.onSelchange = function(idx,strip,form){ + winform.btnUpdateSsrCore.hide = idx!=2; + winform.btnUpdateV2RayCore.hide = idx!=2; + winform.btnUpdateXrayCore.hide = idx!=2; + winform.btnUpdateRules.hide = idx!=2; + winform.btnUpdateNaiveCore.hide = idx!=2; + winform.editCoreConfig.hide = idx!=2; + winform.editOutbounds.hide = idx!=1; + winform.subscription.hide = idx!=3; + winform.advancedConfig.hide = idx!=4; + winform.btnUpdate.hide = idx>2; + winform.lbTip.hide = idx!=1; + winform.lbTipForCoreJson.hide = true; + + if(idx==1){ + winform.btnUpdate.text = "更新服务器配置"; + } + elseif(idx==2) { + winform.btnUpdate.text = "更新内核配置 " + } + elseif(idx==3) { + winform.subscription.loadSubscriptionsOnce(); + } +} +tbs.selIndex = 1; + +import style; +winform.btnUpdate.skin(style.primaryButton); +winform.btnUpdate.oncommand = function(id,event){ + winform.btnUpdate.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'}; + + if(tbs.selIndex==1){ + if(..string.match(winform.editOutbounds.text,"%\[\]")){ + var cfg,err = web.json.tryParse(winform.editOutbounds.text); + if(!cfg){ + winform.editOutbounds.showErrorTip(,string.concat("JSON语法错误 ",err)); + winform.btnUpdate.disabledText = null; + return; + } + + if(cfg){ + cfg = v2ray.outbounds.validAll(cfg) + } + config.proxy.outbounds = cfg : ..table.array(); + } + else { + var outbounds = v2ray.outbounds.importFromString(winform.editOutbounds.text); + config.proxy.outbounds = outbounds : ..table.array(); + winform.editOutbounds.text = web.json.stringifyArray(outbounds,true,false,true); + } + + config.proxy.save(); + winform.editOutbounds.modified = false; + publish("uiCommand.restartV2RayCore",cfg) + } + elseif(tbs.selIndex==2) { + var cfg,err = web.json.tryParse(winform.editCoreConfig.text); + if(type(cfg)!==type.table){ + winform.editCoreConfig.showErrorTip(,string.concat("JSON语法错误 ",err)); + winform.btnUpdate.disabledText = null; + return; + } + + var proxyOutboundInCore; + for(k,ob in cfg.outbounds){ + if(ob.tag == "proxy"){ + proxyOutboundInCore = ob; + } + } + + if( type(proxyOutboundInCore) !="table" ){ + winform.msgErr(`outbounds 数组中未找到默认出站节点 {tag:"proxy"}`); + winform.btnUpdate.disabledText = null; + return; + } + + var socksInbounds,httpInbounds; + for(k,ib in cfg.inbounds){ + if(ib.tag == "proxy"){ + socksInbounds = ib; + } + elseif(ib.tag == "http_proxy"){ + httpInbounds = ib; + } + } + + if( type(socksInbounds) !="table" ){ + winform.msgErr(`inbounds 数组中未找到SOCKS协议入站节点 {tag:"proxy"}`); + winform.btnUpdate.disabledText = null; + return; + } + + if( type(httpInbounds) !="table" ){ + winform.msgErr(`inbounds 数组中未找到HTTP协议入站节点 {tag:"http_proxy"}`); + winform.btnUpdate.disabledText = null; + return; + } + + if(type(socksInbounds[["listen"]])!="string"){ + winform.msgErr(`出站节点 {tag:"proxy"} listen字段必须指定IP或0.0.0.0`); + winform.btnUpdate.disabledText = null; + return; + } + + if(type(socksInbounds[["port"]])!="number"){ + winform.msgErr(`出站节点 {tag:"proxy"} port字段必须用数值指定监听端口`); + winform.btnUpdate.disabledText = null; + return; + } + + if(type(httpInbounds[["listen"]])!="string"){ + winform.msgErr(`出站节点 {tag:"http_proxy"} listen字段必须指定IP或0.0.0.0`); + winform.btnUpdate.disabledText = null; + return; + } + + if(type(httpInbounds[["port"]])!="number"){ + winform.msgErr(`出站节点 {tag:"http_proxy"} port字段必须用数值指定监听端口`); + winform.btnUpdate.disabledText = null; + return; + } + + config.core.default = cfg; + config.core.save(); + + publish("uiCommand.restartV2RayCore",cfg); + publish("config.core.changed"); + } + + win.delay(500); + winform.btnUpdate.disabledText = null; + winform.msgOk("配置已更新",1200); +} + + +import v2ray.outbounds; +winform.editOutbounds.enablePopMenu(function(){ + if(tbs.selIndex==1){ + var strEditBounds = string.trim(winform.editOutbounds.text); + var menu = { + { /*---分隔线---*/ }; + { "自剪贴板导入 vmess/vless/trojan/ss 链接或订阅源"; + function(id){ + + var outbounds = v2ray.outbounds.importFromClipboard(); + if(#outbounds){ + var json = strEditBounds; + if( (!#json) || ..string.match(json,"%\[\]")){ + var cfgOutbounds,err = ..table.array(); + if(#json){ + cfgOutbounds,err= web.json.tryParse(strEditBounds); + if(!cfgOutbounds){ + winform.editOutbounds.showErrorTip(,string.concat("当前配置存在JSON语法错误 ",err)); + return; + } + } + + var subscribeUrl = outbounds[1].subscribeUrl; + if(subscribeUrl){ + for(i=#cfgOutbounds;1;-1){ + var outbound = cfgOutbounds[i] + if(outbound.subscribeUrl==url){ + ..table.remove( cfgOutbounds,i ); + } + } + } + + ..table.append(cfgOutbounds,outbounds); + winform.editOutbounds.text = ..web.json.stringifyArray(cfgOutbounds,true,false,true); + } + else { + var str = v2ray.outbounds.exportSharedLinks(outbounds); + if(#strEditBounds){ + winform.editOutbounds.text = strEditBounds+ '\r\n' + str; + } + else { + winform.editOutbounds.text = str; + } + } + + winform.msgOk("已成功导入" + #outbounds + "个服务器,请点击「更新设置」启用新配置。",1200); + winform.editOutbounds.modified = true; + winform.editOutbounds.setFocus(); + return; + } + + winform.msgFrown('未导入服务器!\r\n请先复制以下格式文本(自动清除其中的无效内容):\r\n\r\n1、一行或多行(忽略无效行)分享链接或服务器JSON配置。\r\n支持 vmess://,vless://,ss://,ssr://,trojan://, trojan-go:// 等通用分享链接。\r\n\r\n2、包含多个服务器配置的JSON数组。\r\n\r\n3、单个 http:// 或 https:// 开头的通用订阅源地址。\r\n订阅源地址支持直接使用github项目文件地址(网址含raw或blob目录名)。\r\n订阅源可以BASE64编码或明文返回以上1、2条规定的配置或分享链接。') + } + }; + } + + if( (!#strEditBounds) || ..string.match(strEditBounds,"%\[\]")){ + menu[3] = { "更新当前配置内订阅源"; + function(id){ + var cfg,err = ..table.array(); + + var json = strEditBounds; + if(#json){ + cfg,err = web.json.tryParse(strEditBounds); + if(!cfg){ + winform.editOutbounds.showErrorTip(,string.concat("JSON语法错误 ",err)); + return; + } + } + + var subscribeUrls = {} + for(i=#cfg;1;-1){ + var outbound = cfg[i] + if(outbound.subscribeUrl){ + subscribeUrls[outbound.subscribeUrl] = true; + } + } + + if(!table.count(subscribeUrls)){ + import win.clip; + var clibStr = win.clip.read(); + if( ..string.startWith(clibStr,"http://") || ..string.startWith(clibStr,"https://") ){ + subscribeUrls[clibStr] = true; + } + else { + winform.msgWarn('当前配置不包含来自订阅源的服务器,\n请先复制订阅源网址到剪贴板!'); + return; + } + } + + var count = 0; + for(url,v in subscribeUrls){ + var outbounds = v2ray.outbounds.importFromString(url); + if(#outbounds){ + for(i=#cfg;1;-1){ + var outbound = cfg[i] + if(outbound.subscribeUrl==url){ + ..table.remove( cfg,i ); + } + } + + count = count + #outbounds; + ..table.append(cfg,outbounds); + } + } + + winform.editOutbounds.text = ..web.json.stringifyArray(cfg,true,false,true); + + winform.msgOk("已成功刷新" + count + "个服务器,请点击「更新设置」启用新配置。",1200); + winform.editOutbounds.modified = true; + winform.editOutbounds.setFocus(); + return; + } + }; + } + + if(..string.match(strEditBounds,"%\[\]")){ + menu[4] = {} + menu[5] = { "转换为 vmess、vless、trojan、trojan-go、ss 分享链接"; + function(id){ + var cfgOutbouds,err = web.json.tryParse(strEditBounds); + if(!cfgOutbouds){ + winform.editOutbounds.showErrorTip(,string.concat("JSON语法错误 ",err)); + return; + } + + for(i,ob in cfgOutbouds){ + if(ob.subscribeUrl){ + if(!winform.msgAsk('当前配置包含订阅源,\n转换为分享链接所有服务器与订阅源将解除关联,\n按确定继续操作,按取消中止。')){ + return; + } + + break; + } + } + + var str = v2ray.outbounds.exportSharedLinks(cfgOutbouds); + if(str){ + winform.editOutbounds.text = str; + winform.editOutbounds.modified = true; + } + } + }; + menu[6] = { "转换为 Base64 订阅源"; + function(id){ + var cfg,err = web.json.tryParse(strEditBounds); + if(!cfg){ + winform.editOutbounds.showErrorTip(,string.concat("JSON语法错误 ",err)); + return; + } + + var str = v2ray.outbounds.exportSharedLinks(cfg); + if(str){ + import crypt; + winform.editOutbounds.text = ..crypt.encodeBin(str); + winform.editOutbounds.modified = true; + } + } + }; + } + elseif( #strEditBounds ) { + menu[3] = {} + + menu[4] = { "转换为 JSON"; + function(id){ + import web.json; + var outbounds = v2ray.outbounds.importFromString(strEditBounds); + if(outbounds){ + winform.editOutbounds.text = web.json.stringifyArray(outbounds,true,false,true); + winform.editOutbounds.modified = true; + } + } + }; + } + + table.push(menu,{ /*---分隔线---*/ }); + + table.push(menu,{ "打开配置文件(JSON)"; + function(id){ + import fsys.dlg; + var path = fsys.dlg.open("*.json|*.json||","打开 json 文件",,winform) + if(path){ + winform.editOutbounds.text = string.load(path); + winform.editOutbounds.modified = true; + } + } + }); + + table.push(menu,{ "另存为配置文件(JSON)"; + function(id){ + import fsys.dlg; + var path = fsys.dlg.save("*.json|*.json||","另存为 json 文件",,winform) + if(path){ + var str = web.json.stringifyArray( + config.proxy.outbounds,true,false,true + ) + + string.save(path,str ) + } + } + }); + + table.push(menu,{ "另存为默认服务器列表(JSON)"; + function(id){ + var str = web.json.stringifyArray( + config.proxy.outbounds,true,false,true + ) + + string.save("/v2ray-core/winXray-default-servers.json",str ); + winform.msgOk("已存为默认服务器列表 /v2ray-core/winXray-default-servers.json",1000) + } + }); + + table.push(menu,{ /*---分隔线---*/ }); + if(winform.editOutbounds.modified){ + table.push(menu,{ "恢复为当前使用的服务器列表(JSON)"; + function(id){ + winform.btnUpdate.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} + winform.editOutbounds.text = web.json.stringifyArray( + config.proxy.outbounds,true,false,true + ) + winform.editOutbounds.modified = false; + + win.delay(500); + winform.btnUpdate.disabledText = null; + } + }); + } + + table.push(menu,{ "重置为默认服务器列表(JSON)"; + function(id){ + winform.btnUpdate.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} + ..config.__loadDefaultOutbounds(); + winform.editOutbounds.modified = false; + publish("uiCommand.restartV2RayCore",cfg); + + winform.btnUpdate.disabledText = null; + } + }); + + table.push(menu,{ "清空服务器列表"; + function(id){ + winform.editOutbounds.text = "[]"; + winform.editOutbounds.modified = true; + } + }); + + if( ..string.match(winform.editOutbounds.text,"%\[\]")){ + + table.push(menu,{ /*---分隔线---*/ }); + table.push(menu,{ "插入配置字段";{ + { "代理服务协议:protocol"; + function(id){ + winform.editOutbounds.selText = '"protocol":"vless",' + } + }; + { "SSH管理端口:sshPort"; + function(id){ + winform.editOutbounds.selText = '"sshPort":22,' + } + }; + { "代理服务器地址:address"; + function(id){ + winform.editOutbounds.selText = '"address":"",' + } + }; + { "端口:port"; + function(id){ + winform.editOutbounds.selText = '"port":443,' + } + }; + { "网络协议:network"; + function(id){ + winform.editOutbounds.selText = '"network":"tcp",' + } + }; + { "服务器密码:id"; + function(id){ + winform.editOutbounds.selText = '"id":"",' + } + }; + { "加密方式:security"; + function(id){ + winform.editOutbounds.selText = '"security":"auto",' + } + }; + { "允许忽略证书:allowInsecure"; + function(id){ + winform.editOutbounds.selText = '"allowInsecure":true,' + } + }; + { "TLS服务器名:sni"; + function(id){ + winform.editOutbounds.selText = '"sni":"",' + } + }; + { "启用TLS:tls"; + function(id){ + winform.editOutbounds.selText = '"tls":"tls",' + } + }; + { "流控:flow"; + function(id){ + winform.editOutbounds.selText = '"flow":"xtls-rprx-direct",' + } + }; + { "多路复用最大连接:concurrency"; + function(id){ + winform.editOutbounds.selText = '"concurrency":4,' + } + }; + + { "伪装类型:type"; + function(id){ + winform.editOutbounds.selText = '"type":"http",' + } + }; + { "备注:ps"; + function(id){ + winform.editOutbounds.selText = '"ps":"",' + } + }; + { "请求主机名:host"; + function(id){ + winform.editOutbounds.selText = '"host":"",' + } + }; + { "请求路径:path"; + function(id){ + winform.editOutbounds.selText = '"path":"/",' + } + }; + { "HTTP请求方法:httpMethod"; + function(id){ + winform.editOutbounds.selText = '"httpMethod":"GET",' + } + }; + { "HTTP请求头:headers"; + function(id){ + winform.editOutbounds.selText = '"headers":{"method":"GET"},' + } + }; + { "绑定的订阅网址:subscribeUrl"; + function(id){ + winform.editOutbounds.selText = '"subscribeUrl":"https://",' + } + }; + { "允许自动测试并连接:autoConnect"; + function(id){ + winform.editOutbounds.selText = '"autoConnect":false,' + } + }; + { "备注:ps"; + function(id){ + winform.editOutbounds.selText = '"ps":"",' + } + }; + }}); + } + + return menu; + } +}) + +winform.editCoreConfig.enablePopMenu({ + { /*---分隔线---*/ }; + { "重置为默认内核配置"; + function(id){ + winform.editCoreConfig.text = string.crlf( string.load("\forms\main\config\coreConfigs\default.json") ) + winform.editCoreConfig.msgOk('已重置为默认内核配置。\n请在下面点击:『更新内核配置』启用新的配置。',1300) + } + }; + { "重置为启用路由规则默认内核配置"; + function(id){ + winform.editCoreConfig.text = string.crlf( string.load("\forms\main\config\coreConfigs\v2ray.rules.json") ) + import v2ray.core.rules; + var versionTag = v2ray.core.rules.check(); + if(versionTag) winform.editCoreConfig.msgOk('已重置为启用路由规则默认内核配置,\n已下载路由规则数据最新版本:' + versionTag+ '\n\n请在下面点击:『更新内核配置』启用新的配置。',2000) + else winform.msgOk('已重置为启用路由规则默认内核配置,\n请在下面点击:『更新内核配置』启用新的配置。',1300) + } + }; + { "恢复到当前正在使用的内核配置"; + function(id){ + winform.editCoreConfig.text = web.json.stringify( + config.core.default,true + ) + + winform.editCoreConfig.msgOk('已恢复到当前正在使用的内核配置',1300) + } + }; +} ) + +subscribe("outbounds.updateConfigJson",function(){ + if(winform.editOutbounds.modified){ + return; + } + + winform.editOutbounds.text = web.json.stringifyArray( + config.proxy.outbounds,true,false,true + ) + + winform.editOutbounds.modified = false; +} ) + +winform.editOutbounds.text = web.json.stringifyArray( + config.proxy.outbounds,true,false,true +) : "[]" +winform.editOutbounds.modified = false; + +subscribe("config.inbounds.changed",function(){ + if(winform.editCoreConfig.modified){ + return; + } + + winform.editCoreConfig.text = web.json.stringify( + config.core.default,true + ) + + winform.editCoreConfig.modified = false; +} ) +winform.editCoreConfig.text = web.json.stringify( + config.core.default,true +) + +var editOutboundsTip = { + address = {"代理服务器地址";"值可以是域名或者IP地址"}; + alterId = {"额外ID";"仅用于VMESS协议,与服务器一致即可"}; + aid = {"额外ID(alterId)";"数值,仅用于VMESS协议,与服务器一致即可"}; + network = {"传输协议(network)";"可选值为tcp,ws等,也可以放 SSR 的 protocol 值"}; + net = {"传输协议(network)";"可选值为tcp,ws等"}; + type = {"伪装类型";"默认的可选值为none,http等,kcp或quic此字段表示header.type,可选值为 none,srtp,utp,wechat-video,dtls,wireguard"}; + ps = {"备注";"备注"}; + tls = {"是否启用TLS";"可选值为tls,xtls或空值,vless协议省略时默认值为tls"}; + path = {"请求路径";"用于ws,http等协议指定请求路径"}; + httpMethod = {"HTTP请求方法";"用于http协议指定请求方法"}; + headers = {"HTTP请求头";"用于ws,http等协议指定请求头"}; + id = {"密码";"服务器密码"}; + host = {"主机名";"用于指定http,ws等协议请求头中的主机名"}; + protocol = {"协议";"可选值为 vmess,vless,shadowsocks,trojan,trojan-go 之一"}; + port = {"端口";"服务器端口,数值"}; + security = {"加密方式";"可省略,vmess协议默认为auto,vless协议默认为none"}; + sni = {"TLS服务器名";"TLS客户端请求中的服务器名字段,如果不指定则默认取host或address字段值。"}; + flow = {"流控";"目前仅用于选择 XTLS 的算法,省略时默认值为xtls-rprx-direct"}; + obfs = {"混淆插件";"可选值:plain,http_simple,http_post,tls1.2_ticket_auth ..."}; + obfsParam = {"混淆参数";"SSR 里的 obfs_param"}; + networkParam = {"SSR网络协议参数";"SSR 里的 protocol_param"}; + concurrency = {"Mux多路复用:最大并发连接数";"最小值1,最大值1024,特殊值-1,不加载mux模块。缺省由winXray根据连接协议自动设定此值。"}; +} + +winform.editOutbounds.wndproc = function(hwnd,message,wParam,lParam){ + if(message == 0x202/*_WM_LBUTTONUP*/){ + var lineIndex = winform.editOutbounds.lineFromChar(); + if(lineIndex == winform.editOutbounds.preLineIndex){ + return; + } + winform.editOutbounds.preLineIndex = lineIndex; + + var line = winform.editOutbounds.lineText(); + var n,v = string.match(line,`^\s*\"(\w+)\"\s*\:\s*(%"")[\,\s]*$`); + if( !n ) n,v = string.match(line,`^\s*\"(\w+)\"\s*\:\s*(\d+)[\,\s]*$`); + if( !n ) n,v = string.match(line,`^\s*\"(\w+)\"\s*\:\s*\{`); + if(editOutboundsTip[n]){ + winform.editOutbounds.showInfoTip(editOutboundsTip[n][1],editOutboundsTip[n][2]) + } + } +} + +winform.editCoreConfig.oncommand = function(id,event){ + if( event === 0x100/*_EN_SETFOCUS*/){ + winform.lbTipForCoreJson.hide = false; + } +} + +winform.editOutbounds.limit = 0; +winform.editCoreConfig.limit = 0; + +winform.btnUpdateSsrCore.skin(style.plainButton) +winform.btnUpdateSsrCore.oncommand = function(id,event){ + winform.btnUpdateSsrCore.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'}; + + import v2ray.core.ssr; + var versionTag = v2ray.core.ssr.updateCore(); + if( versionTag ){ + publish("uiCommand.restartV2RayCore"); + winform.btnUpdateSsrCore.disabledText = null; + winform.msgOk("SSR Core( ShadowsocksR-native ) 已更新到:" + versionTag,1500) + } + else { + winform.btnUpdateSsrCore.disabledText = null; + } +} + +winform.btnUpdateV2RayCore.skin(style.plainButton) +winform.btnUpdateV2RayCore.oncommand = function(id,event){ + winform.btnUpdateXrayCore.disabled = true; + winform.btnUpdateV2RayCore.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'}; + + import v2ray.core; + var versionTag = v2ray.core.updateCore(); + if( versionTag ){ + publish("uiCommand.restartV2RayCore"); + winform.btnUpdateV2RayCore.disabledText = null; + winform.msgOk("已下载最新 V2Ray Core 版本:" + versionTag + '\nV2Ray 内核已切换为: V2Ray Core',1500) + } + else { + winform.btnUpdateV2RayCore.disabledText = null; + winform.msgErr("V2Ray Core 下载失败!"); + } + + winform.btnUpdateXrayCore.disabled = false; +} + +winform.btnUpdateXrayCore.skin(style.plainButton) +winform.btnUpdateXrayCore.oncommand = function(id,event){ + + winform.btnUpdateV2RayCore.disabled = true; + winform.btnUpdateXrayCore.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'}; + + import v2ray.core.xray; + var versionTag = v2ray.core.xray.updateCore(); + if( versionTag ){ + publish("uiCommand.restartV2RayCore"); + winform.btnUpdateXrayCore.disabledText = null; + winform.msgOk("已下载最新 XRay Core 版本:" + versionTag+ '\nV2Ray 内核已切换为:XRay Core',1500) + } + else { + winform.btnUpdateXrayCore.disabledText = null; + winform.msgErr("XRay Core 下载失败!"); + } + + winform.btnUpdateV2RayCore.disabled = false; +} + +winform.btnUpdateRules.skin(style.plainButton) +winform.btnUpdateRules.oncommand = function(id,event){ + + winform.btnUpdateRules.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'}; + + import v2ray.core.rules; + var versionTag = v2ray.core.rules.update(); + if( versionTag ){ + publish("uiCommand.restartV2RayCore"); + winform.btnUpdateRules.disabledText = null; + winform.msgOk('已下载路由规则到最新版本:' + versionTag+ '\n请在下面的配置编辑器点击右键,然后点击:\n『重置为启用路由规则默认内核配置』',2000) + } + else { + winform.btnUpdateRules.disabledText = null; + winform.msgErr("路由规则下载失败!"); + } +} + +winform.btnUpdateNaiveCore.skin(style.plainButton) +winform.btnUpdateNaiveCore.oncommand = function(id,event){ + winform.btnUpdateNaiveCore.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'}; + + import v2ray.core.naive; + var versionTag = v2ray.core.naive.updateCore(); + if( versionTag ){ + publish("uiCommand.restartV2RayCore"); + winform.btnUpdateNaiveCore.disabledText = null; + winform.msgOk("NaÏveProxy Core 已更新到:" + versionTag,1500) + } + else { + winform.btnUpdateNaiveCore.disabledText = null; + winform.msgErr("NaÏveProxy Core 下载失败!"); + } +} + +if(!_WIN10_LATER){ + winform.navUwpExemption.close(); +} +else { + winform.navUwpExemption.skin(style.plainButton) + winform.navUwpExemption.oncommand = function( id,event ){ + if(_STUDIO_INVOKED){ + winform.msgErr("请先发布为 EXE!"); + return; + } + + import process; + process.execute(io._exepath,"/uwp","runas") + } +} + +winform.show(); +win.loopMessage(); +return winform; \ No newline at end of file diff --git a/forms/main/config/subscription.aardio b/forms/main/config/subscription.aardio new file mode 100644 index 0000000..2318224 --- /dev/null +++ b/forms/main/config/subscription.aardio @@ -0,0 +1,308 @@ +import fonts.fontAwesome; +import win.ui; +/*DSG{{*/ +var winform = win.form(text="aardio form";right=892;bottom=564;bgcolor=16777215) +winform.add( +btnAdd={cls="plus";text="添加订阅";left=10;top=4;right=143;bottom=31;align="left";dl=1;dt=1;font=LOGFONT(h=-15);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=12}};iconText='\uF196 ';notify=1;textPadding={left=30};z=5}; +btnRemove={cls="plus";text="移除选中订阅";left=143;top=4;right=276;bottom=31;align="left";dl=1;dt=1;font=LOGFONT(h=-15);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=12}};iconText='\uF014';notify=1;textPadding={left=30};z=6}; +btnUpdate={cls="plus";text="更新订阅";left=608;top=506;right=730;bottom=542;align="left";bgcolor=11580047;db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=22}};iconText='\uF0C7';notify=1;textPadding={left=40};z=1}; +chkAll={cls="plus";text="全部启用";left=11;top=489;right=118;bottom=520;align="left";bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-16;name='FontAwesome')};iconText='\uF0C8';notify=1;textPadding={left=19};z=3}; +chkAutoRefreshSubscription={cls="plus";text="允许出站服务器异常自动刷新订阅";left=11;top=524;right=527;bottom=555;align="left";bgcolor=16777215;db=1;dl=1;dr=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-16;name='FontAwesome')};iconText='\uF0C8';notify=1;textPadding={left=19};z=2}; +listview={cls="listview";left=10;top=36;right=883;bottom=477;db=1;dl=1;dr=1;dt=1;edge=1;fullRow=1;gridLines=1;z=4}; +static={cls="static";text="双击上面单元格可直接编辑";left=710;top=616;right=867;bottom=634;color=10789024;db=1;dr=1;transparent=1;z=7} +) +/*}}*/ + +import style; +winform.chkAutoRefreshSubscription.skin(style.checkBox); +winform.chkAll.skin(style.checkBox); +winform.btnAdd.skin(style.plainButton); + +winform.listview.insertColumn("",20) +winform.listview.insertColumn("状态",50) +winform.listview.insertColumn("备注",150) +winform.listview.insertColumn("订阅地址",-1) +winform.listview.checkbox = true; +winform.listview.gridLines = 0; + +import win.ui.grid; +var grid = win.ui.grid(winform.listview);//创建数据视图 +grid.readonlyColums = { [1] = true;[2] = true }; + +import config; +import inet.url; +var reloadSubscriptions = function(){ + winform.chkAutoRefreshSubscription.checked = config.proxy.autoRefreshSubscription; + config.proxy.subscribeUrls.fields = {"";"checked";"ps";"url";} + var outbounds = ..config.proxy.outbounds : ..table.array(); + + var outbondSubscribeUrlMap = {}; + for(i=#outbounds;1;-1){ + var outbound = outbounds[i] + if(outbound.subscribeUrl){ + outbondSubscribeUrlMap[outbound.subscribeUrl] = true; + } + } + + var cfgSubscribeUrls = config.proxy.subscribeUrls; + for(i=#cfgSubscribeUrls;1;-1){ + var sub = cfgSubscribeUrls[i] + if(outbondSubscribeUrlMap[sub.url]){ + outbondSubscribeUrlMap[sub.url] = null; + } + else{ + sub.checked = "禁用"; + } + } + + var count = 0; + for(url,v in outbondSubscribeUrlMap){ + var tUrl = ..inet.url.split(subscribeUrl); + ..table.push(cfgSubscribeUrls,{url=url;ps=tUrl ? tUrl.host : "";checked="启用"}) + } + + var chkAll = true; + var checked = {} + for(i=#cfgSubscribeUrls;1;-1){ + var sub = cfgSubscribeUrls[i] + if(sub.checked=="启用"){ + table.push(checked,i) + } + else { + chkAll = false; + } + } + winform.chkAll.checked = chkAll; + + grid.setTable( cfgSubscribeUrls ); + winform.listview.checked = checked; +} + +winform.loadSubscriptionsOnce = function(){ + reloadSubscriptions(); + winform.loadSubscriptionsOnce = function(){}; +} + +subscribe("uiCommand.subscriptionNew",function(subItem,existIndex){ + if(existIndex){ + winform.listview.setItemText(subItem.url,existIndex,4); + winform.listview.setChecked(existIndex,true); + return; + } + + var item = winform.listview.addItem({"",subItem.checked,subItem.ps,subItem.url}); + winform.listview.setChecked(item,true); +} ) + +//编辑变更值会触发下面的事件 +grid.onEditChanged = function(text,iItem,iSubItem){ + var name = config.proxy.subscribeUrls.fields[iSubItem] + var sub = config.proxy.subscribeUrls[iItem]; + + if( name==="url" ){ + if( text[1]=='/'#) { + text = "https://github.com"+text; + } + + if(sub && sub.ps=="订阅源"){ + import inet.url; + var tUrl = inet.url.split(text); + if(tUrl&&#tUrl.host){ + sub.ps = tUrl.host; + winform.listview.setItemText(sub.ps,iItem,3); + } + } + } + + if(sub){ + sub[name] = text; + config.proxy.save(); + } + else { + winform.msgErr("错误的订阅索引") + } +} + +winform.popmenu = win.ui.popmenu(winform);//创建弹出菜单 +winform.popmenu.add('删除',function(id){ + winform.btnRemove.oncommand(); +}); +winform.popmenu.add('全部删除',function(id){ + for(i=1; winform.listview.count) winform.listview.setSelected(i,true); + winform.btnRemove.oncommand(); +}); +winform.popmenu.add(); +winform.popmenu.add('自剪贴板添加订阅',function(id){ + winform.btnAdd.oncommand(); +}); + +winform.btnUpdate.skin(style.primaryButton); +winform.btnUpdate.oncommand = function(id,event){ + + winform.btnUpdate.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} + config.proxy.autoRefreshSubscription = winform.chkAutoRefreshSubscription.checked; + + var outbondSubscribeUrlMap = {}; + var cfgSubscribeUrls = config.proxy.subscribeUrls; + for(i=#cfgSubscribeUrls;1;-1){ + var sub = cfgSubscribeUrls[i] + outbondSubscribeUrlMap[sub.url] = sub.checked=="启用"; + } + + var removed = 0; + var outbounds = ..config.proxy.outbounds : ..table.array(); + for(i=#outbounds;1;-1){ + var outbound = outbounds[i] + if(outbound.subscribeUrl){ + if(!outbondSubscribeUrlMap[outbound.subscribeUrl]){ + table.remove(outbounds,i); + removed++; + } + } + } + + if(removed) config.proxy.save(); + + import v2ray.outbounds; + if(!v2ray.outbounds.updateSubscription()){ + if(removed) publish("uiCommand.restartV2RayCore",outbounds) + } + + winform.btnUpdate.disabledText = null; +} + +winform.chkAll.oncommand = function(id,event){ + var checked = winform.chkAll.checked + for hItem in winform.listview.each(){ + winform.listview.setChecked(hItem,checked) + } +} + +winform.btnRemove.skin(style.plainButton) +winform.btnRemove.oncommand = function(id,event){ + + var outboundRemoved = 0; + var subscribeUrls = config.proxy.subscribeUrls; + var items = winform.listview.selected; + if(!#items){ + return winform.msgWarn("未选中任何订阅项( 请用鼠标单击订阅链接,不是指「勾选」 )") + } + + winform.btnUpdate.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} + + for(i=#items;1;-1){ + var url = subscribeUrls[items[i]].url; + table.remove(subscribeUrls,items[i]); + winform.listview.delItem(items[i]); + + var outbounds = ..config.proxy.outbounds : ..table.array(); + for(i=#outbounds;1;-1){ + var outbound = outbounds[i] + if(outbound.subscribeUrl===url){ + table.remove(outbounds,i); + outboundRemoved++; + } + } + } + + config.proxy.save(); + + if(outboundRemoved){ + publish("uiCommand.restartV2RayCore") + } + else { + win.delay(200); + } + + publish("outbounds.updateConfigJson"); + winform.btnUpdate.disabledText = null; +} + +winform.btnAdd.oncommand = function(id,event){ + import inet.url; + import win.clip; + + var ps = "订阅源"; + var url = win.clip.read(); + url = url ? string.trim(url,'"\'\s\t\r\n '); + if(url && url[1]=='/'#){ + url = "http://github.com" + url; + } + + if(!inet.url.is(url)){ + url = ""; + } + else { + var tUrl = inet.url.split(url); + if(tUrl && tUrl.host){ + ps = tUrl.host + } + } + + config.proxy.subscribeUrls[winform.listview.count+1] = {checked="启用";ps="订阅源";url=url} + var item = winform.listview.addItem({ + "";"启用";ps;url + }) + + winform.listview.setChecked(item,true); + grid.beginEdit(item,4); +} + +winform.listview.onnotify = function(id,code,ptr){ + if( code == 0xFFFFFF9B/*_LVN_ITEMCHANGED*/ ){ + var nmListView = winform.listview.getNotifyMessage(code,ptr); + if( !nmListView ) + return; + + if( nmListView.uNewState & 0xF000/*_LVIS_STATEIMAGEMASK*/){ + var selIndex = nmListView.iItem; + if( winform.listview.getChecked( selIndex ) ){ + config.proxy.subscribeUrls[selIndex].checked = "启用"; + config.proxy.save(); + + winform.listview.setItemText("启用",selIndex,2); + } + else { + config.proxy.subscribeUrls[selIndex].checked = "禁用"; + config.proxy.save(); + + winform.listview.setItemText("禁用",selIndex,2); + } + + var chkAll = true; + for(i=#config.proxy.subscribeUrls;1;-1){ + var sub = config.proxy.subscribeUrls[i] + if(sub.checked!="启用"){ + chkAll = false; + + } + } + + winform.chkAll.checked = chkAll; + } + } + elseif( code == 0xFFFFFFF4/*_NM_CUSTOMDRAW*/ ) { + var lvcd = winform.listview.getNotifyCustomDraw(code,ptr); + if( lvcd.nmcd.dwDrawStage == 0x10001/*_CDDS_ITEMPREPAINT*/) + return 0x20/*_CDRF_NOTIFYSUBITEMDRAW*/ + elseif( lvcd.nmcd.dwDrawStage == 1/*_CDDS_PREPAINT*/ ){ + return 0x20/*_CDRF_NOTIFYITEMDRAW*/; + } + elseif( lvcd.nmcd.dwDrawStage == ( 0x10001/*_CDDS_ITEMPREPAINT*/ | 0x20000/*_CDDS_SUBITEM*/) ){ + //注意这里 iSubItem 的索引自0开始( 其他函数通常自1开始 ) + lvcd.clrText = lvcd.nmcd.dwItemSpec % 2 ? 0x373737 : 0; + lvcd.clrTextBk = lvcd.nmcd.dwItemSpec % 2 ? 0xFFFFFF : 0xF5F5F5; + lvcd.update(); + + return 0/*_CDRF_DODEFAULT*/ + } + } + elseif( code == 0xFFFFFFFB/*_NM_RCLICK*/ ) { + var x,y = win.getCursorPos(); + winform.popmenu.popup(x,y,true);//弹出菜单 + } +} + +winform.show(); +win.loopMessage(); +return winform; \ No newline at end of file diff --git a/forms/main/outbound.aardio b/forms/main/outbound.aardio new file mode 100644 index 0000000..77af6a2 --- /dev/null +++ b/forms/main/outbound.aardio @@ -0,0 +1,626 @@ +import web.json; +import win.dlg.message; +import fonts.fontAwesome; +import win.ui; +/*DSG{{*/ +var winform = win.form(text="winXray - 代理服务器配置";right=999;bottom=504;bgcolor=16777215;exmode="none";min=false;mode="popup") +winform.add( +btnAddOutbound={cls="plus";text="新 增";left=705;top=410;right=808;bottom=446;align="left";bgcolor=14935259;db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=22}};iconText='\uF067';notify=1;textPadding={left=40};z=17}; +btnCopySharedLink={cls="plus";text="复制";left=829;top=471;right=901;bottom=496;align="left";clip=1;db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=12}};iconText='\uF0C1';notify=1;textPadding={left=30};z=1}; +btnGenGuid={cls="plus";text="生成";left=914;top=259;right=986;bottom=284;align="left";clip=1;dr=1;dt=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=12}};iconText='\uF0AD';notify=1;textPadding={left=30};z=19}; +btnImportSharedLink={cls="plus";text="导入";left=912;top=471;right=984;bottom=496;align="left";clip=1;db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=12}};iconText='\uF0C1';notify=1;textPadding={left=30};z=21}; +btnInsertField={cls="plus";text="插入更多配置字段";left=10;top=0;right=191;bottom=24;align="left";dl=1;dt=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=12}};iconText='\uF196 ';notify=1;textPadding={left=30};z=18}; +btnSaveOutbound={cls="plus";text="保 存";left=826;top=410;right=929;bottom=446;align="left";bgcolor=11580047;db=1;disabled=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=22}};iconText='\uF0C7';notify=1;textPadding={left=40};z=16}; +btnUpdateCore={cls="plus";text="下载 / 更新 NaÏveProxy Core";left=637;top=61;right=979;bottom=89;align="left";color=3947580;dr=1;dt=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-17;name='FontAwesome');padding={left=18}};iconText='\uF0AB';notify=1;textPadding={left=50};z=23}; +cmbNetwork={cls="combobox";left=656;top=97;right=814;bottom=123;dr=1;dt=1;edge=1;items={"tcp";"kcp";"ws";"h2";"quic"};mode="dropdown";z=13}; +cmbProtocol={cls="combobox";left=656;top=28;right=814;bottom=54;dr=1;dt=1;edge=1;items={"vmess";"vless";"trojan";"trojan-go";"ssr";"shadowsocks";"naive";"socks";"https";"http"};mode="dropdown";z=12}; +cmbSecurity={cls="combobox";left=656;top=140;right=814;bottom=166;dr=1;dt=1;edge=1;items={"auto";"none";"chacha20-poly1305";"aes-128-gcm"};mode="dropdown";z=15}; +editAddress={cls="plus";left=656;top=183;right=878;bottom=207;align="left";bgcolor=16777215;border={bottom=1;color=-8355712};dr=1;dt=1;editable="edit";font=LOGFONT(h=-16);textPadding={bottom=1};z=2}; +editId={cls="plus";left=656;top=263;right=986;bottom=287;align="left";bgcolor=16777215;border={bottom=1;color=-8355712};clip=1;dr=1;dt=1;editable="edit";font=LOGFONT(h=-16);notify=1;textPadding={right=75;bottom=1};z=20}; +editOutbound={cls="edit";left=15;top=25;right=472;bottom=462;db=1;dl=1;dr=1;dt=1;edge=1;font=LOGFONT(h=-13);hscroll=1;multiline=1;vscroll=1;z=14}; +editPort={cls="plus";left=656;top=224;right=745;bottom=248;align="left";bgcolor=16777215;num=1;border={bottom=1;color=-8355712};dr=1;dt=1;editable="edit";font=LOGFONT(h=-16);textPadding={bottom=1};z=4}; +editPs={cls="plus";left=656;top=306;right=878;bottom=330;align="left";bgcolor=16777215;border={bottom=1;color=-8355712};dr=1;dt=1;editable="edit";font=LOGFONT(h=-16);textPadding={bottom=1};z=7}; +editSharedLink={cls="plus";left=13;top=475;right=986;bottom=499;align="left";bgcolor=16777215;border={bottom=1;color=-8355712};clip=1;db=1;dl=1;dr=1;font=LOGFONT(h=-16);notify=1;textPadding={right=150;bottom=1};z=22}; +lbId={cls="static";text="登录用户( id ):";left=492;top=262;right=641;bottom=288;align="right";bgcolor=16777215;dr=1;dt=1;font=LOGFONT(h=-16);transparent=1;z=6}; +lbSecurity={cls="static";text="加密方式( security ):";left=473;top=136;right=641;bottom=162;align="right";bgcolor=16777215;dl=1;dr=1;dt=1;font=LOGFONT(h=-16);transparent=1;z=10}; +qrPicture={cls="plus";left=510;top=358;right=606;bottom=454;bgcolor=16777215;db=1;dr=1;notify=1;repeat="scale";z=24}; +static={cls="static";text="服务器( address ):";left=481;top=178;right=641;bottom=204;align="right";bgcolor=16777215;dl=1;dr=1;dt=1;font=LOGFONT(h=-16);transparent=1;z=3}; +static10={cls="static";text="代理协议( protocol ):";left=473;top=26;right=641;bottom=52;align="right";bgcolor=16777215;dl=1;dr=1;dt=1;font=LOGFONT(h=-16);transparent=1;z=11}; +static2={cls="static";text="服务端口( port ):";left=498;top=220;right=641;bottom=246;align="right";bgcolor=16777215;dr=1;dt=1;font=LOGFONT(h=-16);transparent=1;z=5}; +static4={cls="static";text="备注( ps ):";left=498;top=304;right=641;bottom=330;align="right";bgcolor=16777215;dr=1;dt=1;font=LOGFONT(h=-16);transparent=1;z=8}; +static5={cls="static";text="传输协议( network ):";left=473;top=94;right=641;bottom=126;align="right";bgcolor=16777215;dl=1;dr=1;dt=1;font=LOGFONT(h=-16);transparent=1;z=9} +) +/*}}*/ + +winform.outboundConfig = {}; +winform.addOutboundField = function(k,v){ + if(winform.outboundConfig[k] !== null){ + return winform.msgInfo("该字段已经存在,不需要添加!"); + } + + winform.outboundConfig[k] = v; + winform.editOutbound.text = web.json.stringify(winform.outboundConfig,true,false); + winform.updateSharedLink(); +} + +winform.cmbProtocol.onProtocolChange = function(){ + var sel = winform.cmbProtocol.selText; + if(sel=="vmess"){ + winform.cmbSecurity.items = { + "auto";"none";"chacha20-poly1305";"aes-128-gcm" + } + winform.cmbSecurity.selIndex = 1; + winform.outboundConfig.security = "auto"; + + winform.cmbNetwork.items = { + "tcp";"kcp";"h2";"quic"; + } + winform.cmbNetwork.selIndex = 1; + winform.outboundConfig.network = "tcp"; + winform.btnUpdateCore.text = '下载 / 更新支持组件: V2Ray Core'; + winform.editId.setCueBannerText("请输入 GUID"); + } + elseif(sel=="shadowsocks"){ + winform.cmbSecurity.items = { + "aes-256-gcm";"aes-128-gcm";"chacha20-poly1305";"chacha20-ietf-poly1305";"none" + } + + winform.cmbSecurity.selIndex = 1; + winform.outboundConfig.security = "aes-256-gcm"; + + winform.cmbNetwork.items = {"tcp";} + winform.cmbNetwork.selIndex = 1; + winform.outboundConfig.network = "tcp"; + winform.btnUpdateCore.text = '下载 / 更新支持组件: V2Ray Core'; + winform.editId.setCueBannerText("请输入密码"); + } + elseif(sel=="ssr"){ + winform.cmbNetwork.items = { + "origin";"plain";"auth_sha1_v4";"http_simple";"auth_aes128_sha1";"http_post";"auth_aes128_md5";"http_mix";"auth_chain_a";"tls1.2_ticket_auth";"auth_chain_b";"tls1.2_ticket_fastauth";"auth_chain_c/d/e/f"; + } + winform.cmbNetwork.selIndex = 1; + winform.outboundConfig.network = "origin"; + + winform.cmbSecurity.items = { + "none";"table";"rc4";"rc4-md5-6";"rc4-md5";"aes-128-cfb";"aes-192-cfb";"aes-256-cfb";"aes-128-ctr";"aes-192-ctr";"aes-256-ctr";"camellia-128-cfb";"camellia-192-cfb";"camellia-256-cfb";"bf-cfb";"cast5-cfb";"des-cfb";"idea-cfb";"rc2-cfb";"seed-cfb";"salsa20";"chacha20";"chacha20-ietf"; + } + + winform.cmbSecurity.selIndex = 1; + winform.outboundConfig.security = "none"; + winform.btnUpdateCore.text = '下载 / 更新支持组件: SSR Core'; + winform.editId.setCueBannerText("请输入密码"); + } + elseif(sel=="vless"){ + winform.cmbSecurity.items = { + "none"; + } + winform.cmbSecurity.selIndex = 1; + winform.outboundConfig.security = "none"; + + winform.cmbNetwork.items = { + "tcp";"kcp";"h2";"quic"; + } + winform.cmbNetwork.selIndex = 1; + winform.outboundConfig.network = "tcp"; + winform.btnUpdateCore.text = '下载 / 更新支持组件: Xray Core'; + winform.editId.setCueBannerText("请输入 GUID"); + } + elseif(sel=="naive"){ + winform.cmbNetwork.items = { + "https";"quic"; + } + winform.cmbNetwork.selIndex = 1; + winform.outboundConfig.network = "https"; + + winform.cmbSecurity.items = {} + winform.outboundConfig.security = null; + + winform.btnUpdateCore.text = '下载 / 更新支持组件: NaïveProxy Core'; + winform.editId.setCueBannerText("请输入 用户名:密码"); + } + elseif(sel=="socks"){ + winform.cmbSecurity.items = { } + winform.outboundConfig.security = null; + + winform.cmbNetwork.items = {"tcp";} + winform.cmbNetwork.selIndex = 1; + winform.outboundConfig.network = "tcp"; + winform.btnUpdateCore.text = '下载 / 更新支持组件: V2Ray Core'; + winform.editId.setCueBannerText("请输入 用户名:密码"); + } + elseif(sel=="http" || sel=="https"){ + winform.cmbSecurity.items = { } + winform.outboundConfig.security = null; + + winform.cmbNetwork.items = {"tcp";} + winform.cmbNetwork.selIndex = 1; + winform.outboundConfig.network = "tcp"; + winform.btnUpdateCore.text = '下载 / 更新支持组件: V2Ray Core'; + winform.editId.setCueBannerText("请输入 用户名:密码"); + } + else { + winform.cmbSecurity.items = { } + winform.outboundConfig.security = null; + + winform.cmbNetwork.items = {"tcp";} + winform.cmbNetwork.selIndex = 1; + winform.outboundConfig.network = "tcp"; + winform.btnUpdateCore.text = '下载 / 更新支持组件: V2Ray Core'; + winform.editId.setCueBannerText("请输入密码"); + } +} + +winform.cmbProtocol.onListChange = function(){ + winform.cmbProtocol.onProtocolChange(); + + table.define(winform.outboundConfig); + winform.outboundConfig.protocol = winform.cmbProtocol.selText;; + winform.editOutbound.text = web.json.stringify(winform.outboundConfig,true,false); + winform.updateSharedLink(); +} + +winform.cmbNetwork.onListChange = function(){ + var sel = winform.cmbNetwork.selText; + winform.outboundConfig.network = sel; + winform.editOutbound.text = web.json.stringify(winform.outboundConfig,true,false); + winform.updateSharedLink(); +} + +winform.cmbSecurity.onListChange = function(){ + var sel = winform.cmbSecurity.selText; + winform.outboundConfig.security = sel; + winform.editOutbound.text = web.json.stringify(winform.outboundConfig,true,false); + winform.updateSharedLink(); +} + +winform.editId.editBox.onChange = function(){ + if( winform.outboundConfig.id == winform.editId.text ){ + return; + } + + winform.outboundConfig.id = winform.editId.text; + winform.editOutbound.text = web.json.stringify(winform.outboundConfig,true,false); + winform.updateSharedLink(); +} + +winform.editPort.editBox.onChange = function(){ + winform.outboundConfig.port = tonumber(owner.text):443; + winform.editOutbound.text = web.json.stringify(winform.outboundConfig,true,false); + winform.updateSharedLink(); +} + +winform.editAddress.editBox.onChange = function(){ + winform.outboundConfig.address = owner.text; + winform.editOutbound.text = web.json.stringify(winform.outboundConfig,true,false); + winform.updateSharedLink(); +} + +winform.editPs.editBox.onChange = function(){ + winform.outboundConfig.ps = owner.text; + winform.editOutbound.text = web.json.stringify(winform.outboundConfig,true,false); + winform.updateSharedLink(); +} + +var editOutboundTip = { + address = {"代理服务器地址";"值可以是域名或者IP地址"}; + alterId = {"额外ID";"仅用于VMESS协议,与服务器一致即可"}; + aid = {"额外ID(alterId)";"数值,仅用于VMESS协议,与服务器一致即可"}; + network = {"传输协议(network)";"可选值为tcp,ws等,也可以放 SSR 的 protocol 值"}; + net = {"传输协议(network)";"可选值为tcp,ws等"}; + type = {"伪装类型";"默认的可选值为none,http等,kcp或quic此字段表示header.type,可选值为 none,srtp,utp,wechat-video,dtls,wireguard"}; + ps = {"备注";"备注"}; + tls = {"是否启用TLS";"可选值为tls,xtls或空值,vless协议省略时默认值为tls"}; + path = {"请求路径";"用于ws,http等协议指定请求路径"}; + httpMethod = {"HTTP请求方法";"用于http协议指定请求方法"}; + headers = {"HTTP请求头";"用于ws,http等协议指定请求头"}; + id = {"密码";"服务器密码"}; + host = {"主机名";"用于指定http,ws等协议请求头中的主机名"}; + protocol = {"协议";"可选值为 vmess,vless,shadowsocks,trojan,trojan-go 之一"}; + port = {"端口";"服务器端口,数值"}; + security = {"加密方式";"可省略,vmess协议默认为auto,vless协议默认为none"}; + sni = {"TLS服务器名";"TLS客户端请求中的服务器名字段,如果不指定则默认取host或address字段值。"}; + flow = {"流控";"目前仅用于选择 XTLS 的算法,省略时默认值为xtls-rprx-direct"}; + obfs = {"混淆插件";"可选值:plain,http_simple,http_post,tls1.2_ticket_auth ..."}; + obfsParam = {"混淆参数";"SSR 里的 obfs_param"}; + networkParam = {"SSR网络协议参数";"SSR 里的 protocol_param"}; + concurrency = {"Mux多路复用:最大并发连接数";"最小值1,最大值1024,特殊值-1,不加载mux模块。缺省由winXray根据连接协议自动设定此值。"}; +} + +winform.editOutbound.wndproc = function(hwnd,message,wParam,lParam){ + if(message == 0x202/*_WM_LBUTTONUP*/){ + var lineIndex = winform.editOutbound.lineFromChar(); + if(lineIndex == winform.editOutbound.preLineIndex){ + return; + } + winform.editOutbound.preLineIndex = lineIndex; + + var line = winform.editOutbound.lineText(); + var n,v = string.match(line,`^\s*\"(\w+)\"\s*\:\s*(%"")[\,\s]*$`); + if( !n ) n,v = string.match(line,`^\s*\"(\w+)\"\s*\:\s*(\d+)[\,\s]*$`); + if( !n ) n,v = string.match(line,`^\s*\"(\w+)\"\s*\:\s*\{`); + if(editOutboundTip[n]){ + winform.editOutbound.showInfoTip(editOutboundTip[n][1],editOutboundTip[n][2]) + } + } +} + +import win.ui.menu; +var insertFieldMenu = { + { "允许忽略证书:allowInsecure"; + function(id){ + winform.addOutboundField("allowInsecure",true); + } + }; + { "TLS服务器名:sni"; + function(id){ + winform.addOutboundField("sni",""); + } + }; + { "启用TLS:tls"; + function(id){ + winform.addOutboundField("tls","xtls"); + } + }; + { "流控:flow"; + function(id){ + winform.addOutboundField("flow","xtls-rprx-direct"); + } + }; + { "多路复用最大连接:concurrency"; + function(id){ + winform.addOutboundField("concurrency",4); + } + }; + + { "伪装类型:type"; + function(id){ + winform.addOutboundField("type","http"); + } + }; + { "备注:ps"; + function(id){ + winform.addOutboundField("ps",""); + } + }; + { "请求主机名:host"; + function(id){ + winform.addOutboundField("host",""); + } + }; + { "请求路径:path"; + function(id){ + winform.addOutboundField("path","/"); + } + }; + { "HTTP请求方法:httpMethod"; + function(id){ + winform.addOutboundField("httpMethod","GET"); + } + }; + { "HTTP请求头:headers"; + function(id){ + winform.addOutboundField("headers",{method="GET"}); + } + }; + { "SSR混淆插件:obfs"; + function(id){ + winform.addOutboundField("obfs","plain"); + } + }; + { "SSR混淆参数:obfsParam"; + function(id){ + winform.addOutboundField("obfsParam",""); + } + }; + { "SSR网络协议参数:networkParam"; + function(id){ + winform.addOutboundField("networkParam",""); + } + }; + { "绑定的订阅网址:subscribeUrl"; + function(id){ + winform.addOutboundField("subscribeUrl","https://"); + } + }; + { "允许自动测试并连接:autoConnect"; + function(id){ + winform.addOutboundField("autoConnect",false); + } + }; + { "SSH管理端口:sshPort"; + function(id){ + winform.addOutboundField("sshPort",22); + } + }; +} +winform.editOutbound.enablePopMenu({ + { "插入配置字段";insertFieldMenu} +}) + +import style; +winform.btnInsertField.skin(style.transButton) +winform.btnInsertField.oncommand = function(id,event){ + var popInsertFieldMenu = win.ui.popmenu(winform); + popInsertFieldMenu.addTable(insertFieldMenu); + + var x,y,cx,cy = winform.btnInsertField.getPos(); + popInsertFieldMenu.popup(x,y+cy); +} + +import win.debounce; +var onEditChange = win.debounce( + function(){ + var data,err = web.json.tryParse(winform.editOutbound.text); + if(!data){ + if(err){ + return winform.editOutbound.showErrorTip("JSON 语法错误",err) + } + return; + } + + var editPortChange = winform.editPort.editBox.onChange; + var editIdChange = winform.editId.editBox.onChange; + var editAddressChange = winform.editAddress.editBox.onChange; + var editPsChange = winform.editPs.editBox.onChange; + + winform.editPort.editBox.onChange = null; + winform.editId.editBox.onChange = null; + winform.editAddress.editBox.onChange = null; + winform.editPs.editBox.onChange = null; + + winform.editPort.text = data.port; + winform.editId.text = data.id; + winform.editAddress.text = data.address; + winform.editPs.text = data.ps; + + winform.editPort.editBox.onChange = editPortChange; + winform.editId.editBox.onChange = editIdChange; + winform.editAddress.editBox.onChange = editAddressChange; + winform.editPs.editBox.onChange = editPsChange; + + var cmbNetworkChange = winform.cmbNetwork.onListChange; + var cmbProtocolChange = winform.cmbProtocol.onListChange; + var cmbSecurityChange = winform.cmbSecurity.onListChange; + + winform.cmbNetwork.onListChange = null; + winform.cmbProtocol.onListChange = null; + winform.cmbSecurity.onListChange = null; + + winform.cmbNetwork.selText = data.network; + winform.cmbProtocol.selText = data.protocol; + winform.cmbProtocol.onProtocolChange(); + winform.cmbSecurity.selText = data.security; + + winform.cmbNetwork.onListChange = cmbNetworkChange; + winform.cmbProtocol.onListChange = cmbProtocolChange; + winform.cmbSecurity.onListChange = cmbSecurityChange; + + winform.updateSharedLink(); + },500 +) + +winform.editOutbound.onChange = function(){ + onEditChange(); +} + +winform.btnSaveOutbound.oncommand = function(id,event){ + if(!#winform.editAddress.text){ + return winform.editAddress.editBox.showErrorTip("配置错误","服务器地址不能为空") + } + + if(!#winform.editPort.text){ + return winform.editPort.editBox.showErrorTip("配置错误","端口不能为空") + } + + if( !#winform.editId.text ){ + var protocol = winform.outboundConfig.protocol; + if((protocol!="socks") && (protocol!="http") && (protocol!="https")){ + return winform.editId.editBox.showErrorTip("配置错误","当前代理协议密码不能为空") + } + } + + table.assign(winform.origOutboundConfig,winform.outboundConfig); + winform.endModal(); + + publish("uiCommand.restartV2RayCore"); + publish("outbounds.updateConfigJson"); + +} + +import config; +winform.btnAddOutbound.oncommand = function(id,event){ + if(!#winform.editAddress.text){ + return winform.editAddress.editBox.showErrorTip("配置错误","服务器地址不能为空") + } + + if(!#winform.editPort.text){ + return winform.editPort.editBox.showErrorTip("配置错误","端口不能为空") + } + + if(!#winform.editId.text ){ + var protocol = winform.outboundConfig.protocol + if( (protocol!="socks") && (protocol!="http") && (protocol!="https") ){ + return winform.editId.editBox.showErrorTip("配置错误","当前代理协议密码不能为空") + } + } + + table.push(config.proxy.outbounds,winform.outboundConfig); + winform.endModal(); + + publish("uiCommand.restartV2RayCore"); + publish("outbounds.updateConfigJson"); +} + +import win.guid; +winform.btnGenGuid.oncommand = function(id,event){ + var sel = winform.cmbProtocol.selText; + if(sel=="socks" || sel=="http" || sel=="https" || sel=="naive" ){ + winform.editId.text = "user:" + string.random(16); + } + elseif(sel=="shadowsocks" || sel=="ssr" ){ + winform.editId.text = string.random(22,"/@0123456abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + } + else { + var guid = win.guid.create(); + winform.editId.text = string.lower( tostring(guid) ); + } +} +winform.btnGenGuid.skin(style.link) + +winform.btnSaveOutbound.skin(style.button) +winform.btnAddOutbound.skin(style.primaryButton) +winform.btnSaveOutbound.disabled = true; + +import qrencode.bitmap; +import v2ray.outbounds; +winform.updateSharedLink = function(modified){ + var cfg = winform.outboundConfig; + var link = ""; + + if(#cfg.address && (cfg.port!==null) && #cfg.protocol){ + link = v2ray.outbounds.exportSharedLinks({winform.outboundConfig}); + } + + winform.editSharedLink.text = link; + + if(#link){ + var qrBmp = qrencode.bitmap(link,0,0); + if(qrBmp){ + winform.qrPicture.setBackground(qrBmp.copyBitmap(winform.qrPicture.width)); + } + } +} + +import win.clip; +winform.btnImportSharedLink.skin(style.link); +winform.btnImportSharedLink.oncommand = function(id,event){ + var str = ..win.clip.read(); + if(str){ + var outbounds = v2ray.outbounds.importFromString(str); + if(#outbounds){ + var cfg = winform.outboundConfig; + table.clear(cfg); + table.assign(cfg,outbounds[1]); + + winform.editOutbound.text = web.json.stringify(winform.outboundConfig,true,false); + onEditChange(); + + winform.msgOk("已成功导入服务器",1000); + return; + } + } + + winform.msgFrown('未导入服务器!\r\n请先复制以下格式文本(自动清除其中的无效内容):\r\n\r\n1、分享链接或服务器JSON配置。\r\n支持 vmess://,vless://,ss://,ssr://,trojan://, trojan-go:// 等通用分享链接。\r\n\r\n2、服务器配置的JSON数组,支持winXray格式以及通用格式JSON。\r\n其他 BASE64 编码或明文返回以上1、2条规定的配置或分享链接。') +} + +winform.btnCopySharedLink.skin(style.link) +winform.btnCopySharedLink.oncommand = function(id,event){ + var lnk = winform.editSharedLink.text; + if(!#lnk){ + winform.msgErr("分享链接不能为空",1500); + } + else { + win.clip.write(lnk); + winform.msgOk("分享链接已复制到剪贴板",1500); + } +} + + +winform.setOutboundConfig = function(cfg){ + winform.cmbProtocol.selText = cfg.protocol; + winform.cmbProtocol.onListChange(); + + winform.btnAddOutbound.skin(style.button); + winform.btnSaveOutbound.skin(style.primaryButton); + winform.btnSaveOutbound.disabled = false; + + winform.origOutboundConfig = cfg; + winform.outboundConfig = table.clone(cfg); + winform.editOutbound.text = web.json.stringify(winform.outboundConfig,true,false); + onEditChange(); +} +winform.setOutboundConfig({ + port = 443; + protocol = "vmess"; + network = "tcp"; +}); +winform.btnAddOutbound.skin(style.primaryButton); +winform.btnSaveOutbound.skin(style.button); +winform.btnSaveOutbound.disabled = true; + +winform.btnUpdateCore.skin(style.plainButton) +winform.btnUpdateCore.oncommand = function(id,event){ + winform.btnUpdateCore.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'}; + var sel = winform.cmbProtocol.selText; + + if(sel=="ssr"){ + import v2ray.core.ssr; + var versionTag = v2ray.core.ssr.updateCore(); + if( versionTag ){ + publish("uiCommand.restartV2RayCore"); + winform.btnUpdateCore.disabledText = null; + winform.msgOk("SSR Core( ShadowsocksR-native ) 已更新到:" + versionTag,1500) + } + else { + winform.btnUpdateCore.disabledText = null; + } + } + elseif(sel=="vless"){ + import v2ray.core.xray; + var versionTag = v2ray.core.xray.updateCore(); + if( versionTag ){ + publish("uiCommand.restartV2RayCore"); + winform.btnUpdateCore.disabledText = null; + winform.msgOk("已下载最新 XRay Core 版本:" + versionTag+ '\nV2Ray 内核已切换为:XRay Core',1500) + } + else { + winform.btnUpdateCore.disabledText = null; + winform.msgErr("XRay Core 下载失败!"); + } + } + elseif(sel=="naive"){ + import v2ray.core.naive; + var versionTag = v2ray.core.naive.updateCore(); + if( versionTag ){ + publish("uiCommand.restartV2RayCore"); + winform.btnUpdateCore.disabledText = null; + winform.msgOk("NaÏveProxy Core 已更新到:" + versionTag,1500) + } + else { + winform.btnUpdateCore.disabledText = null; + winform.msgErr("NaÏveProxy Core 下载失败!"); + } + } + else { + import v2ray.core; + var versionTag = v2ray.core.updateCore(); + if( versionTag ){ + publish("uiCommand.restartV2RayCore"); + winform.btnUpdateCore.disabledText = null; + winform.msgOk("已下载最新 V2Ray Core 版本:" + versionTag + '\nV2Ray 内核已切换为: V2Ray Core',1500) + } + else { + winform.btnUpdateCore.disabledText = null; + winform.msgErr("V2Ray Core 下载失败!"); + } + } +} + +winform.qrPicture.skin( + foreground = { + hover = 0x10FFFF00; + active = 0x20EEEE00; + } +) +winform.qrPicture.oncommand = function(id,event){ + var lnk = string.trim(winform.editSharedLink.text); + if(#lnk){ + var frmChild = winform.loadForm("\forms\main\tools\qr.aardio"); + frmChild.createQrCode(lnk); + frmChild.show(); + } +} + +winform.show(); +win.loopMessage(); +return winform; \ No newline at end of file diff --git a/forms/main/pac.aardio b/forms/main/pac.aardio new file mode 100644 index 0000000..3e27acb --- /dev/null +++ b/forms/main/pac.aardio @@ -0,0 +1,626 @@ +import win.ui; +import win.ui.atom; +import fonts.fontAwesome; +/*DSG{{*/ +var winform = win.form(text="winXray - 代理自动配置文件(PAC)";right=912;bottom=802;bgcolor=16777215) +winform.add( +btnAddDomain={cls="plus";text="添加";left=625;top=25;right=723;bottom=56;align="left";bgcolor=14935259;dr=1;dt=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=22}};iconText='\uF1C4';notify=1;textPadding={left=40};z=16}; +btnDeleteDomain={cls="plus";text="移除";left=740;top=25;right=838;bottom=56;align="left";bgcolor=14935259;dr=1;dt=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=22}};iconText='\uF1C4';notify=1;textPadding={left=40};z=17}; +btnReset={cls="plus";text="恢复PAC";left=609;top=763;right=741;bottom=794;align="left";bgcolor=14935259;db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=22}};iconText='\uF0E2';notify=1;textPadding={left=40};z=9}; +btnSave={cls="plus";text="保存PAC";left=751;top=763;right=883;bottom=794;align="left";bgcolor=11580047;db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=22}};iconText='\uF0C7';notify=1;textPadding={left=40};z=10}; +btnUpdate={cls="plus";text="同步到网络最新PAC";left=402;top=763;right=599;bottom=794;align="left";bgcolor=14935259;db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=22}};iconText='\uF26B';notify=1;textPadding={left=40};z=7}; +editPacDirect={cls="richedit";left=8;top=97;right=901;bottom=745;db=1;dl=1;dr=1;dt=1;edge=1;font=LOGFONT(h=-13);hidesel=false;hscroll=1;multiline=1;vscroll=1;z=2}; +editPacDomain={cls="plus";left=91;top=29;right=436;bottom=53;align="right";bgcolor=16777215;border={bottom=1;color=-8355712};dl=1;dr=1;dt=1;editable="edit";font=LOGFONT(h=-16);textPadding={bottom=1};z=12}; +editPacProxy={cls="richedit";left=8;top=97;right=901;bottom=751;db=1;dl=1;dr=1;dt=1;edge=1;font=LOGFONT(h=-15);hidesel=false;hscroll=1;multiline=1;vscroll=1;z=3}; +groupbox={cls="groupbox";text="域名项";left=8;top=8;right=901;bottom=64;bgcolor=16777215;dl=1;dr=1;dt=1;edge=1;z=1}; +lbTip={cls="plus";text="以下域名通过代理连接( 点域名绑定上面选项,点击右键菜单可批量导入域名 )。";left=10;top=66;right=898;bottom=92;align="left";color=3947580;dl=1;dr=1;dt=1;font=LOGFONT(h=-13);notify=1;transparent=1;z=13}; +navDirect={cls="plus";text="直连域名( JSON )";left=184;top=750;right=315;bottom=782;border={top=1;color=-16744448};db=1;dl=1;z=8}; +navProxy={cls="plus";text="代理域名( JSON )";left=53;top=750;right=184;bottom=782;border={top=1;color=-16744448};db=1;dl=1;z=5}; +navRight={cls="plus";left=314;top=750;right=604;bottom=751;bgcolor=16777215;border={color=-16744448};db=1;dl=1;dr=1;forecolor=32768;linearGradient=180;z=11}; +plus={cls="plus";left=9;top=750;right=53;bottom=751;border={color=-16744448};db=1;dl=1;forecolor=32768;z=14}; +plus2={cls="plus";text="域名:";left=16;top=28;right=79;bottom=54;align="right";color=3947580;dl=1;dt=1;font=LOGFONT(h=-13);notify=1;transparent=1;z=15}; +radioDirect={cls="plus";text="直连";left=540;top=27;right=611;bottom=58;align="left";dr=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-15;name='FontAwesome')};iconText='\uF111';notify=1;textPadding={left=15};z=6}; +radioProxy={cls="plus";text="代理";left=460;top=27;right=529;bottom=58;align="left";dr=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-15;name='FontAwesome')};iconText='\uF111';notify=1;textPadding={left=15};z=4} +) +/*}}*/ + +import config; +import style; +winform.btnSave.skin(style.primaryButton); +winform.btnUpdate.skin(style.button); +winform.btnReset.skin(style.button); +winform.btnAddDomain.skin(style.button); +winform.btnDeleteDomain.skin(style.button); +winform.radioDirect.skin(style.radio); +winform.radioProxy.skin(style.radio); +winform.radioProxy.checked = true; + +import config; +import web.json; +import win.ui.tabs; +var tbs = win.ui.tabs(winform.navProxy,winform.navDirect,winform.nav06,winform.nav091,winform.navZhengMa,winform.navTxt) +tbs.margin = 0; + +tbs.skin({ + foreground={ + active=0xFFFFFFFF; + default=0x00FFFFFF; + hover=0xFFCCCCCC; + }; + checked={ + foreground={ + default=0x00FFFFFF; + }; + border = { + default = {left=1;right=1;bottom=1;color=0xFF008000} + }; + } +}); + +tbs.onSelchange = function(idx,strip,form){ + if(idx==1){ + winform.currentEditPac = winform.editPacProxy; + winform.editPacProxy.hide = false; + winform.editPacDirect.hide = true; + winform.lbTip.text = `以下域名通过代理连接( 点域名绑定上面选项,点击右键菜单可批量导入代理域名 ):` + } + else { + winform.currentEditPac = winform.editPacDirect; + winform.editPacProxy.hide = true; + winform.editPacDirect.hide = false; + winform.lbTip.text = `以下域名不使用代理( 点域名绑定上面选项,点击右键菜单可批量导入直连域名 ): ` + } +} +tbs.selIndex = 1; + +import win.dlg.message; +win.dlg.message.install(); + +winform.loadPacToEdit = function(str,fromUpdater){ + var rules = string.match(str,"var\s+rules\s*=\s*(%\[\])") + if(!rules) return winform.msgErr("PAC文件格式错误"); + + rules = web.json.parse(rules); + if(!(rules && table.isArray(rules) && type(rules[1][1])==type.table)) return winform.msgErr("PAC文件格式错误"); + + var proxy,direct = table.array(),table.array() + for(i=1;#rules){ + table.append(direct,rules[i][1]); + table.append(proxy,rules[i][2]); + } + + if(fromUpdater && !..table.find(proxy,"91.108.56.0/22") ){ + // https://ipinfo.io/AS44907 https://ipinfo.io/AS59930 https://ipinfo.io/AS62041 + table.push(proxy, + "149.154.160.0/22", + "149.154.164.0/22", + "149.154.172.0/22", + "91.108.4.0/22", + "91.108.20.0/22", + "91.108.56.0/22", + "91.108.8.0/22", + "95.161.64.0/20", + "91.108.12.0/22" + ) + } + + winform.editPacProxy.text = web.json.stringify(proxy,true) + winform.editPacDirect.text = web.json.stringify(direct,true) +} + + +winform.btnUpdate.oncommand = function(id,event){ + winform.btnUpdate.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'}; + + thread.invoke( + function(winform){ + import web.rest.github; + var result = web.rest.github.getContent("petronny","gfwlist2pac","gfwlist.pac"); + if( result ){ + var jsTestHost = /*** +function testHost(host, index) { + if( /^\d+\.\d+\.\d+\.\d+$/.test(host) && ( typeof isInNetEx !== "undefined" ) ){ + 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) || ( lastRule.indexOf("/") && isInNetEx(host, lastRule) ) ){ + return i % 2 == 0 ? 'DIRECT' : proxy; + } + } + } + return; + } + + 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 = ''; +} +***/ + var result = string.replace(result,"function\s*testHost\s*%\(\)\s*%\{\}",jsTestHost); + + winform.loadPacToEdit( result,true ); + winform.editPacDirect.modified = true; + winform.btnSave.disabled = false; + winform.btnReset.disabled = false; + winform.msgOk("PAC 已同步到最新版本,请点击「保存 PAC」按钮"); + } + else { + winform.msgFrown("PAC 更新失败,建议开启全局代理后重试。") + } + winform.btnUpdate.disabledText = null; + },winform + ) +} + +import sysProxy; +import string.conv; +import v2ray.pacServer; +winform.savePacToFile = function(){ + var proxy = web.json.tryParse(string.conv.fromWide(winform.editPacProxy.text)) + var direct = web.json.tryParse(string.conv.fromWide(winform.editPacDirect.text)) + if(!(table.isArray(proxy))) { + winform.btnSave.disabledText = null; + return winform.msgErr("代理域名配置格式错误"); + } + if(!(table.isArray(direct))) { + winform.btnSave.disabledText = null; + return winform.msgErr("直连域名配置格式错误"); + } + + v2ray.pacServer.savePacText(web.json.stringify({{direct;proxy}},true)); + + winform.editPacDirect.modified = false; + winform.editPacProxy.modified = false; + sysProxy.reset(true); + + winform.msgOk("已保存 PAC 文件",1200); + winform.btnSave.disabledText = null; + winform.btnSave.disabled = true; + winform.btnReset.disabled = true; +} + +winform.btnSave.oncommand = function(id,event){ + winform.btnSave.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'}; + + thread.invoke( + function(winform){ + sleep(300) + winform.savePacToFile(); + + },winform + ) +} + +winform.btnReset.oncommand = function(id,event){ + winform.btnReset.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'}; + + thread.invoke( + function(winform){ + import v2ray.pacServer; + winform.loadPacToEdit(v2ray.pacServer.loadPacText()); + + winform.btnReset.disabledText = null; + winform.btnSave.disabled = true; + winform.btnReset.disabled = true; + winform.msgOk("已恢复到当前 PAC 配置") + },winform + ) +} + +import v2ray.pacServer; +winform.loadPacToEdit( v2ray.pacServer.loadPacText() ); + +winform.editPacProxy.modified = false; +winform.editPacDirect.modified = false; +winform.btnSave.disabled = true; +winform.btnReset.disabled = true; + +winform.editPacDirect.limit = -1; +winform.editPacDirect.onChange = function(){ + winform.btnSave.disabled = false; + winform.btnReset.disabled = false; +} + +winform.editPacProxy.limit = -1; +winform.editPacProxy.onChange = function(){ + winform.btnSave.disabled = false; + winform.btnReset.disabled = false; +} + +import process; +winform.lbTip.oncommand = function(id,event){ + process.openUrl("https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_(PAC)_file") +} + +winform.editPacDirect.wndproc = function(hwnd,message,wParam,lParam){ + if(message == 0x202/*_WM_LBUTTONUP*/){ + var lineIndex = winform.editPacDirect.lineFromChar(); + if(lineIndex == winform.editPacDirect.preLineIndex){ + return; + } + winform.editPacDirect.preLineIndex = lineIndex; + + var line = winform.editPacDirect.lineText(); + var domain = string.match(line,`\"(.+)\"`); + + if(domain){ + winform.editPacDomain.text = domain; + winform.radioDirect.checked = true; + } + } +} + +winform.editPacProxy.wndproc = function(hwnd,message,wParam,lParam){ + if(message == 0x202/*_WM_LBUTTONUP*/){ + var lineIndex = winform.editPacProxy.lineFromChar(); + if(lineIndex == winform.editPacProxy.preLineIndex){ + return; + } + winform.editPacProxy.preLineIndex = lineIndex; + + var line = winform.editPacProxy.lineText(); + var domain = string.match(line,`\"(.+)\"`); + + if(domain){ + winform.editPacDomain.text = domain; + winform.radioProxy.checked = true; + } + } +} + +import win.dlg.findReplace; +var findDlgDirect = win.dlg.findReplace(winform); + +findDlgDirect.onSearch = function(findWhat,down,matchCase,wholeWord){ + winform.currentEditPac.findText(findWhat,findDlgDirect.flags); +} + +findDlgDirect.onReplace = function(findWhat,replaceWith,down,matchCase,wholeWord){ + winform.currentEditPac.replaceText(findWhat,replaceWith,findDlgDirect.flags); +} + +findDlgDirect.onReplaceAll = function(findWhat,replaceWith,down,matchCase,wholeWord){ + winform.currentEditPac.replaceAll(findWhat,replaceWith,findDlgDirect.flags) +} + +winform.editPacDirect.enablePopMenu(function(){ + var items = { + { "查找 Ctrl + F"; + function(id){ + findDlgDirect.find(winform.editPacDirect.selText) + } + }; + { "替换 Ctrl + H"; + function(id){ + findDlgDirect.replace(winform.editPacDirect.selText); + } + }; + {}; + { "自剪贴板导入直连域名或 CIDR 格式 IP 段"; + function(id){ + var proxy = web.json.tryParse(string.conv.fromWide(winform.editPacProxy.text)) + var direct = web.json.tryParse(string.conv.fromWide(winform.editPacDirect.text)) + if(!(proxy)) return winform.msgErr("代理域名配置格式错误"); + if(!(direct)) return winform.msgErr("直连域名配置格式错误"); + + import win.clip; + var str = win.clip.read(); + if(!str){ + return winform.msgWarn("请先复制域名或CIDR格式IP段到剪贴板(支持任意空白分隔符)"); + } + + var count,ignored = 0,0; + for domain in string.gmatch(str,"\w<[\w-_]*\.>+\w{1,8}") { + + if(!table.indexOf(proxy,domain) && table.indexOf(direct,domain) ){ + ignored++; + continue; + } + + proxy = table.filter(proxy,lambda(v) v!=domain); + if(!table.indexOf(direct,domain)){ + table.unshift(direct,domain) + } + count++; + } + + //CIDR IP + for cidrIp in string.gmatch(str,"\d+\.\d+\.\d+\.\d+<\/\d+>*") { + + if(!table.indexOf(direct,cidrIp) && table.indexOf(proxy,cidrIp) ){ + ignored++; + continue; + } + + direct = table.filter(direct,lambda(v) v!=cidrIp); + if(!table.indexOf(proxy,cidrIp)){ + table.unshift(proxy,cidrIp) + } + count++; + } + + winform.editPacProxy.text = web.json.stringify(proxy,true) + winform.editPacDirect.text = web.json.stringify(direct,true) + winform.editPacProxy.modified = true; + winform.editPacDirect.modified = true; + winform.msgInfo('已成功导入 '+count+' 个直连域名或 IP 段,\r\n' + + ignored + '个域名已经是直连域名无需添加。\r\n下一步请点下面的「保存PAC」按钮。',1500); + } + }; + { "重置为默认 PAC"; + function(id){ + import v2ray.pacServer; + v2ray.pacServer.resetPac(); + winform.loadPacToEdit(v2ray.pacServer.loadPacText()); + } + }; + { "恢复为当前使用的 PAC"; + function(id){ + import v2ray.pacServer; + winform.loadPacToEdit(v2ray.pacServer.loadPacText()); + } + }; + } + return items; +}); + +winform.editPacProxy.enablePopMenu(function(){ + var items = { + { "查找 Ctrl + F"; + function(id){ + findDlgDirect.find(winform.editPacProxy.selText) + } + }; + { "替换 Ctrl + H"; + function(id){ + findDlgDirect.replace(winform.editPacProxy.selText); + } + }; + {}; + { "自剪贴板导入代理域名或 CIDR 格式 IP 段"; + function(id){ + var proxy = web.json.tryParse(string.conv.fromWide(winform.editPacProxy.text)) + var direct = web.json.tryParse(string.conv.fromWide(winform.editPacDirect.text)) + if(!(proxy)) return winform.msgErr("代理域名配置格式错误"); + if(!(direct)) return winform.msgErr("直连域名配置格式错误"); + + import win.clip; + var str = win.clip.read(); + if(!str){ + return winform.msgWarn("请先复制域名或 CIDR 格式 IP 段到剪贴板(支持任意空白分隔符)"); + } + + var count,ignored = 0,0; + for domain in string.gmatch(str,"\w<[\w-_]*\.>+\w{1,8}") { + + if(!table.indexOf(direct,domain) && table.indexOf(proxy,domain) ){ + ignored++; + continue; + } + + direct = table.filter(direct,lambda(v) v!=domain); + if(!table.indexOf(proxy,domain)){ + table.unshift(proxy,domain) + } + count++; + } + + //CIDR IP + for cidrIp in string.gmatch(str,"\d+\.\d+\.\d+\.\d+<\/\d+>*") { + + if(!table.indexOf(direct,cidrIp) && table.indexOf(proxy,cidrIp) ){ + ignored++; + continue; + } + + direct = table.filter(direct,lambda(v) v!=cidrIp); + if(!table.indexOf(proxy,cidrIp)){ + table.unshift(proxy,cidrIp) + } + count++; + } + + + winform.editPacProxy.text = web.json.stringify(proxy,true) + winform.editPacDirect.text = web.json.stringify(direct,true) + winform.editPacProxy.modified = true; + winform.editPacDirect.modified = true; + winform.msgInfo('已成功导入 '+count+' 个代理域名或 IP 段,\r\n' + + ignored + '个域名已经是代理域名无需添加。\r\n下一步请点下面的「保存PAC」按钮。',1500); + } + }; + + { "导入所有 Telegram IP"; + function(id){ + var proxy = web.json.tryParse(string.conv.fromWide(winform.editPacProxy.text)) + if(!(proxy)) return winform.msgErr("代理域名配置格式错误"); + + if( !..table.find(proxy,"91.108.56.0/22") ){ + // https://ipinfo.io/AS44907 https://ipinfo.io/AS59930 https://ipinfo.io/AS62041 + table.push(proxy, + "149.154.160.0/22", + "149.154.164.0/22", + "149.154.172.0/22", + "91.108.4.0/22", + "91.108.20.0/22", + "91.108.56.0/22", + "91.108.8.0/22", + "95.161.64.0/20", + "91.108.12.0/22" + ) + + winform.editPacProxy.text = web.json.stringify(proxy,true) + winform.msgOk('已成功导入所有 Telegram IP\r\n下一步请点下面的「保存PAC」按钮。') + } + else { + winform.msgWarn("代理 IP 段已包含所有 Telegram IP,不需要重复导入!") + } + + } + }; + { /*分隔符*/ }; + { "重置为默认 PAC"; + function(id){ + import v2ray.pacServer; + v2ray.pacServer.resetPac(); + winform.loadPacToEdit(v2ray.pacServer.loadPacText()); + } + }; + { "恢复为当前使用的 PAC"; + function(id){ + import v2ray.pacServer; + winform.loadPacToEdit(v2ray.pacServer.loadPacText()); + } + }; + } + return items; +}); + + +import win.ui.accelerator; +var accelerator = win.ui.accelerator({ + + { + ctrl = true; vkey = 'F'#; + oncommand = function() findDlgDirect.find(winform.currentEditPac.selText); + }; + + { + ctrl = true; vkey = 'H'#; + oncommand = function() findDlgDirect.replace(winform.currentEditPac.selText); + }; + +},winform ); + +winform.btnDeleteDomain.oncommand = function(id,event){ + var domain = winform.editPacDomain.text; + if(!#domain){ + return winform.editPacDomain.editBox.showErrorTip(,"请先指定域名") + } + + var proxy = web.json.tryParse(string.conv.fromWide(winform.editPacProxy.text)) + var direct = web.json.tryParse(string.conv.fromWide(winform.editPacDirect.text)) + if(!(table.isArray(proxy))) return winform.msgErr("代理域名配置格式错误:不是有效的 JSON 数组。"); + if(!(table.isArray(direct))) return winform.msgErr("直连域名配置格式错误:不是有效的 JSON 数组"); + + if(!table.indexOf(proxy,domain) && !table.indexOf(direct,domain) ){ + winform.editPacDomain.editBox.showInfoTip(,"PAC 配置不包含此域名") + return; + } + + direct = table.filter(direct,lambda(v) v!=domain); + proxy = table.filter(proxy,lambda(v) v!=domain); + + winform.editPacProxy.text = web.json.stringify(proxy,true); + winform.editPacDirect.text = web.json.stringify(direct,true); + winform.editPacProxy.modified = true; + winform.editPacDirect.modified = true; + winform.btnUpdate.disabled = false; + winform.editPacDomain.editBox.showInfoTip(,"已移除此域名"); +} + +winform.btnAddDomain.oncommand = function(id,event){ + var proxy = web.json.tryParse(string.conv.fromWide(winform.editPacProxy.text)) + var direct = web.json.tryParse(string.conv.fromWide(winform.editPacDirect.text)) + if(!(table.isArray(proxy))) return winform.msgErr("代理域名配置格式错误:不是有效的JSON数组。"); + if(!(table.isArray(direct))) return winform.msgErr("直连域名配置格式错误:不是有效的JSON数组"); + + var domain = winform.editPacDomain.text; + if(!#domain){ + return winform.editPacDomain.editBox.showErrorTip(,"请先指定域名") + } + + if(winform.radioProxy.checked){ + if(!table.indexOf(direct,domain) && table.indexOf(proxy,domain) ){ + winform.editPacDomain.editBox.showWarningTip(,"此域名已经是代理域名,无需添加") + return; + } + + direct = table.filter(direct,lambda(v) v!=domain); + if(!table.indexOf(proxy,domain)){ + table.unshift(proxy,domain) + } + winform.editPacDomain.editBox.showInfoTip(,"已添加到代理域名"); + } + else { + if(table.indexOf(direct,domain) && !table.indexOf(proxy,domain) ){ + winform.editPacDomain.editBox.showWarningTip(,"此域名已经是直连域名,无需添加") + return; + } + + proxy = table.filter(proxy,lambda(v) v!=domain); + if(!table.indexOf(direct,domain)){ + table.unshift(direct,domain) + } + winform.editPacDomain.editBox.showInfoTip(,"已添加到直连域名"); + } + + winform.editPacProxy.text = web.json.stringify(proxy,true) + winform.editPacDirect.text = web.json.stringify(direct,true) + winform.editPacProxy.modified = true; + winform.editPacDirect.modified = true; + winform.btnUpdate.disabled = false; +} + +winform.onClose = function(hwnd,message,wParam,lParam){ + if(winform.editPacDirect.modified||winform.editPacProxy.modified){ + winform.btnUpdate.disabled = true; + + if(!winform.msgAsk("PAC 配置已修改但尚未保存,确定要退出并放弃更改吗?")){ + return true; + } + } +} + +winform.onDestroy = function(){ + if(mainForm){ + win.setActive(mainForm.hwnd); + win.setForeground(mainForm.hwnd); + } +} + +import win.clip; +winform.onActivate = function(state,hwndOther,minimized){ + if(state){ + if(#winform.editPacDomain.text){ + return; + } + + var str = win.clip.read(); + if(str){ + var domain = string.match(str,"\w<[\w-_]*\.>+\w{1,8}"); + if(domain){ + winform.editPacDomain.text = domain; + + var proxy = web.json.tryParse(string.conv.fromWide(winform.editPacProxy.text)) + if( (proxy)) { + winform.radioProxy.checked = table.indexOf(proxy,domain); + winform.radioDirect.checked = !winform.radioProxy.checked; + } + } + } + } +} + +import inet.url; +winform.editPacDomain.editBox.onChange = function(){ + var url = owner.text; + if(string.startWith(url,"http:",true) || string.startWith(url,"https:",true) ){ + var tUrl = inet.url.split(url); + if(tUrl && #tUrl.host){ + owner.text = tUrl.host; + owner.setFocus(); + } + } +} + +winform.enableDpiScaling(); +winform.show(); +win.loopMessage(); + +return winform; \ No newline at end of file diff --git a/forms/main/tools/github.aardio b/forms/main/tools/github.aardio new file mode 100644 index 0000000..eb7b218 --- /dev/null +++ b/forms/main/tools/github.aardio @@ -0,0 +1,241 @@ +//RUNAS//github优化 +import fonts.fontAwesome; +import win.ui; +/*DSG{{*/ +var winform = win.form(text="github.com 网速优化工具";right=655;bottom=281;bgcolor=16777215;border="none";max=false) +winform.add( +bk={cls="bk";left=0;top=0;right=659;bottom=34;bgcolor=12632256;z=8}; +cmbIpCidrs={cls="combobox";left=49;top=111;right=328;bottom=137;edge=1;items={};mode="dropdown";z=1}; +editIpCurrent={cls="edit";left=118;top=206;right=366;bottom=230;edge=1;z=5}; +plusExploreHosts={cls="plus";text='\uF07C 编辑hosts文件';left=450;top=204;right=607;bottom=235;bgcolor=-6371181;font=LOGFONT(h=-15;name='FontAwesome';charset=0);notify=1;z=7}; +plusUpdateDns={cls="plus";text='\uF0AD 更改github.com解析到选定IP / 并更新图像等服务器IP';left=77;top=158;right=563;bottom=189;bgcolor=-6371181;font=LOGFONT(h=-15;name='FontAwesome';charset=0);notify=1;z=3}; +plusUpdateIps={cls="plus";text='\uF021 获取最新IP列表 / 测速';left=345;top=108;right=607;bottom=139;bgcolor=-6371181;font=LOGFONT(h=-15;name='FontAwesome';charset=0);notify=1;z=2}; +static={cls="static";text="本工具优化无代理时直连 Github 官网访问当前速度最快的服务器, +可解决无法下载更新 V2Ray Core / SSR Core ,无法显示 Github 上的图像等问题。";left=49;top=45;right=635;bottom=93;font=LOGFONT(h=-13);transparent=1;z=4}; +static2={cls="static";text="当前指向IP:";left=27;top=208;right=111;bottom=228;align="right";transparent=1;z=6} +) +/*}}*/ + +winform.cmbIpCidrs.onListChange = function(){ + winform.setTimeout( + function(){ + var ip = string.match(winform.cmbIpCidrs.selText,"\d+\.\d+\.\d+\.\d+"); + if(!ip){ + return ; + } + winform.plusUpdateDns.text = "更改 github.com 域名解析到:" + ip + } + ); +} + +import wsock; +import fsys.config; +config = fsys.config( io.appData("/aardio/github-ip-tools/") ); +winform.plusUpdateIps.oncommand = function(id,event){ + winform.editIpCurrent.text = wsock.getIp("www.github.com") + + winform.plusUpdateIps.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} + winform.text = "请稍候,正在测试github.com所有可用IP的响应速度" + + var metaInfo = win.invoke( + function(){ + import win; + import web.rest.jsonClient; + var http = web.rest.jsonClient(); + var github = http.api("https://api.github.com/") + + return github.meta.get() : { git = { + "192.30.252.0"; + "185.199.108.0"; + "140.82.112.0"; + "13.114.40.48"; + "13.229.188.59"; + "13.234.176.102"; + "13.234.210.38"; + "13.236.229.21"; + "13.237.44.5"; + "13.250.177.223"; + "15.164.81.167"; + "18.194.104.89"; + "18.195.85.27"; + "35.159.8.160"; + "52.192.72.89"; + "52.64.108.95"; + "52.69.186.44"; + "52.74.223.119"; + "52.78.231.108" + } }; + } + ) + + if(metaInfo[["git"]]){ + config.meta.data = table.map(metaInfo.git,lambda(v)..string.match(v,"^\d+\.\d+\.\d+\.\d+")) + } + elseif(!config.meta.data){ + winform.msgboxErr("您的操作系统版本过低") + } + + var pingThread = function( ip ) { + import wsock.tcp.client; + + var result = 0; + for(i=1;4;1){ + + var beginTick = ..time.tick() + var tcp = wsock.tcp.client() + + tcp.setTimeouts(1000,1000); + if( ! tcp.connectTimeout(ip,80,2) ){ + return; + }; + + sendData =/*********** +GET / HTTP/1.1 +Host: www.github.com +Connection: close +User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) +Accept: */*; +Accept-Language: zh-CN,zh; +Accept-Charset:utf-8; +***********/ + tcp.write( sendData + '\r\n\r\n' ) + + var rep = tcp.readAll(); + tcp.close(); + + if( rep && ..string.startWith(rep,"HTTP/1.1 301 Moved Permanently") ){ + result = result + ((..time.tick() - beginTick)/1000); + } + else { + return; + } + + } + + return ip,math.round(result/4,2); + + } + + import thread.manage; + manage = thread.manage(#config.meta.data) + + var ipData = {} + for(k,ip in config.meta.data){ + manage.createSuspended(pingThread,ip).onEnd = function(ip,sec){ + if(ip && sec!==null ) { + table.push(ipData,ip + " 响应速度:" + sec + "秒"); + winform.cmbIpCidrs.items = ipData; + winform.cmbIpCidrs.selIndex = 1; + } + } + } + + manage.resume(); + manage.waitClose(); + + winform.cmbIpCidrs.items = ipData; + winform.cmbIpCidrs.selIndex = 1; + winform.cmbIpCidrs.onListChange(); + + winform.text = "github.com 网速优化工具" + winform.plusUpdateIps.disabledText = null; +} + +import fsys.hosts; +winform.plusUpdateDns.oncommand = function(id,event){ + var ip = winform.cmbIpCidrs.text; + if(!#ip){ + winform.msgboxErr("请选选择IP地址") + return; + } + + ip = string.match(ip,"\d+\.\d+\.\d+\.\d+"); + if( ip == winform.editIpCurrent.text ) return winform.msgboxErr("域名之前已经解析到该IP地址") + + winform.plusUpdateDns.disabledText = "正在更新IP" + + var githubIps = { + ["www.github.com"] = ip; + ["github.com"] = ip; + } + + import web.rest.jsonLiteClient; + var http = web.rest.jsonLiteClient(); + var ipApi = http.api("http://ip-api.com/json"); + var data = ipApi["raw.githubusercontent.com"].get(); + if(data[["query"]]){ + githubIps["raw.github.com"] = data[["query"]]; + githubIps["assets-cdn.github.com"] = data[["query"]]; + githubIps["raw.githubusercontent.com"] = data[["query"]]; + githubIps["gist.githubusercontent.com"] = data[["query"]]; + githubIps["cloud.githubusercontent.com"] = data[["query"]]; + githubIps["camo.githubusercontent.com"] = data[["query"]]; + githubIps["avatars0.githubusercontent.com"] = data[["query"]]; + githubIps["avatars1.githubusercontent.com"] = data[["query"]]; + githubIps["avatars2.githubusercontent.com"] = data[["query"]]; + githubIps["avatars3.githubusercontent.com"] = data[["query"]]; + githubIps["avatars4.githubusercontent.com"] = data[["query"]]; + githubIps["avatars5.githubusercontent.com"] = data[["query"]]; + githubIps["avatars6.githubusercontent.com"] = data[["query"]]; + githubIps["avatars7.githubusercontent.com"] = data[["query"]]; + githubIps["avatars8.githubusercontent.com"] = data[["query"]]; + githubIps["marketplace-screenshots.githubusercontent.com"] = data[["query"]]; + githubIps["repository-images.githubusercontent.com"] = data[["query"]]; + githubIps["user-images.githubusercontent.com"] = data[["query"]]; + githubIps["desktop.githubusercontent.com"] = data[["query"]]; + } + + fsys.hosts.ownCacls(); + fsys.hosts.update(githubIps); + + win.delay(1000); + winform.editIpCurrent.text = wsock.getIp("www.github.com"); + winform.plusUpdateDns.disabledText = null; + + if( ip != winform.editIpCurrent.text ){ + winform.msgboxErr("修改hosts文件失败,如果hosts文件被其他软件锁定时请先解除锁定,也可以搜索网上教程试试设置文件权限") + } +} + +winform.plusExploreHosts.skin( + background = { + hover = "/res/images/btn-hover.png"; + focus = "/res/images/btn-focus.jpg"; + active = "/res/images/btn-active.png"; + disabled = "/res/images/btn-disabled.png"; + } +) +winform.plusExploreHosts.oncommand = function(id,event){ + import process; + process.execute("notepad.exe",fsys.hosts.path,"runas") +} + +winform.plusUpdateDns.skin({ + background={ + default=0xFF93C89E; + hover=0xFF928BB3 + } +}) + +winform.plusUpdateIps.skin({ + background={ + default=0xFF93C89E; + hover=0xFF928BB3 + } +}) + +winform.plusExploreHosts.skin({ + background={ + default=0xFF93C89E; + hover=0xFF928BB3 + } +}) + +import win.ui.simpleWindow2; +win.ui.simpleWindow2(winform); + +winform.enableDpiScaling(); +winform.show() +winform.plusUpdateIps.oncommand(); + +win.loopMessage(); diff --git a/forms/main/tools/qr.aardio b/forms/main/tools/qr.aardio new file mode 100644 index 0000000..82db4fd --- /dev/null +++ b/forms/main/tools/qr.aardio @@ -0,0 +1,71 @@ +import win.ui; +import win.ui.atom; +import fonts.fontAwesome; +/*DSG{{*/ +var winform = win.form(text="winXray - 二维码生成工具";right=730;bottom=678;bgcolor=16777215;border="none";exmode="none";mode="popup") +winform.add( +bk={cls="bk";left=-6;top=-2;right=734;bottom=27;bgcolor=12632256;z=10}; +btnQrEnode={cls="plus";text="生成二维码";left=562;top=565;right=694;bottom=595;align="left";bgcolor=14935259;db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=22}};iconText='\uF1C4';notify=1;textPadding={left=40};z=9}; +editUrl={cls="plus";left=44;top=569;right=537;bottom=594;align="right";bgcolor=16777215;border={bottom=1;color=-8355712};db=1;dl=1;dr=1;editable="edit";font=LOGFONT(h=-16);textPadding={bottom=1};z=8}; +lbErrLevel={cls="static";text=" 0:L 可纠错7%数据码字";left=104;top=656;right=272;bottom=679;db=1;dl=1;transparent=1;z=6}; +lbVersion={cls="static";text="自动选择版本";left=466;top=656;right=672;bottom=679;db=1;dr=1;transparent=1;z=7}; +plus={cls="plus";left=28;top=49;right=708;bottom=522;bgcolor=16777215;db=1;dl=1;dr=1;dt=1;repeat="scale";z=1}; +static={cls="static";text="纠错级别:";left=13;top=624;right=97;bottom=651;align="right";db=1;dl=1;transparent=1;z=3}; +static2={cls="static";text="版本(大小):";left=353;top=624;right=437;bottom=651;align="right";db=1;dl=1;dr=1;transparent=1;z=5}; +static3={cls="static";text="winXray - 二维码生成工具";left=17;top=4;right=230;bottom=24;color=3947580;transparent=1;z=11}; +tbErrLevel={cls="trackbar";left=96;top=611;right=290;bottom=641;bgcolor=16777215;db=1;dl=1;max=3;min=0;z=2}; +tbVersion={cls="trackbar";left=439;top=611;right=703;bottom=641;bgcolor=16777215;db=1;dr=1;max=40;min=0;z=4} +) +/*}}*/ + +import style; +winform.btnQrEnode.skin(style.primaryButton); + +winform.tbErrLevel.oncommand = function(id,event,pos){ + + if( event == 0x8/*_TB_ENDTRACK*/ ){ + pos = winform.tbErrLevel.pos; + var v = {[0]="L 可纠错7%数据码字";[1]="M 可纠错15%的数据码字";[2]="Q 可纠错25%的数据码字";[3]="H 可纠错30%的数据码字";} + winform.lbErrLevel.text = pos +":"+ v[pos]; + } +} + +winform.tbVersion.oncommand = function(id,event,pos){ + if( event == 0x8/*_TB_ENDTRACK*/ ){ + pos = winform.tbVersion.pos; + if(!pos)winform.lbVersion.text = "自动选择版本"; + else { + var width = ((pos-1)*4)+21; + winform.lbVersion.text = string.format("版本:%d 二维码数据大小:%d x %d",pos,width,width ); + } + } +} + +import win.dlg.message; +import qrencode.bitmap; +winform.btnQrEnode.oncommand = function(id,event){ + if(!#winform.editUrl.text){ + return winform.msgErr("请先输入内容") + } + + winform.plus.hide = true; + var qrBmp = qrencode.bitmap(winform.editUrl.text,winform.tbVersion.pos,winform.tbErrLevel.pos ); + if(!qrBmp){ + return winform.msgErr("请先输入内容") + } + winform.plus.setBackground(qrBmp.copyBitmap(winform.plus.width)); + + winform.plus.hide = false; + winform.plus.redraw() +} + +winform.createQrCode = function(url){ + winform.editUrl.text = url; + winform.btnQrEnode.oncommand(); +} + +import win.ui.simpleWindow2; +win.ui.simpleWindow2(winform); + +winform.show() +win.loopMessage(); diff --git a/forms/main/tools/tools.aardio b/forms/main/tools/tools.aardio new file mode 100644 index 0000000..e606548 --- /dev/null +++ b/forms/main/tools/tools.aardio @@ -0,0 +1,277 @@ +import fonts.fontAwesome; +import win.ui; +/*DSG{{*/ +var winform = win.form(text="aardio form";right=938;bottom=638;bgcolor=16777215) +winform.add( +btnAardio={cls="plus";text="aardio 桌面软件快速开发( 开发环境仅 6.5MB )";left=26;top=533;right=460;bottom=575;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-27;name='FontAwesome');padding={left=18}};iconText='\uF17A';notify=1;textPadding={left=50};z=3}; +btnCreateLnk={cls="plus";text="创建桌面图标";left=26;top=391;right=205;bottom=433;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-23;name='FontAwesome');padding={left=18}};iconText='\uF108';notify=1;textPadding={left=50};z=10}; +btnDeleteIconCache={cls="plus";text="修复桌面图标空白";left=26;top=439;right=269;bottom=481;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-23;name='FontAwesome');padding={left=18}};iconText='\uF0AD';notify=1;textPadding={left=50};z=16}; +btnDnsFlush={cls="plus";text="清空 DNS 缓存";left=26;top=155;right=412;bottom=197;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-27;name='FontAwesome');padding={left=18}};iconText='\uF021';notify=1;textPadding={left=50};z=5}; +btnGitHub={cls="plus";text="Github 网速优化";left=26;top=250;right=262;bottom=292;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-27;name='FontAwesome');padding={left=18}};iconText='\uF09B';notify=1;textPadding={left=50};z=2}; +btnQrCode={cls="plus";text="二维码生成工具";left=26;top=297;right=262;bottom=339;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-27;name='FontAwesome');padding={left=18}};iconText='\uF029';notify=1;textPadding={left=50};z=14}; +btnSshInstall={cls="plus";text="一键安装 V2Ray 服务端";left=393;top=14;right=601;bottom=56;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-27;name='FontAwesome');padding={left=11}};iconText='\uF17C';notify=1;textPadding={left=40};z=9}; +btnSshInstallKey={cls="plus";text="安装SSH密钥";left=606;top=15;right=755;bottom=57;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-24;name='FontAwesome');padding={left=11}};iconText='\uF084';notify=1;textPadding={left=40};z=11}; +btnTestSpeed={cls="plus";text="当前代理服务器测速";left=26;top=61;right=244;bottom=103;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-24;name='FontAwesome');padding={left=18}};iconText='\uF0ED';notify=1;textPadding={left=50};z=12}; +btnUpdateSystemTime={cls="plus";text="同步系统时间( 修正 V2Ray 连接报错 )";left=26;top=108;right=412;bottom=150;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-27;name='FontAwesome');padding={left=18}};iconText='\uF017';notify=1;textPadding={left=50};z=4}; +btnUuid={cls="plus";text="UUID 生成工具";left=26;top=344;right=262;bottom=386;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-27;name='FontAwesome');padding={left=18}};iconText='\uF13E';notify=1;textPadding={left=50};z=15}; +btnWubiLex={cls="plus";text="WIN10 五笔助手(仅830KB,自带五笔86、98、091、新世纪、郑码……)";left=26;top=486;right=661;bottom=528;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-24;name='FontAwesome');padding={left=18}};iconText='\uF11C';notify=1;textPadding={left=50};z=6}; +btnYoutube={cls="plus";text="Youtube 视频下载工具";left=26;top=203;right=262;bottom=245;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-27;name='FontAwesome');padding={left=18}};iconText='\uF167';notify=1;textPadding={left=50};z=1}; +editSshHost={cls="plus";left=158;top=23;right=386;bottom=47;align="left";bgcolor=16777215;border={bottom=1;color=-8355712};dl=1;dt=1;editable="edit";font=LOGFONT(h=-16);textPadding={bottom=1};z=7}; +lbCurrentProxyLocation={cls="static";left=245;top=74;right=729;bottom=101;color=32768;dl=1;dt=1;transparent=1;z=13}; +lbTip={cls="static";text="友情提醒:winXray 不会注册任何域名,谨防冒充官网的钓鱼网站!!!";left=227;top=603;right=918;bottom=630;align="right";color=5921370;db=1;dr=1;font=LOGFONT(h=-13);transparent=1;z=17}; +static={cls="static";text="账号@服务器:";left=36;top=27;right=151;bottom=54;align="right";color=4934475;dl=1;dt=1;font=LOGFONT(h=-13);transparent=1;z=8} +) +/*}}*/ + +import style; +winform.btnYoutube.skin(style.plainButton); + +var frmYoutube; +winform.btnYoutube.oncommand = function(id,event){ + if(frmYoutube&&win.isWindow(frmYoutube.hwnd)){ + if(win.isIconic(frmYoutube.hwnd)){ + frmYoutube.show(9/*_SW_RESTORE*/); + } + + frmYoutube.show(); + return; + } + + frmYoutube = winform.loadForm("\forms\main\tools\youtube.aardio"); + frmYoutube.show(); +} + +import process; +winform.btnGitHub.skin(style.plainButton) +winform.btnGitHub.oncommand = function(id,event){ + if(_STUDIO_INVOKED){ + winform.msgboxErr("请在发布后运行此功能"); + return; + } + + process.execute(io._exepath,"/github","runas"); +} + +winform.btnAardio.skin(style.plainButton) +winform.btnAardio.oncommand = function(id,event){ + process.openUrl("http://www.aardio.com") +} + +winform.btnUpdateSystemTime.skin(style.plainButton) +winform.btnUpdateSystemTime.oncommand = function(id,event){ + if(_STUDIO_INVOKED){ + winform.msgboxErr("请在发布后运行此功能"); + return; + } + + winform.btnUpdateSystemTime.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} + if( process.executeWait(io._exepath,"/updateTime","runas") ){ + winform.btnUpdateSystemTime.disabledText = null; + winform.btnUpdateSystemTime.text = '时间已同步' + winform.setTimeout( + function(){ + winform.btnUpdateSystemTime.text = '同步系统时间( 修正 v2ray 连接报错 )' + },2000) + } + else { + winform.btnUpdateSystemTime.disabledText = null; + } +} + +winform.btnDnsFlush.skin(style.plainButton) +winform.btnDnsFlush.oncommand = function(id,event){ + winform.btnDnsFlush.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} + + import process.popen; + var prcs = process.popen(,"ipconfig /flushdns"); + var str = prcs.read(-1) + + var dnsapi = ..raw.loadDll("dnsapi.dll"); + dnsapi.DnsFlushResolverCacheB(); + + winform.msgInfo(str); + winform.btnDnsFlush.disabledText = null; +} + +import process; +winform.btnWubiLex.skin(style.plainButton) +winform.btnWubiLex.oncommand = function(id,event){ + process.openUrl("http://wubi.aardio.com/"); +} + +winform.editSshHost.setCueBannerText("root@0.0.0.0:22") +winform.btnSshInstall.skin(style.plainButton) +winform.btnSshInstall.oncommand = function(id,event){ + + if(_STUDIO_INVOKED){ + winform.msgErr("请在发布后运行此功能"); + return; + } + + config.ui.sshServer = winform.editSshHost.text; + config.ui.save(); + + winform.btnSshInstall.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} + + var server = winform.editSshHost.text; + if( ! ..string.indexOf(server,"@") ){ + server = "root@" + server; + } + process.execute(io._exepath,"/sshInstall " + server); + win.delay(1000); + winform.btnSshInstall.disabledText = null; +} + +import config; +if(config.ui.sshServer){ + winform.editSshHost.text = config.ui.sshServer; +} + +winform.btnSshInstallKey.skin(style.plainButton) +winform.btnSshInstallKey.oncommand = function(id,event){ + if(_STUDIO_INVOKED){ + winform.msgErr("请在发布后运行此功能"); + return; + } + + config.ui.sshServer = winform.editSshHost.text; + config.ui.save(); + + winform.btnSshInstall.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} + + var server = winform.editSshHost.text; + if( ! ..string.indexOf(server,"@") ){ + server = "root@" + server; + } + process.execute(io._exepath,"/sshInstallKey " + server); + win.delay(1000); + winform.btnSshInstall.disabledText = null; +} + +winform.btnCreateLnk.skin(style.plainButton) +winform.btnCreateLnk.oncommand = function(id,event){ + if(_STUDIO_INVOKED){ + return winform.msgboxErr("请在发布后使用此功能") + } + + import fsys.lnk; + var lnk = fsys.lnk(); + lnk.description = "winXray(V2Ray/V2Ray、Shadowsocks、Trojan通用客户端 )" + + lnk.path = io._exepath //设置目标路径 + lnk.setIcon(io._exepath,0); //设置图标 + + lnk.save( + io.getSpecial(0/*_CSIDL_DESKTOP*/,"winXray.lnk" ) + ) + + ::Shell32.SHChangeNotify(0x8000000/*_SHCNE_ASSOCCHANGED*/,0,0,0); + + import com; + com.CreateObject("Shell.Application").MinimizeAll(); +} + +winform.btnTestSpeed.skin(style.plainButton) +winform.btnTestSpeed.oncommand = function(id,event){ + import chrome.path; + var chromePath = chrome.path(); + if(!chromePath){ + winform.msgFrown('抱歉,\r\n测速工具需要调用Chrome或兼容浏览器才能运行,\r\n但是当前系统未找到任何Chrome兼容浏览器!'); + return; + } + + import v2ray.core; + if(!v2ray.core.socksProxyPort){ + winform.msgFrown('抱歉,当前未连接到任何代理服务器!'); + return; + } + + winform.btnTestSpeed.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} + + var ipip = win.invoke( + function(port){ + import web.rest.client; + var restClient = web.rest.client(,"SOCKS=127.0.0.1:"+port); + restClient._http.setTimeouts(1000,2000,2000); + restClient.get("https://www.google.com/generate_204"); + var lastStatusCode = restClient.lastStatusCode; + + if( lastStatusCode == 204 ){ + + var ipip,err = restClient.get("http://myip.ipip.net"); + if(ipip){ + ipip = ..string.match(ipip,"\d+\.\d+\.\d+\.\d+\A+"); + if(ipip) { + restClient.close(); + return "当前代理服务器:"+ipip; + } + } + + restClient.close(); + return null; + } + restClient.close(); + },v2ray.core.socksProxyPort + ) + + if(!ipip){ + winform.msgFrown('抱歉,当前未连接到任何代理服务器!'); + winform.btnTestSpeed.disabledText = null; + return; + } + + winform.lbCurrentProxyLocation.text = ipip; + + import process + process.execute(chromePath,` --proxy-server="SOCKS5://127.0.0.1:`+v2ray.core.socksProxyPort + +`" --user-data-dir="` +io.appData("winXray/chrome-socks5")+ `" --app="https://speed.cloudflare.com/"`); + winform.btnTestSpeed.disabledText = null; +} + +onActiveOutbound = function(address){ + winform.btnTestSpeed.disabled = !address; + if(type.isString(address)){ + winform.lbCurrentProxyLocation.text = "当前活动的代理服务器:" + address; + } +} + +subscribe("activeOutbound",function(address){ + onActiveOutbound(address) +} ) +if(globalActiveOutbound){ + onActiveOutbound(globalActiveOutbound) +} + +winform.btnQrCode.skin(style.plainButton) +winform.btnQrCode.oncommand = function(id,event){ + + var frmChild = winform.loadForm("\forms\main\tools\qr.aardio"); + frmChild.show(); + +} + +winform.btnUuid.skin(style.plainButton) +winform.btnUuid.oncommand = function(id,event){ + var frmChild = winform.loadForm("\forms\main\tools\uuid.aardio"); + frmChild.show(); +} + +winform.btnDeleteIconCache.skin(style.plainButton) +winform.btnDeleteIconCache.oncommand = function(id,event){ + import fsys; + import process; + + var explorerPath = process.kill("explorer.exe") + if( explorerPath ) { + fsys.delete(io.appData("iconcache.db")); + process.execute(explorerPath); + + ::Shell32.SHChangeNotify(0x8000000/*_SHCNE_ASSOCCHANGED*/,0,0,0); + } +} + + + +winform.enableDpiScaling(); +winform.show(); +win.loopMessage(); \ No newline at end of file diff --git a/forms/main/tools/uuid.aardio b/forms/main/tools/uuid.aardio new file mode 100644 index 0000000..a59218a --- /dev/null +++ b/forms/main/tools/uuid.aardio @@ -0,0 +1,28 @@ +//GUID生成器 +import win.ui; +import win.ui.menu; +import win.guid; +import win.clip; +/*DSG{{*/ +var winform = win.form(text="UUID 生成器 - 已生成新的UUID";right=550;bottom=91;border="dialog frame";exmode="none";max=false;parent=...) +winform.add( +btnCpy={cls="button";text="复制到剪贴板";left=436;top=21;right=529;bottom=47;z=3}; +btnGenerant={cls="button";text="生成UUID";left=339;top=21;right=432;bottom=47;z=2}; +static={cls="static";text="UUID理论上能产生全球唯一的值";left=37;top=63;right=543;bottom=80;transparent=1;z=4}; +txtGuid={cls="edit";left=31;top=21;right=327;bottom=47;edge=1;multiline=1;z=1} +) +/*}}*/ + +winform.btnCpy.oncommand = function(id,event){ + win.clip.write(winform.txtGuid.text) +} + +winform.btnGenerant.oncommand = function(id,event){ + winform.txtGuid.text = string.lower( tostring(win.guid.create() )); +} +winform.btnGenerant.oncommand(); + +winform.enableDpiScaling(); +winform.show(true) +win.loopMessage(); +return winform; diff --git a/forms/main/tools/uwpExemption.aardio b/forms/main/tools/uwpExemption.aardio new file mode 100644 index 0000000..ffa60de --- /dev/null +++ b/forms/main/tools/uwpExemption.aardio @@ -0,0 +1,240 @@ +//RUNAS//UWP本机隔离 +import win.ui; +import win.ui.atom; +import win.ui.menu; +import fonts.fontAwesome; +/*DSG{{*/ +var winform = win.form(text="UWP 应用 - 本机网络隔离工具";right=1150;bottom=666;bgcolor=16777215) +winform.add( +btnAllowLocalhostLoopback={cls="plus";text='\uF13E 允许所有应用访问本机网络';left=562;top=625;right=818;bottom=661;bgcolor=14609886;db=1;dr=1;font=LOGFONT(h=-16;name='FontAwesome');notify=1;tabstop=1;z=5}; +btnDisableLocalhostLoopback={cls="plus";text='\uF023 禁止所有应用访问本机网络';left=825;top=625;right=1081;bottom=661;bgcolor=14147583;db=1;dr=1;font=LOGFONT(h=-16;name='FontAwesome');notify=1;tabstop=1;z=6}; +listview={cls="listview";left=8;top=41;right=1138;bottom=617;acceptfiles=1;asel=false;bgcolor=16777215;db=1;dl=1;dr=1;dt=1;edge=1;font=LOGFONT(name='SimSun');fullRow=1;gridLines=1;hide=1;vscroll=1;z=1}; +plusLoading={cls="plus";left=368;top=195;right=739;bottom=457;color=15780518;db=1;dl=1;dr=1;dt=1;font=LOGFONT(h=-96;name='FontAwesome');z=2}; +plusSearch={cls="plus";left=727;top=3;right=1136;bottom=33;align="right";autohscroll=false;autovscroll=false;border={bottom=1;color=-4144960};dr=1;dt=1;editable=1;font=LOGFONT(h=-13);hide=1;textPadding={top=10;bottom=3};valign="top";z=3}; +tip={cls="static";text="单击列标题可排序,双击列表项可复制,右键点列表项可弹出菜单,回车搜索或刷新";left=13;top=626;right=552;bottom=655;db=1;dl=1;dr=1;transparent=1;z=4} +) +/*}}*/ + +var atom,hwnd = winform.atom("winXray.762C7E32-3E75-42BE-8F4A-4B0E8AAC4EF0"); +if(!atom && hwnd){ + win.showForeground(hwnd); + win.quitMessage(); return; +} + +uiLanguage = { + displayName = "显示名称"; + packageName = "完整包名"; + localhost = "本机"; + enabled = "允许"; + disabled = "禁止"; + searchCueBannerText = "输入应用名(支持模式匹配)"; + exemptAll = '\uF13E 允许所有应用访问本机网络'; + exemptNone = '\uF023 禁止所有应用访问本机网络'; + allowLocalhostLoopback = "允许访问本机网络"; + disableLocalhostLoopback = "禁止访问本机网络"; + requiredWin10 = "本程序仅支持 WIN10"; + run = "启动应用"; + tip = "单击列标题可排序,双击列表项可复制,右键点列表项可弹出菜单,回车搜索或刷新"; + title = "UWP 应用 - 本机网络隔离工具"; +} + +import win.ui.grid; +var grid = win.ui.grid(winform.listview); + +var reloadItemData = function(){ + thread.invoke( + function(uiLanguage,winform,grid){ + winform.plusLoading.hide = false; + winform.plusSearch.hide = true; + winform.listview.hide = true; + winform.plusLoading.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} + + import sys.networkIsolation; + var exemptApps = sys.networkIsolation.getLoopbackState(); + var dataTable = sys.networkIsolation.getAppContainers(); + + var word = string.trim(winform.plusSearch.text); + if(#word){ + word = "@@" + word; + dataTable = table.filter(dataTable + ,lambda(v) string.find(v.displayName,word) || string.find(v.appContainerName,word)|| string.find(v.description,word) ) + + } + + for(k,app in dataTable){ + app.loopback = exemptApps[app.sid]?uiLanguage.enabled:uiLanguage.disabled; + } + + + dataTable.fields = {"displayName","appContainerName","loopback","sid"} + if(grid.sortCloumn){ + var name = dataTable.fields[grid.sortCloumn]; + if(name){ + if(!grid.sortDesc){ + table.sort(dataTable,function(b){ + return owner[name] < b[name] + }) + } + else { + table.sort(dataTable,function(b){ + return owner[name] > b[name] + }) + } + } + } + + grid.setTable( dataTable ) + sleep(300); + + winform.plusLoading.disabledText = null; + winform.plusLoading.hide = true; + winform.listview.hide = false; + winform.plusSearch.hide = false; + + winform.resize(); + + },uiLanguage,winform,grid + ) +} + +grid.onSortColumn = function(cloumn,desc){ + grid.sortDesc = desc; + grid.sortCloumn = cloumn ; + reloadItemData(); + return true; +} + +grid.onEditChanged = function(text,iItem,iSubItem){ + return false; //禁止编辑 +} + +winform.adjust = function( cx,cy,wParam ) { + winform.listview.fillParent(); +}; + +import win.debounce; +winform.plusSearch.editBox.onChange = win.debounce(function(){ + if(#winform.plusSearch.text) reloadItemData(); +}) + +import sys.networkIsolation +var exemptUwpApp = function(exempted){ + var sidConfigs = {}; + for item,sid in winform.listview.eachSelected(4){ + sidConfigs[sid] = exempted; + } + sys.networkIsolation.enableLoopback(sidConfigs); + + var exemptApps = sys.networkIsolation.getLoopbackState(); + for item,sid in winform.listview.eachSelected(4){ + winform.listview.setItemText( exemptApps[sid]?uiLanguage.enabled:uiLanguage.disabled,item,3); + } +} + +import com.shell; +winform.listview.onnotify = function(id,code,ptr){ + + select(code) { + case 0xFFFFFFFB/*_NM_RCLICK*/ { + + var x,y = win.getCursorPos(); + winform.popmenu = win.ui.popmenu(winform); + + if(1===#winform.listview.selected){ + var item,path = winform.listview.getSelection(,2); + winform.popmenu.add(uiLanguage.run,function(id){ + import com.shell; + com.shell.activateApp(path+"!App"); + }); + } + + winform.popmenu.add(uiLanguage.allowLocalhostLoopback,function(id){ + exemptUwpApp(true); + }); + + winform.popmenu.add(uiLanguage.disableLocalhostLoopback,function(id){ + exemptUwpApp(false); + }); + + winform.popmenu.popup(x,y,true); + } + } +} + +winform.btnAllowLocalhostLoopback.skin({ + background={ + default=0x669BCC9B; + hover=0xFF928BB3; + disabled=0xFFCCCCCC; + } +}) +winform.btnAllowLocalhostLoopback.oncommand = function(id,event){ + var sidConfigs = {}; + for item,sid in winform.listview.each(0,0,4){ + sidConfigs[sid] = true; + } + sys.networkIsolation.enableLoopback(sidConfigs); + reloadItemData(); +} + +winform.btnDisableLocalhostLoopback.skin({ + background={ + default=0x66FFA07D; + hover=0xFF928BB3; + disabled=0xFFCCCCCC; + } +}) +winform.btnDisableLocalhostLoopback.oncommand = function(id,event){ + var sidConfigs = {}; + for item,sid in winform.listview.each(0,0,4){ + sidConfigs[sid] = false; + } + sys.networkIsolation.enableLoopback(sidConfigs); + reloadItemData(); +} + +winform.onOk = function(){ + winform.plusSearch.setFocus() +} + +winform.plusSearch.setCueBannerText(uiLanguage.searchCueBannerText); +winform.listview.setExtended(0x10000/*_LVS_EX_DOUBLEBUFFER*/); + +var setUiLanguage = function(lang){ + uiLanguage = lang; + winform.text = uiLanguage.title; + winform.btnAllowLocalhostLoopback.text = uiLanguage.exemptAll; + winform.btnDisableLocalhostLoopback.text = uiLanguage.exemptNone; + winform.tip.text = uiLanguage.tip; + + winform.listview.clear(true); + winform.listview.insertColumn(uiLanguage.displayName,300) + winform.listview.insertColumn(uiLanguage.packageName,300) + winform.listview.insertColumn(uiLanguage.localhost,80) + winform.listview.insertColumn("SID",-2) + winform.plusSearch.setCueBannerText(uiLanguage.searchCueBannerText) +} + +var lcid = ::Kernel32.GetUserDefaultLCID() +if( lcid==1028 || lcid == 3076 || lcid == 5124 ){ + import string.conv; + setUiLanguage(table.map(uiLanguage,lambda(v) string.conv.traditionalized(v)) ) +} +else { + setUiLanguage(uiLanguage); +} + +reloadItemData(); + +winform.plusSearch.editBox.onOk = function(){ + reloadItemData(); + return true; +} + +winform.show(); +import win.dlg.message; +if(!_WIN10_LATER){ + winform.msgWarn(uiLanguage.requiredWin10) +} + +win.loopMessage(); \ No newline at end of file diff --git a/forms/main/tools/youtube.aardio b/forms/main/tools/youtube.aardio new file mode 100644 index 0000000..3fe7587 --- /dev/null +++ b/forms/main/tools/youtube.aardio @@ -0,0 +1,95 @@ +import fonts.fontAwesome; +import win.ui; +import win.ui.atom; +/*DSG{{*/ +var winform = win.form(text="youtube 视频下载工具(点击视频链接即可下载)";right=759;bottom=469) +winform.add( +btnVideoInfo={cls="button";text="获取视频下载地址";left=511;top=27;right=732;bottom=60;dr=1;dt=1;font=LOGFONT(h=-16;name='FontAwesome');z=3}; +editInfo={cls="richedit";left=29;top=83;right=735;bottom=445;autohscroll=false;db=1;dl=1;dr=1;dt=1;edge=1;link=1;multiline=1;vscroll=1;z=1}; +editVideoUrl={cls="edit";text="https://www.youtube.com/watch?v=ZFA5Rax0ypU";left=27;top=29;right=499;bottom=58;dl=1;dr=1;dt=1;edge=1;multiline=1;z=2} +) +/*}}*/ + +winform.btnVideoInfo.oncommand = function(id,event){ + var url = winform.editVideoUrl.text; + var vid = string.match(url,"v=([\w\-]+)"); + if(!vid){ + return winform.editVideoUrl.showErrorTip(,"请输入正确的视频地址"); + } + + winform.btnVideoInfo.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} + thread.invoke( + function(winform,vid){ + import web.rest.jsonLiteClient; + var http = web.rest.jsonLiteClient(); + + var videoApi = http.api("https://www.youtube.com/get_video_info?video_id={video_id}"); + var info = videoApi[vid].get(); + + if(!info){ + winform.editInfo.text = "网络错误"; + winform.btnVideoInfo.disabledText = null; + } + + winform.editInfo.text = ""; + winform.editInfo.print( "视频作者:",info.player_response.videoDetails.author); + winform.editInfo.print( "视频标题:",info.player_response.videoDetails.title); + winform.editInfo.print( "视频说明:",info.player_response.videoDetails.shortDescription); + winform.videoTitle = info.player_response.videoDetails.title; + + for(i,v in info.player_response.streamingData.adaptiveFormats){ + if(!string.indexOf(v.mimeType,"audio/mp4")){ + continue; + } + + winform.editInfo.print(); + winform.editInfo.print("音频质量:",v.quality); + winform.editInfo.print("音频地址:",v.url); + } + + for(i,v in info.player_response.streamingData.formats){ + if(!string.indexOf(v.mimeType,"video/mp4")){ + continue; + } + + winform.editInfo.print(); + winform.editInfo.print("视频质量:",v.qualityLabel); + winform.editInfo.print("视频地址(含音频):",v.url); + } + + + var captionTracks = info.player_response.captions[["playerCaptionsTracklistRenderer"]][["captionTracks"]]; + if(info.captions[["playerCaptionsTracklistRenderer"]][["captionTracks"]]){ + if(#captionTracks){ + for(k,v in captionTracks){ + if(v.languageCode=="en"){ + var str = http.get(v.baseUrl) + winform.editInfo.print(str); + break + } + } + + } + } + + winform.editInfo.setFocus(); + winform.btnVideoInfo.disabledText = null; + },winform,vid + ) +} + +import fsys.dlg; +import inet.downBox; +winform.editInfo.onlink=function(message,href){ + if( message = 0x202/*_WM_LBUTTONUP*/ ) { + var path = fsys.dlg.open("*.mp4|*.mp4","请选择下载路径",,winform,,fsys.path.validName(winform.videoTitle)) + if(!path) return; + + var downBox = inet.downBox(winform,"下载视频"); + downBox.download(href,path); + } +} + +winform.enableDpiScaling(); +winform.show(); +win.loopMessage(); \ No newline at end of file diff --git a/forms/main/v2ray.aardio b/forms/main/v2ray.aardio new file mode 100644 index 0000000..5548495 --- /dev/null +++ b/forms/main/v2ray.aardio @@ -0,0 +1,1058 @@ +import win.ui; +import fonts.fontAwesome; +/*DSG{{*/ +var frmXray = win.form(text="winXray ";right=959;bottom=591;bgcolor=16777215) +frmXray.add( +btnEditPacOrUwp={cls="plus";text="编辑PAC";left=328;top=367;right=447;bottom=397;align="left";db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=12}};iconText='\uF1C4';notify=1;textPadding={left=30};z=7}; +btnImportServerFromClipBd={cls="plus";text="批量导入链接";left=459;top=367;right=592;bottom=397;align="left";db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=12}};iconText='\uF196 ';notify=1;textPadding={left=30};z=8}; +btnTcping={cls="plus";text="检测并连接最快服务器";left=735;top=366;right=941;bottom=398;align="left";bgcolor=11580047;border={radius=4};db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=18}};iconText='\uF012';notify=1;textPadding={left=42};z=3}; +chkAutoTest={cls="plus";text="异常自动重连 ";left=598;top=367;right=729;bottom=397;align="left";db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=12}};iconText='\uF0C8';notify=1;textPadding={left=30};z=9}; +edit={cls="edit";left=6;top=405;right=953;bottom=585;bgcolor=0;color=16777215;db=1;dl=1;dr=1;edge=1;hscroll=1;multiline=1;vscroll=1;z=2}; +listview={cls="listview";left=4;top=5;right=954;bottom=358;db=1;dl=1;dr=1;dt=1;edge=1;fullRow=1;gridLines=1;z=1}; +radioProxy={cls="radiobutton";text="全局代理";left=129;top=369;right=226;bottom=395;bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-13);z=4}; +radioProxyDirect={cls="radiobutton";text="不使用代理";left=14;top=369;right=120;bottom=395;bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-13);z=6}; +radioProxyPac={cls="radiobutton";text="PAC代理";left=234;top=369;right=321;bottom=395;bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-13);z=5} +) +/*}}*/ + +frmXray.listview.insertColumn("类型",100) +frmXray.listview.insertColumn("服务器",160) +frmXray.listview.insertColumn("端口",70) +frmXray.listview.insertColumn("加密",90) +frmXray.listview.insertColumn("协议",50) +frmXray.listview.insertColumn("备注",190) +frmXray.listview.insertColumn("响应速度",95) +frmXray.listview.insertColumn("状态",-1) +frmXray.listview.setExtended(0x10000/*_LVS_EX_DOUBLEBUFFER*/); + +frmXray.show(); + +import config; +import v2ray.core; +var currentOutboundIndex,currentOutboundAddress; +var activeOutbound = function(outboundIndex,outboundAddress,enableRetry,timerTesting){ + + if(!outboundIndex && !outboundAddress){ + outboundIndex,outboundAddress = currentOutboundIndex,currentOutboundAddress; + if(!outboundIndex && !outboundAddress) { + return; + } + } + + var outbound = config.proxy.outbounds[outboundIndex]; + if(!outbound){ + return ; + } + + + var startTesting = timerTesting; + if(!startTesting){ + ..publish("activeOutbound",false); + + var started,err = v2ray.core.restart(frmXray.edit,outbound); + startTesting = started; + if(!started){ + frmXray.edit.print("启动 V2Ray 错误",err:""); + frmXray.btnTcping.disabledText = null; + return false; + } + } + + if( startTesting ){ + currentOutboundIndex,currentOutboundAddress = outboundIndex,outboundAddress; + frmXray.autoTesting = true; + + ..thread.invoke( + function(frmXray,outboundIndex,outboundAddress,sockProxyPort,httpProxyAddress,enableRetry,timerTesting){ + import web.rest.client; + var restClient = web.rest.client(,httpProxyAddress); + restClient._http.setTimeouts(1000,2000,2000); + var ret = restClient.get("https://www.google.com/generate_204"); + var lastStatusCode = restClient.lastStatusCode; + + if( lastStatusCode == 204 ){ + frmXray.onStartXrayComplete(outboundIndex,timerTesting,outboundAddress); + return; + } + restClient.close(); + + if(timerTesting){ + sleep(100); + } + + import inet.http; + var http = inet.http(,httpProxyAddress); + http.setTimeouts(1000,1000,1000); + var isAlive = http.get("http://www.msftconnecttest.com/connecttest.txt")=="Microsoft Connect Test"; + http.close(); + + if(isAlive){ + frmXray.onStartXrayComplete(outboundIndex,timerTesting,outboundAddress); + return; + } + + if(timerTesting){ + sleep(100); + } + + import wsock.tcp.socks5Client; + + var client; + for(i=1;2;1){ + sleep(200); + client = wsock.tcp.socks5Client("127.0.0.1",sockProxyPort); + if(client)break; + } + + if(client){ + client.setTimeouts(1000,1000); + if(client.connect("www.google.com",80) ){ + + var sendData =/*********** +GET / HTTP/1.1 +Host: www.google.com +Connection: close +User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) +Accept: */*; +Accept-Language: zh-CN,zh; +Accept-Charset:utf-8; +***********/ + client.write( sendData + '\r\n\r\n' ) + var rep = client.read(9); + client.close(); + + if( rep && ..string.startWith(rep,"HTTP/1.1 ") ){ + frmXray.onStartXrayComplete(outboundIndex,timerTesting,outboundAddress); + return; + } + } + }; + frmXray.onStartXrayFailed(outboundIndex,enableRetry,outboundAddress); + },frmXray,outboundIndex,outboundAddress, + v2ray.core.socksProxyPort,v2ray.core.getSystemProxyConfig(),enableRetry,timerTesting + ) + + return true; + } +} + +var autoUpdateSubscriptionTimerId; +frmXray.autoUpdateSubscription = function(timeout){ + ..win.clearTimeout(autoUpdateSubscriptionTimerId); + if(timeout===-1){ + autoUpdateSubscriptionTimerId = null; + return; + } + + if(config.proxy.autoRefreshSubscription){ + autoUpdateSubscriptionTimerId = ..win.setTimeout(function(){ + autoUpdateSubscriptionTimerId = null; + + import v2ray.outbounds; + v2ray.outbounds.autoUpdateSubscription(); + },timeout:10000) + } +} + +frmXray.onStartXrayComplete = function(outboundIndex,timerTesting,outboundAddress){ + frmXray.autoUpdateSubscription(-1); + + var outbound = config.proxy.outbounds[outboundIndex]; + var outbound = ..config.proxy.outbounds[outboundIndex]; + if(!(outbound && (outbound.address == outboundAddress))){ + return; + } + + var listview = frmXray.listview; + listview.ensureVisible(outboundIndex); + for b,v in table.eachIndex(config.proxy.outbounds){ + listview.setItemText("",b,8); + } + + frmXray.autoTesting = false; + listview.setItemText("活动服务器:正常",outboundIndex,8); + listview.activeOutboundIndex = outboundIndex; + + var address = listview.getItemText(outboundIndex,2); + if(!timerTesting) frmXray.edit.print("已切换到服务器:",address); + listview.activeOutboundAddress = address; + + if(listview.getItemText(outboundIndex,7)=="不可用"){ + listview.setItemText("",outboundIndex,7); + } + + frmXray.onTcpingReturn = function(outboundIndex,address,succeeded,speedText){ + if(address==listview.getItemText(outboundIndex,2)){ + listview.setItemText(speedText,outboundIndex,7); + } + }; + frmXray.validOutbounds = {}; + + frmXray.btnTcping.disabledText = null; + ..publish("activeOutbound",address); +} + +subscribe("activeOutbound",function(address){ + ..globalActiveOutbound = address; +} ) + +frmXray.onStartXrayFailed = function(outboundIndex,enableRetry,outboundAddress){ + ..publish("activeOutbound",false); + + var outbound = ..config.proxy.outbounds[outboundIndex]; + if(!(outbound && (outbound.address == outboundAddress))){ + return; + } + + if(outbound.subscribeUrl){ + frmXray.autoUpdateSubscription(); + } + + var listview = frmXray.listview; + listview.ensureVisible(outboundIndex); + if(listview.activeOutboundIndex==outboundIndex){ + listview.activeOutboundIndex=null; + listview.activeOutboundAddress = null; + } + + listview.setItemText("不可用",outboundIndex,7); + if(enableRetry){ + if(#frmXray.validOutbounds){ + var next = table.shift(frmXray.validOutbounds); + activeOutbound(next[1],next[2],#frmXray.validOutbounds); + listview.setItemText("异常,测试下一个...",outboundIndex,8); + frmXray.edit.print("服务器异常:",listview.getItemText(outboundIndex,2)); + frmXray.edit.print("正在尝试连接:",next[2]); + } + else { + frmXray.btnTcping.oncommand(); + } + } + else { + listview.setItemText("活动服务器:异常",outboundIndex,8); + frmXray.edit.print("已切换到服务器:",listview.getItemText(outboundIndex,2)); + frmXray.autoTesting = false; + } + + frmXray.btnTcping.disabledText = null; + +} + +var tcping = function(frmXray,outboundIndex,outbound){ + import wsock.tcp.client; + var timeout = 0; + var failed = 0; + for(i=1;8;1){ + sleep(1); + + var client = wsock.tcp.client(); + var tickBegin = time.tick(); + if(client.connectTimeout(outbound.address,tonumber(outbound.port),3)){ + var ret = client.send("."); + client.close(); + + if( ret != 1){ + frmXray.onTcpingReturn(outboundIndex,outbound.address,false,"不可用"); + return; + } + timeout = timeout + (time.tick() - tickBegin); + } + else { + client.close(); + + failed++; + if(failed>1){ + frmXray.onTcpingReturn(outboundIndex,outbound.address,false,"不可用"); + return; + } + } + } + + frmXray.onTcpingReturn(outboundIndex,outbound.address,true,math.round(timeout / (8-failed) / 1000,2)+"秒"); +}; + +var retryOnNetworkAliveTimerId; +frmXray.onTcpingFailed = function(){ + frmXray.autoTesting = false; + frmXray.btnTcping.disabledText = null; + ..publish("activeOutbound",false); + + if(retryOnNetworkAliveTimerId){ + frmXray.clearTimeout(retryOnNetworkAliveTimerId); + } + + if(inet.http.isAlive(,false)){ + frmXray.autoUpdateSubscription(1000); + } + else { + retryOnNetworkAliveTimerId = frmXray.setInterval( + 1000,function(){ + + if(frmXray.listview.activeOutboundIndex){ + retryOnNetworkAliveTimerId = null; + return 0; + } + + if(inet.http.isAlive(,false)){ + frmXray.btnTcping.oncommand(); + retryOnNetworkAliveTimerId = null; + return false; + } + } + ) + } +} + +import sysProxy; +import style; +frmXray.btnTcping.skin(style.primaryButton); +frmXray.btnTcping.oncommand = function(id,event){ + frmXray.listview.activeOutboundIndex = null; + frmXray.listview.activeOutboundAddress = null; + frmXray.listview.clearColumnImage(); + + var items = frmXray.listview.items; + if(#items){ + frmXray.btnTcping.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} + + v2ray.core.lastDownloadingCoreFailed = false; + if(!v2ray.core.getPath()){ + frmXray.btnTcping.disabledText = null; + return; + } + + var failedCount = 0; + frmXray.onTcpingReturn = function(outboundIndex,address,succeeded,speedText){ + if(address!=frmXray.listview.getItemText(outboundIndex,2)){ + return; + } + frmXray.listview.setItemText(speedText,outboundIndex,7); + + if(succeeded){ + frmXray.listview.setItemText(speedText,outboundIndex,7); + frmXray.validOutbounds = {} + frmXray.onTcpingReturn = function(outboundIndex,address,succeeded,speedText){ + if(address!=frmXray.listview.getItemText(outboundIndex,2)){ + return; + } + + frmXray.listview.setItemText(speedText,outboundIndex,7); + if(succeeded) { + table.push(frmXray.validOutbounds,{outboundIndex;address}); + } + else{ + failedCount++; + if(failedCount==#items) { + frmXray.onTcpingFailed(); + } + } + } + activeOutbound(outboundIndex,address,#items>1); + } + else{ + failedCount++; + if(failedCount==#items) { + frmXray.onTcpingFailed(); + } + } + } + + thread.createSuspended(true); + + var handles = {}; + var outbounds = config.proxy.outbounds; + var lenPing = 0; + var listview = frmXray.listview; + for(i=1;#items;1){ + if(outbounds[i].autoConnect===false){ + listview.setItemText("禁止测速",i,7); + continue; + } + + if(lenPing>config.proxy.maxTestServers){ + frmXray.edit.print("测速服务器数超出设定上限:"+config.proxy.maxTestServers + ",您可在「配置 / 高级设置」中修改此值。") + break; + } + lenPing++; + + listview.setItemText("...",i,7); + listview.setItemText("",i,8); + + var h = thread.create(tcping,frmXray,i,config.proxy.outbounds[i]); + table.push(handles,h); + } + thread.createSuspended(false); + + for(i=1;#handles;1){ + var h = handles[i]; + thread.resume(h); + raw.closehandle(h); + } + + if(#handles) ..thread.waitOne(handles); + } + else { + if(id) frmXray.msgWarn("请先添加服务器") + v2ray.core.stop(); + + frmXray.btnTcping.disabledText = null; + frmXray.autoTesting = false; + frmXray.onTcpingReturn = function(outboundIndex,address,succeeded,speedText){}; + } +} + +import v2ray.core; +import v2ray.pacServer; +frmXray.onDestroy = function(){ + v2ray.core.stop(); + v2ray.pacServer.stop(); +} + +var pingThread = function( ip,frmXray ) { + import icmp.ping; + var ping = icmp.ping(); + + for(i=1;4;1){ + if( ping.perform(ip) ){ + frmXray.edit.print(ip,string.format( "Reply from %s: bytes=%d time=%dms TTL=%d" + , ping.ip , #ping.requestData , ping.echoReply.roundTripTime , ping.echoReply.options.ttl ) ); + } + else { + frmXray.edit.print(ip,"Request timed out"); + } + + } +} + +var removeOutbounds = function(selectedItems){ + + //避免后台线程改变activeIndex + frmXray.onTcpingReturn = function(outboundIndex,address,succeeded,speedText){}; + frmXray.btnTcping.disabledText = null; + frmXray.autoTesting = false; + + var activeIndex = frmXray.listview.activeOutboundIndex; + var outbounds = config.proxy.outbounds; + for(i=#outbounds;1;-1){ + var ob = outbounds[i]; + if(activeIndex==i){ + ob.active = true; + } + } + + if(#selectedItems){ + for(i=#selectedItems;1;-1){ + var item = selectedItems[i] + frmXray.listview.delItem(item); + ..table.remove(config.proxy.outbounds,item); + } + } + else{ + for(i=#outbounds;1;-1){ + if(frmXray.listview.getItemText(i,7)=="不可用"){ + ..table.remove(outbounds,i); + frmXray.listview.delItem(i); + } + } + } + + frmXray.listview.activeOutboundIndex = null; + for(i=1;#outbounds;1){ + if(outbounds[i].active){ + frmXray.listview.activeOutboundIndex = i; + break; + } + } + publish("outbounds.updateConfigJson"); + + if(activeIndex && (!frmXray.listview.activeOutboundIndex) ){ + if(!v2ray.core.lastDownloadingCoreFailed) frmXray.btnTcping.oncommand(); + } +} + +import v2ray.outbounds; +frmXray.listview.onnotify = function(id,code,ptr){ + select(code) { + case 0xFFFFFFF4/*_NM_CUSTOMDRAW*/ { + var lvcd = frmXray.listview.getNotifyCustomDraw(code,ptr); + if( lvcd.nmcd.dwDrawStage == 0x10001/*_CDDS_ITEMPREPAINT*/) + return 0x20/*_CDRF_NOTIFYSUBITEMDRAW*/ + elseif( lvcd.nmcd.dwDrawStage == 1/*_CDDS_PREPAINT*/ ){ + return 0x20/*_CDRF_NOTIFYITEMDRAW*/; + } + elseif( lvcd.nmcd.dwDrawStage == ( 0x10001/*_CDDS_ITEMPREPAINT*/ | 0x20000/*_CDDS_SUBITEM*/) ){ + //注意这里 iSubItem 的索引自0开始( 其他函数通常自1开始 ) + lvcd.clrText = lvcd.nmcd.dwItemSpec % 2 ? 0x373737 : 0; + lvcd.clrTextBk = lvcd.nmcd.dwItemSpec % 2 ? 0xFFFFFF : 0xF5F5F5; + + var item = lvcd.nmcd.dwItemSpec+1; + if(lvcd.iSubItem==7){ + if(frmXray.listview.activeOutboundIndex=item){ + lvcd.clrTextBk = 0x8AFFC3 + } + } + elseif(lvcd.iSubItem==6){ + if(..config.proxy.outbounds[item].autoConnect===false){ + lvcd.clrText = 0xCCCCCC; + } + } + lvcd.update() + + return 0/*_CDRF_DODEFAULT*/ + } + } + case 0xFFFFFFFD/*_NM_DBLCLK*/ { + var nm = frmXray.listview.getNotifyMessage(code,ptr); + if( nm ){ + v2ray.core.lastDownloadingCoreFailed = false; + + frmXray.onTcpingReturn = function(outboundIndex,address,succeeded,speedText){ + if(address==frmXray.listview.getItemText(outboundIndex,2)){ + frmXray.listview.setItemText(speedText,outboundIndex,7); + } + } + frmXray.btnTcping.disabledText = null; + + for b,v in table.eachIndex(config.proxy.outbounds){ + frmXray.listview.setItemText("",b,8); + } + activeOutbound(nm.iItem,frmXray.listview.getItemText(nm.iItem,2),false); + } + } + case 0xFFFFFFFB/*_NM_RCLICK*/ { + var x,y = win.getCursorPos(); + var nm = frmXray.listview.getNotifyMessage(code,ptr); + if(!nm) return; + + var currentIdx = nm.iItem; + if(!currentIdx){ + var popmenu = win.ui.popmenu(frmXray); + popmenu.add("新增代理服务器",function(id){ + var frmOutbound = frmXray.loadForm("\forms\main\outbound.aardio"); + frmOutbound.doModal() + }); + + popmenu.add("自剪贴板批量导入分享链接、订阅源",function(id){ + frmXray.btnImportServerFromClipBd.oncommand(); + }); + + popmenu.add('立即更新所有订阅源',function(id){ + v2ray.outbounds.updateSubscription(); + }); + + popmenu.add(); + + popmenu.add('清空服务器列表',function(id){ + config.proxy.outbounds = ..table.array(); + frmXray.listview.clear(); + + frmXray.btnTcping.disabledText = null; + frmXray.autoTesting = false; + frmXray.onTcpingReturn = function(outboundIndex,address,succeeded,speedText){} + publish("outbounds.updateConfigJson"); + }); + + popmenu.add('清除「不可用」服务器',function(id){ + removeOutbounds(); + }); + + popmenu.add("重置为默认服务器列表", + function(id){ + ..config.__loadDefaultOutbounds(); + publish("outbounds.updateConfigJson"); + publish("uiCommand.restartV2RayCore"); + } + ); + popmenu.add(); + + if(!frmXray.btnTcping.disabledText){ + popmenu.add('按「响应速度」排序服务器',function(id){ + frmXray.listview.sortBySpeed(); + }); + popmenu.add(); + }; + popmenu.popup(x,y,true); + return; + } + + var selectedItems = frmXray.listview.selected; + var popmenu = win.ui.popmenu(frmXray); + + if(#selectedItems==1){ + popmenu.add('设为活动服务器( 鼠标双击 )',function(id){ + if(currentIdx){ + v2ray.core.lastDownloadingCoreFailed = false; + + frmXray.onTcpingReturn = function(outboundIndex,address,succeeded,speedText){ + if(address==frmXray.listview.getItemText(outboundIndex,2)){ + frmXray.listview.setItemText(speedText,outboundIndex,7); + } + } + + frmXray.btnTcping.disabledText = null; + + for b,v in table.eachIndex(config.proxy.outbounds){ + frmXray.listview.setItemText("",b,8); + } + activeOutbound(currentIdx,frmXray.listview.getItemText(currentIdx,2),false) + } + }); + + popmenu.add(); + } + + popmenu.add("编辑 / 新增代理服务器",function(id){ + var frmOutbound = frmXray.loadForm("\forms\main\outbound.aardio"); + frmOutbound.setOutboundConfig(config.proxy.outbounds[currentIdx]); + frmOutbound.doModal() + }); + + popmenu.add("自剪贴板批量导入分享链接、订阅源",function(id){ + frmXray.btnImportServerFromClipBd.oncommand(); + }); + + var subscribeUrl = config.proxy.outbounds[currentIdx][["subscribeUrl"]]; + if(#selectedItems=1 && subscribeUrl){ + + var ps; + var cfgSubscribeUrls = ..config.proxy.subscribeUrls; + for(i=#cfgSubscribeUrls;1;-1){ + var sub = cfgSubscribeUrls[i] + if(sub.url===subscribeUrl) { + ps = sub.ps; + break; + } + } + + if(#ps){ + ps = ": "+ps; + } + + popmenu.add('更新当前订阅源'+ps,function(id){ + if(currentIdx){ + v2ray.outbounds.updateSubscription({[subscribeUrl]=true}); + } + }); + } + + popmenu.add('更新所有订阅源',function(id){ + if(currentIdx){ + v2ray.outbounds.updateSubscription(); + } + }); + + popmenu.add() + + var autoConnect = config.proxy.outbounds[currentIdx].autoConnect!==false; + var id = popmenu.add('允许自动测速并连接',function(id){ + if(currentIdx){ + for(i=#selectedItems;1;-1){ + var item = selectedItems[i]; + if(autoConnect === false){ + config.proxy.outbounds[item].autoConnect = null; + frmXray.listview.setItemText("",item,7); + } + else { + config.proxy.outbounds[item].autoConnect = false; + frmXray.listview.setItemText("禁止测速",item,7); + } + } + } + }); + popmenu.check(id,autoConnect,0/*_MF_BYCOMMAND*/); + popmenu.add() + + popmenu.add('删除服务器',function(id){ + removeOutbounds(selectedItems); + }); + + popmenu.add('清空服务器列表',function(id){ + if(currentIdx){ + config.proxy.outbounds = ..table.array(); + frmXray.listview.clear(); + publish("outbounds.updateConfigJson"); + } + }); + + popmenu.add('清除「不可用」服务器',function(id){ + removeOutbounds(); + }); + + popmenu.add("重置为默认服务器列表", + function(id){ + ..config.__loadDefaultOutbounds(); + publish("outbounds.updateConfigJson"); + publish("uiCommand.restartV2RayCore"); + } + ); + + if(#selectedItems==1){ + + popmenu.add(); + popmenu.add('生成二维码',function(id){ + if(currentIdx){ + import v2ray.outbounds; + import win.clip; + + var str = v2ray.outbounds.exportSharedLinks({config.proxy.outbounds[currentIdx]}); + if(str){ + var frmChild = frmXray.loadForm("\forms\main\tools\qr.aardio"); + frmChild.createQrCode(str); + frmChild.show(); + } + } + }); + + popmenu.add('复制服务器分享链接',function(id){ + if(currentIdx){ + import v2ray.outbounds; + import win.clip; + + var str = v2ray.outbounds.exportSharedLinks({config.proxy.outbounds[currentIdx]}); + if(str){ + win.clip.write(str); + frmXray.edit.print("已复制链接:",str); + } + } + }); + + popmenu.add(); + + var toolMenu = win.ui.popmenu(frmXray) + toolMenu.add('本机 Ping 检测',function(id){ + if(currentIdx){ + thread.invoke(pingThread,config.proxy.outbounds[currentIdx].address,frmXray) + } + }); + + toolMenu.add('全球范围 Ping 检测 ...',function(id){ + if(currentIdx){ + process.openUrl("http://ping.pe/" + config.proxy.outbounds[currentIdx].address) + } + }); + + toolMenu.add('全球范围端口检测 ...',function(id){ + if(currentIdx){ + process.openUrl("http://port.ping.pe/" + config.proxy.outbounds[currentIdx].address + ":" + config.proxy.outbounds[currentIdx].port) + } + }); + + toolMenu.add('在线路由跟踪检测 ...',function(id){ + if(currentIdx){ + process.openUrl("https://www.boce.com/traceroute/" + config.proxy.outbounds[currentIdx].address) + } + }); + + toolMenu.add('本机路由检测',function(id){ + if(currentIdx){ + import process; + process.execute("cmd.exe","/k tracert " + config.proxy.outbounds[currentIdx].address); + } + }); + + if(config.proxy.outbounds[currentIdx].port == 443 && config.proxy.outbounds[currentIdx].tls){ + toolMenu.add('浏览 HTTPS 主页 ...',function(id){ + if(currentIdx){ + process.openUrl("https" ++ "://" + config.proxy.outbounds[currentIdx].address); + } + }); + } + + popmenu.add("服务器工具",toolMenu) + + popmenu.add('SSH 登录服务器',function(id){ + if(currentIdx){ + if(_STUDIO_INVOKED){ + frmXray.msgErr("请在发布后运行此功能"); + return; + } + import process; + process.execute(io._exepath,"/sshLogin root@" + + config.proxy.outbounds[currentIdx].address + ":" + + (config.proxy.outbounds[currentIdx].sshPort||22)); + } + }); + } + popmenu.popup(x,y,true); + } + case 0xFFFFFF94/*_LVN_COLUMNCLICK*/{ + var nm = frmXray.listview.getNotifyMessage(code,ptr) + if(nm.iSubItem==7){ + frmXray.listview.sortBySpeed(); + } + else { + frmXray.msgWarn("排序请点击「响应速度」列") + } + } + } +} + +// 排序函数 +frmXray.listview.sortBySpeed = function () { + if(frmXray.btnTcping.disabledText){ + frmXray.msgWarn("请等待测速完成,然后再点击此排序列。"); + return; + } + + var outbounds = ..table.clone(config.proxy.outbounds); + var activeIndex = frmXray.listview.activeOutboundIndex; + frmXray.onTcpingReturn = function(outboundIndex,address,succeeded,speedText){}; //避免后台线程改变activeIndex + + for(i=#outbounds;1;-1){ + var ob = outbounds[i]; + if(type(ob)!="table"){ + table.remove(outbounds,i); + continue; + } + + ob.speed = frmXray.listview.getItemText(i,7); + if(ob.speed=="不可用"){ + ob.speedNum = 0xFFFE; + } + elseif(ob.speed==""){ + ob.speedNum = 0xFFFF; + } + elseif(ob.speed=="..."){ + frmXray.msgWarn("请等待检测速度完成,然后再点击此排序列。") + return; + } + else { + ob.speedNum = tonumber(ob.speed):-3; + } + + if(activeIndex==i){ + ob.active = true; + } + } + + var hasStatus; + for(i=1;#outbounds;1){ + if(#outbounds[i].speed){ + hasStatus = true; + break; + } + } + + if(!hasStatus){ + frmXray.msgWarn("请先点击「检测并连接服务器」获取服务器响应速度!"); + return; + } + + var desc = frmXray.listview.getColumnImage(7) == 0; + if(desc){ + table.sort(outbounds,function(b){ + return owner.speedNum > b.speedNum; + }) + } + else { + table.sort(outbounds,function(b){ + return owner.speedNum < b.speedNum; + }) + } + + frmXray.listview.activeOutboundIndex = null; + for(i=1;#outbounds;1){ + if(outbounds[i].active){ + frmXray.listview.activeOutboundIndex = i; + break; + } + } + + outbounds.fields = {"protocol";"address";"port";"security";"network";"ps";"speed"} + config.proxy.outbounds = outbounds; + frmXray.listview.setTable(outbounds); + outbounds.fields = {"protocol";"address";"port";"security";"network";"ps"} + + //清理用于排序的临时字段 + for(i=1;#outbounds;1){ + var ob = outbounds[i]; + ob.speedNum = null; + ob.speed = null; + ob.active = null; + } + + if(frmXray.listview.activeOutboundIndex){ + frmXray.listview.setItemText("活动服务器:正常",frmXray.listview.activeOutboundIndex,8) + } + frmXray.listview.setColumnImage(7, desc ? 1 : 0); +} + +import win.imageList; +var iml = win.imageList(16, 15); +iml.add('GIF\56\57a \0\15\0\x80\0\0\x80\x80\x80\xff\0\xff\33\xf9\4\0\0\0\0\0\44\0\0\0\0 \0\15\0\0\2\31\x8c\x8f\xa9\xcb\xed\15\xa3\x9c\xb4N\xf0\x80\xde\56k\xbfA\\\xd7\x84 \x97Y\xea\xca\xb6\xee\11\xc7F\1\0;', 0xff00ff); +frmXray.listview.setColumnImageList(iml); + +subscribe("uiCommand.restartV2RayCore",function(){ + config.proxy.outbounds.fields = {"protocol";"address";"port";"security";"network";"ps";} + + var outbounds = config.proxy.outbounds; + for(i=#outbounds;1;-1){ + if(type(outbounds[i])!="table"){ + table.remove(outbounds,i); + } + } + frmXray.listview.setTable(outbounds); + + if(!v2ray.core.lastDownloadingCoreFailed) frmXray.btnTcping.oncommand(); +} ) + +import process; +if(#config.proxy.outbounds){ + config.proxy.outbounds.fields = {"protocol";"address";"port";"security";"network";"ps";} + + var outbounds = config.proxy.outbounds; + for(i=#outbounds;1;-1){ + if(type(outbounds[i])!="table"){ + table.remove(outbounds,i); + } + } + frmXray.listview.setTable(outbounds); + + frmXray.setTimeout( + function(){ + publish("uiCommand.restartV2RayCore"); + },1000 + ); +} + +subscribe("sysProxy.modeChanged",function(mode){ + frmXray.radioProxyPac.checked = false; + frmXray.radioProxy.checked = false; + frmXray.radioProxyDirect.checked = false; + + if(mode = "pac"){ + frmXray.radioProxyPac.checked = true; + if(_WIN10_LATER) frmXray.btnEditPacOrUwp.text = "编辑 PAC"; + } + elseif(mode = "proxy"){ + frmXray.radioProxy.checked = true; + if(_WIN10_LATER) frmXray.btnEditPacOrUwp.text = "配置 UWP"; + } + else{ + frmXray.radioProxyDirect.checked = true; + } +} ) +publish("sysProxy.modeChanged",config.proxy.mode); + +import sysProxy; +var switchProxyMode = function(){ + if(frmXray.radioProxyPac.checked){ + sysProxy.switchToPacMode(); + } + elseif(frmXray.radioProxy.checked){ + sysProxy.switchToGlobalMode(); + } + else { + sysProxy.switchToDirectMode(); + } +} +frmXray.radioProxyPac.oncommand = switchProxyMode; +frmXray.radioProxy.oncommand = switchProxyMode; +frmXray.radioProxyDirect.oncommand = switchProxyMode; + +import win.dlg.message; +frmXray.btnEditPacOrUwp.skin(style.plainButton) +frmXray.btnEditPacOrUwp.oncommand = function(id,event){ + if(frmXray.radioProxy.checked && _WIN10_LATER ){ + if(_STUDIO_INVOKED){ + frmXray.msgErr("请先发布为 EXE!"); + return; + } + + import process; + process.execute(io._exepath,"/uwp","runas") + return; + } + + if(frmPac && win.isWindow(frmPac.hwnd)){ + if( win.isIconic(frmPac.hwnd) ) win.show(frmPac.hwnd,9/*_SW_RESTORE*/ ); + if( !win.isVisible(frmPac.hwnd) ) win.show(frmPac.hwnd,0x1/*_SW_NORMAL*/ ); + win.setForeground(frmPac.hwnd) + return; + } + + frmPac = ..mainForm.loadForm("\forms\main\pac.aardio"); + frmPac.show(); +} +subscribe("uiCommand.showPacForm",function(...){ + frmXray.btnEditPacOrUwp.oncommand(); +} ) + +subscribe("uiCommand.print",function(...){ + frmXray.edit.print(...); +} ) + +import v2ray.outbounds; +frmXray.btnImportServerFromClipBd.skin(style.plainButton) +frmXray.btnImportServerFromClipBd.oncommand = function(id,event){ + var str = ..win.clip.read(); + if(str){ + str = ..string.trim(str,'"\'\t\r\n '); + if( ..string.startWith(str,"http://") + || ..string.startWith(str,"https://") + || ..string.match(str,"^\s*/\N+\s*$") ){ + if(..string.match(str,"^\s*/\N+\s*$")){ + str = "https://github.com" + str; + } + + v2ray.outbounds.updateSubscription({[str]=true}); + return; + } + + var outbounds = v2ray.outbounds.importFromString(str); + if(#outbounds){ + ..table.append(config.proxy.outbounds,outbounds); + publish("uiCommand.restartV2RayCore"); + publish("outbounds.updateConfigJson"); + frmXray.msgOk("已成功导入" + #outbounds + "个服务器",1200); + return; + } + } + + frmXray.msgFrown('未导入服务器!\r\n请先复制以下格式文本(自动清除其中的无效内容):\r\n\r\n1、一行或多行(忽略无效行)分享链接或服务器JSON配置。\r\n支持 vmess://,vless://,ss://,ssr://,trojan://, trojan-go:// 等通用分享链接。\r\n\r\n2、包含多个服务器配置的JSON数组,支持winXray格式以及通用格式JSON。\r\n\r\n3、单个 http:// 或 https:// 开头的通用订阅源地址。\r\n可直接使用浏览器地址栏的github文件地址(含blob或raw目录名)。\r\n也可以仅复制单斜杆开始的github文件路径。\r\n\r\n订阅源可用BASE64编码或明文返回以上1、2条规定的配置或分享链接。') +} + +var testTimerId; +frmXray.chkAutoTest.oncommand = function(id,event){ + if(testTimerId){ + frmXray.clearInterval(testTimerId); + } + + config.proxy.test = frmXray.chkAutoTest.checked; + if(!config.proxy.test) return; + + import inet.http; + testTimerId = frmXray.setInterval( + config.proxy.testInterval*1000,function(){ + if(frmXray.btnTcping.disabled) return; + if( frmXray.autoTesting ) return; + + var idx = frmXray.listview.activeOutboundIndex; + var address = frmXray.listview.activeOutboundAddress; + if( !( idx&&address) ){ + if(!inet.http.isAlive(,false)){ + return config.proxy.testInterval*1000; + } + + if(!v2ray.core.lastDownloadingCoreFailed) frmXray.btnTcping.oncommand(); + return; + } + + frmXray.autoTesting = true; + activeOutbound(idx,address,true,true); + + return config.proxy.testInterval*1000; + } + ) +} + +if(config.proxy.test){ + frmXray.chkAutoTest.checked = true; + frmXray.chkAutoTest.oncommand(); +} + +frmXray.chkAutoTest.skin(style.checkBox); +frmXray.edit.print("友情提醒:WinXray 未注册任何域名,谨防钓鱼网站") + +frmXray.enableDpiScaling(); +win.loopMessage(); \ No newline at end of file diff --git a/lib/config.aardio b/lib/config.aardio new file mode 100644 index 0000000..0b3eecb --- /dev/null +++ b/lib/config.aardio @@ -0,0 +1,158 @@ +//config 配置文件 +import fsys.config; +config = fsys.config( io.appData("/winXray/") ); + +namespace config { + __appName = "winXray"; + __loadDefaultOutbounds = function(){ + import v2ray.outbounds; + var serverData = ..string.load("/v2ray-core/winXray-default-servers.json") + : $"/v2ray-core/winXray-default-servers.json" + + proxy.outbounds = ..v2ray.outbounds.importFromString(..string.removeBom(serverData)); + ..publish("outbounds.updateConfigJson",) + } + + if(!proxy.outbounds){ + __loadDefaultOutbounds(); + } +} + +if(!config.proxy.mode) config.proxy.mode = "pac"; +if(!config.proxy.pacPort) config.proxy.pacPort = 0; +if(config.proxy.useHttpGlobal===null){ + config.proxy.useHttpGlobal = true; +} +if(config.proxy.useSocksPac===null){ + config.proxy.useSocksPac = _WIN10_LATER; +} + +if(config.proxy.enableGitConfigGithub===null){ + config.proxy.enableGitConfigGithub = true; +} + +if(config.proxy.test === null){ + config.proxy.test = true; +} + +if(config.proxy.autoRefreshSubscription === null){ + config.proxy.autoRefreshSubscription = true; +} + +if(!config.proxy.testInterval){ + config.proxy.testInterval = 15; +} + +if(!config.proxy.maxTestServers){ + config.proxy.maxTestServers = 100; +} + +if(!config.proxy.subscribeUrls){ + config.proxy.subscribeUrls = { + fields = {"";"checked";"ps";"url";} + } +} + +if(!config.proxy.hotkey){ + config.proxy.hotkey = {1/*_MOD_ALT*/|2/*_MOD_CONTROL*/|4/*_MOD_SHIFT*/;'P'#} +} + +config.__resetDefaultCore = function(){ + config.core.default = { + inbounds={ + { + listen="127.0.0.1"; + port=0; + protocol="socks"; + settings={ + auth="noauth"; + udp=true; + }; + sniffing={ + destOverride={ + "http"; + "tls" + }; + enabled=true + }; + tag="proxy"; + }; + { + listen="127.0.0.1"; + port=0; + protocol="http"; + settings={}; + sniffing={ + destOverride={ + "http"; + "tls" + }; + enabled=true + }; + tag="http_proxy" + } + }; + log={ + access=""; + error=""; + loglevel="warning" + }; + outbounds={ + { + tag="proxy" + }; + { + protocol="freedom"; + settings={}; + tag="direct"; + }; + { + protocol="blackhole"; + settings={ + response={ + type="http" + }; + }; + tag="block"; + } + }; + routing={ + domainStrategy="IPIfNonMatch"; + rules={ + { + inboundTag={ + "api" + }; + outboundTag="api"; + type="field"; + } + } + }; + } +} + +if(!config.core.default){ + config.__resetDefaultCore(); +} + +if(!config.core.default.inbounds[2]){ + config.core.default.inbounds[2] = { + listen="127.0.0.1"; + port=0; + protocol="http"; + settings={}; + sniffing={ + destOverride={ + "http"; + "tls" + }; + enabled=true + }; + tag="http_proxy" + } +} + +/**intellisense(config) +__appName = 应用程序名 +? = 配置文件名,\n读写配置并序列化为一个表对象,\n表的成员值可以是支持序列化的普通变量,支持table对象\n配置文件在首次使用时自动加载,退出程序时自动保存\n!fsys_table. +end intellisense**/ \ No newline at end of file diff --git a/lib/dnsApi.aardio b/lib/dnsApi.aardio new file mode 100644 index 0000000..3530d6d --- /dev/null +++ b/lib/dnsApi.aardio @@ -0,0 +1,11 @@ +//dnsApi 域名解析 +namespace dnsApi + +_dll = ..raw.loadDll("dnsapi.dll"); +flush = function(domain){ + return domain ? _dll.DnsFlushResolverCacheB() : _dll.DnsFlushResolverCacheEntry_A(domain); +} + +/**intellisense(dnsApi) +flush(.(domain) = 清空指定域名的DNS缓存,\n如果参数不指定域名则清空所有DNS缓存 +end intellisense**/ diff --git a/lib/style.aardio b/lib/style.aardio new file mode 100644 index 0000000..42e0c0c --- /dev/null +++ b/lib/style.aardio @@ -0,0 +1,108 @@ +//style 外观样式 + +namespace style{ + primaryButton = { + background={ + default=0xFF8FB2B0; + hover=0xFF928BB3; + disabled=0xFFCCCCCC; + } + }; + button = { + background={ + default=0x668FB2B0; + hover=0xFF928BB3; + disabled=0xFFCCCCCC; + } + }; + transButton = { + background={ + default=0; + hover=0xFF928BB3; + disabled=0xFFCCCCCC; + } + }; + checkBox = { + color = { + hover = 0xFFFF0000; + active = 0xFF00FF00; + disabled = 0xEE666666; + } + checked = { + color = { + hover = 0xFFFF0000; + active = 0xFF00FF00; + disabled = 0xEE666666; + } + iconText = '\uF14a'/*_FA_CHECK_SQUARE*/ + } + }; + radio ={ + group = "default"; + color = { + hover = 0xFFFF0000; + active = 0xFF00FF00; + } + checked = { + iconText = '\uF058'/*_FA_CHECK_CIRCLE*/ + } + }; + link = { + color = { + default = 0xFF000080; + hover = 0xFFFF0000; + active = 0xFF00FF00; + } + }; + plainButton = { + color = { + default = 0xFF3C3C3C; + hover = 0xFFFF0000; + active = 0xFF00FF00; + disabled = 0xFFCCCCCC; + } + }; + key = { + foreground={ + default = 0x00FFFFFF; + hover= 0xFF8ADBAF; + }; + }; + dropdown = { + background={ + default=0xFF68CC95; + disabled=0xFFC4CCC8; + hover=0xFF4A522F; + }; + color={ + default=0xFF000000; + disabled=0xFF8A8A8A; + hover=0xFFFFFFFF + }; + checked = { + foreground={ + default = 0xFFDB8A8E; + hover= 0xFF8ADBAF; + }; + } + }; + edit = { + border={ + default={bottom=1;color=0xFF808080}; + disabled={bottom=1;color=0xFFCCCCCC} + } + }; + trackbar = { + background={ + default=0xFF23ABD9 + }; + foreground={ + default=0xFFFF771C; + hover=0xFFFF6600 + }; + color={ + default=0xFFFF5C00; + hover=0xFFFF6600 + } + } +} diff --git a/lib/sysProxy.aardio b/lib/sysProxy.aardio new file mode 100644 index 0000000..016c3fe --- /dev/null +++ b/lib/sysProxy.aardio @@ -0,0 +1,95 @@ +//sysProxy 系统代理 +import config; +import inet.conn; +import v2ray.github; +import v2ray.pacServer; + +namespace sysProxy; + +switch = function(mode){ + ..config.proxy.mode = mode : "direct"; + ..config.proxy.save(); + + if(mode=="pac"){ + var pacUrl = ..v2ray.pacServer.getUrl(); + if(pacUrl){ + ..inet.conn.setProxyAutoConfig(,pacUrl ); + } + else { + ..v2ray.pacServer.restart(); + } + ..v2ray.github.setProxy(true); + } + elseif(mode=="proxy"){ + import v2ray.core; + var address = v2ray.core.getSystemProxyConfig(); + + if(address){ + ..inet.conn.setProxy(,address); + ..v2ray.github.setProxy(true); + } + } + else { + ..inet.conn.setProxy(); + ..v2ray.github.setProxy(false); + } + ..publish("sysProxy.modeChanged",mode) +} + +switchToGlobalMode = function(){ + switch("proxy") +} + +switchToPacMode = function(){ + switch("pac") +} + +switchToDirectMode = function(){ + switch("direct") +} + +switchHotkey = function(){ + var mode = ..config.proxy.mode; + if( mode != "pac"){ + switch("pac") + } + else { + switch("proxy") + } + + return ..config.proxy.mode; +} + +reset = function(proxy){ + if(proxy===false){ + if(..config.proxy.mode != "direct"){ + ..inet.conn.setProxy(); + ..v2ray.github.setProxy(false); + } + return; + } + + ..inet.conn.setProxy(); + switch(..config.proxy.mode); +} + +..subscribe("pacServer.restarted",function(pacPort){ + if(..config.proxy.mode == "pac"){ + switchToPacMode(); + } +} ) + +..subscribe("v2RayCore.restarted",function(socksProxyPort,httpProxPort){ + if(..config.proxy.mode != "direct"){ + reset(true); + } +} ) + +/**intellisense(sysProxy) +switch(.(mode) = 切换代理模式,同步修改配置文件。\n可选参数:"proxy","pac","direct" +switchToGlobalMode() = 设为全局代理,同步修改配置文件。 +switchToPacMode() = 设为PAC自动代理,同步修改配置文件。 +switchToDirectMode() = 设为禁用代理,同步修改配置文件。 +reset(.(是否启用代理)) = 重置系统代理设置,不修改配置文件。\n省略参数时默认值为true。 +end intellisense**/ + \ No newline at end of file diff --git a/lib/v2ray/core/_.aardio b/lib/v2ray/core/_.aardio new file mode 100644 index 0000000..19e9f4b --- /dev/null +++ b/lib/v2ray/core/_.aardio @@ -0,0 +1,344 @@ +//内核进程 +import v2ray.core.ssr; +import v2ray.core.naive; +import wsock.tcp.server; +import process.popen; +import config; + +namespace v2ray.core; + +socksProxyPort = null; +httpProxPort = null; + +getSystemProxyConfig = function(){ + if(!(socksProxyPort&&httpProxPort)){ return null; } + return ..config.proxy.useHttpGlobal ? ("127.0.0.1:" + httpProxPort ): ("SOCKS=127.0.0.1:"+socksProxyPort) +} + +isInboundPortChanged = function(){ + var inbounds = ..config.core.default.inbounds; + if(! (..table.isArray(inbounds) && inbounds[1] && inbounds[2]) ){ + return true; + } + + return (inbounds[1].port!=socksProxyPort) || (inbounds[2].port!=httpProxPort) +} + +var prcsV2Ray,v2RayStarting; +import process.job.limitKill; +restart = function(editor,outbound){ + + if(!outbound){ return null,"错误的出站代理服务器配置" } + if(_WINXP){ + return null,"抱歉!V2Ray Core 不支持 Windows XP, 仅支持 Windows 7, Windows 10 以及更新操作系统。"; + } + + var inbounds = ..config.core.default[["inbounds"]]; + if(! (..table.isArray(inbounds) && inbounds[1] ) ){ + return null,"错误的入站SOCKS代理服务器配置" + } + if(! ( inbounds[2] ) ){ + return null,"错误的入站HTTP代理服务器配置" + } + + if(v2RayStarting){ return null,"不能重复启动 V2Ray Core" } + v2RayStarting = true; + + var corePath = getPath(editor.hwnd); + if(!corePath){ + v2RayStarting = false; + return false,"启动失败,未找到 v2ray.exe"; + } + + // 先不要断开当前代理,使用当前代理下载会更快。 + if( outbound.protocol == "ssr" ){ + if(!..v2ray.core.ssr.getPath(editor.hwnd)){ + v2RayStarting = false; + return false,"启动失败,未找到 SSR Core"; + } + } + if( outbound.protocol == "naive" ){ + if(!..v2ray.core.naive.getPath(editor.hwnd)){ + v2RayStarting = false; + return false,"启动失败,未找到 NaïveProxy Core"; + } + } + + ..publish("activeOutbound",false); + + import sysProxy; + ..sysProxy.reset(false); + + + socksProxyPort = inbounds[1].port; + httpProxPort = inbounds[2].port; + if( (! socksProxyPort) || socksProxyPort >= 49152 ){ socksProxyPort = ..wsock.tcp.server.getFreePort("127.0.0.1",1081,10801,10811,44821) } + if( (! httpProxPort) || httpProxPort >= 49152 ){ httpProxPort = ..wsock.tcp.server.getFreePort("127.0.0.1",1082,10802,10812,44822) } + + if(prcsV2Ray){ + prcsV2Ray.terminate(); + prcsV2Ray = null; + } + + ..v2ray.core.ssr.stop(); + ..v2ray.core.naive.stop(); + + var nexCore; + if( outbound.protocol == "ssr" ){ + var nextProxyPort = ..wsock.getFreePort(); + if(!..v2ray.core.ssr.restart(editor,outbound,nextProxyPort)){ + v2RayStarting = false; + return false,"SSR Core 启动失败"; + } + + outbound = { + protocol = "socks"; + address = "127.0.0.1"; + port = nextProxyPort; + } + + nexCore = ..v2ray.core.ssr; + } + elseif( outbound.protocol == "naive" ){ + var nextProxyPort = ..wsock.getFreePort(); + if(!..v2ray.core.naive.restart(editor,outbound,nextProxyPort)){ + v2RayStarting = false; + return false,"SSR Core 启动失败"; + } + + outbound = { + protocol = "socks"; + address = "127.0.0.1"; + port = nextProxyPort; + } + + nexCore = ..v2ray.core.naive; + } + + if( ! prcsV2Ray ){ + + import v2ray.core.configJson; + var jsonPath,err = ..v2ray.core.configJson.write( + ..io.joinpath(..io.splitpath(corePath).dir,"config.json") + ,outbound,socksProxyPort,httpProxPort); + + if(!jsonPath){ + if( nexCore ){ nexCore.stop(); } + + v2RayStarting = false; + return false,err:"启动失败,写入配置文件遇到错误!"; + } + + var err; + prcsV2Ray,err = ..process.popen(corePath,"-c=config.json" ); + if(!prcsV2Ray){ + if( nexCore ){ nexCore.stop(); } + + ..publish("uiCommand.print",err:"启动 V2Ray Core 时遇到未知错误!"); + + if(!..process().isWow64()){ + if(..process.isExe(corePath)!="PE32"){ + ..io.remove(corePath); + if(!..io.exist(corePath)){ + ..publish("uiCommand.print","当前操作系统是32位,已删除无效的64位 V2Ray Core,正在下载32位 V2Ray Core"); + v2RayStarting = false; + return restart(editor,outbound) + } + else { + ..publish("uiCommand.print","当前操作系统是32位,但是找到的 V2Ray Core 是64位,请重新下载32位 V2Ray Core"); + } + } + } + + v2RayStarting = false; + return; + } + prcsV2Ray.assignToJobObject(process.job.limitKill); + prcsV2Ray.codepage = 65001; + prcsV2Ray.logResponse(editor); + + inbounds[1].port = socksProxyPort; + inbounds[2].port = httpProxPort; + ..config.core.save(); + } + + ..publish("uiCommand.print","已启动代理服务器,SOCKS端口:" + socksProxyPort + " HTTP端口:" + httpProxPort) + ..publish("v2RayCore.restarted",socksProxyPort,httpProxPort); + v2RayStarting = false; + return true; +} + +stop = function(){ + ..v2ray.core.ssr.stop(); + + if(prcsV2Ray){ + prcsV2Ray.terminate(); + prcsV2Ray = null; + } + + ..sysProxy.reset(false); + + import v2ray.github; + v2ray.github.setProxy(false); +} + +var getV2RayCoreUrl = function(){ + var msgDlg = ..win.dlg.message(..mainForm); + var form = msgDlg.create('正在获取 V2Ray Core 最新版本',,true) + form.icon = '\uF1D8'; + form.progress.startProgress(50); + + var url,tag = ..win.invoke(function(){ + import process; + import inet.http; + var http = ..inet.http(); + var url = http.location("https://github.com/v2fly/v2ray-core/releases/latest"); + http.close(); + + if(!url) return; + + var tag = ..string.match(url,"[^/]+$") + if(!tag || (tag=="latest")) return;; + + return "https://github.com/v2fly/v2ray-core/releases/download/" + + tag + "/v2ray-windows-" + (..process().isWow64() ? "64" : "32") + ".zip",tag + }); + form.close(); + + return url,tag; +} + +getPath = function(hwnd){ + var path = ..io.fullpath("/v2ray-core/v2ray.exe"); + if(..io.exist(path)){ + return path; + } + + var path = ..io.appData("/winXray/core/v2ray.exe"); + if(..io.exist(path)){ + return path; + } + + var path = ..io.fullpath("/xray-core/xray.exe"); + if(..io.exist(path)){ + ..io.rename("/xray-core/","/v2ray-core/") + } + + var path = ..io.fullpath("/v2ray-core/xray.exe"); + if(..io.exist(path)){ + ..io.rename("/v2ray-core/xray.exe","/v2ray-core/v2ray.exe") + return ..io.fullpath("/v2ray-core/v2ray.exe"); + } + + if(self.lastDownloadingCoreFailed){ + return; + } + + ..mainForm.disabled = true; + var url,versionTag = getV2RayCoreUrl(); + + if(!url) { + ..publish("uiCommand.print","请下载 V2Rary Core 到以下路径:"); + ..publish("uiCommand.print",path); + + ..mainForm.disabled = false; + self.lastDownloadingCoreFailed = true; + return null; + } + + import zlib.httpFile; + if( ..zlib.httpFile.download(url,"正在下载 V2Ray Core" + ,..io.appData("/winXray/download/") + ,..io.appData("/winXray/core/"),,..mainForm.hwnd) ){ + + self.lastDownloadingCoreFailed = null; + ..mainForm.disabled = false; + return ..io.exist(path); + } + else { + ..mainForm.disabled = false; + self.lastDownloadingCoreFailed = true; + + ..publish("uiCommand.print","请到以下网址下载 V2Ray Core:"); + ..publish("uiCommand.print",url); + + ..publish("uiCommand.print","下载后请解压到以下目录内:"); + ..publish("uiCommand.print",..io.appData("/winXray/core/")); + + //import process; + //process.execute(..io._exepath,"/github","runas"); + } +} + +getCoreDir = function(hwnd){ + var path = ..io.fullpath("/v2ray-core/v2ray.exe"); + if(..io.exist(path)){ + return ..io.fullpath("/v2ray-core/"); + } + + var path = ..io.appData("/winXray/core/v2ray.exe"); + if(..io.exist(path)){ + return ..io.appData("/winXray/core/");; + } + + var path = ..io.fullpath("/v2ray-core/"); + if(..io.exist(path)){ + return path; + } + + return ..io.appData("/winXray/core/"); +} + +updateCore = function(){ + ..mainForm.disabled = true; + + var coreDir = getCoreDir(); + var url,versionTag = getV2RayCoreUrl(); + if(!url){ + ..mainForm.disabled = false; + self.lastDownloadingCoreFailed = true; + return null; + } + + import fsys; + fsys.delete( ..io.appData("/winXray/temp/v2ray/") ); + + + import zlib.httpFile; + if( ..zlib.httpFile.download(url,"正在下载 V2Ray Core,版本:" + versionTag + ,..io.appData("/winXray/download/") + ,..io.appData("/winXray/temp/v2ray/"),,..mainForm.hwnd) ){ + ..mainForm.disabled = false; + + if(..io.exist(..io.appData("/winXray/temp/v2ray/v2ray.exe"))){ + import sysProxy; + sysProxy.reset(false); + + import process.file; + process.file.terminate(..io.joinpath(coreDir,"v2ray.exe")); + process.file.terminate(..io.joinpath(coreDir,"v2ctl.exe")); + + ..io.createDir(coreDir); + fsys.copy(..io.appData("/winXray/temp/v2ray/v2ray.exe"),..io.joinpath(coreDir,"v2ray.exe")); + fsys.copy(..io.appData("/winXray/temp/v2ray/v2ctl.exe"),..io.joinpath(coreDir,"v2ctl.exe")); + + self.lastDownloadingCoreFailed = null; + return versionTag; + } + else { + self.lastDownloadingCoreFailed = true; + } + } + else { + ..mainForm.disabled = false; + self.lastDownloadingCoreFailed = true; + } +} + +/**intellisense(v2ray.core) +socksProxyPort = SOCKS代理端口 +httpProxPort = HTTP代理端口 +isInboundPortChanged() = 是否已变更代理端口配置 +restart(.(editor,outbound) = 重启启动 V2Ray 服务进程 +lastDownloadingCoreFailed = 上次下载 Core 是否失败,如果希望重新下载请重新赋值为 null +end intellisense**/ diff --git a/lib/v2ray/core/configJson.aardio b/lib/v2ray/core/configJson.aardio new file mode 100644 index 0000000..adbef4a --- /dev/null +++ b/lib/v2ray/core/configJson.aardio @@ -0,0 +1,475 @@ +//configJson 内核配置 +import config; +import web.json; +import inet.url; +import crypt; + +namespace v2ray.core.configJson; + +write = function(jsonPath,outbound,sockPort,httpPort){ + if(!outbound){ return; } + if(type(outbound.port)!=type.number){ + outbound.port = tonumber(outbound.port); + } + + var currentCore = ..table.clone(..config.core.default); + if(! ..table.isArray(currentCore.outbounds) ){ + return null,"错误的出站代理服务器配置" + } + + var inboundsInCore = currentCore.inbounds; + if(! ..table.isArray(inboundsInCore) ){ + return null,"错误的入站代理服务器配置" + } + + var proxyOutboundInCore; + for(k,ob in currentCore.outbounds){ + if(ob.tag == "proxy"){ + proxyOutboundInCore = ob; + } + } + + if( type(proxyOutboundInCore) !="table" ){ + return null,"未找到默认出站代理服务器配置节点" + } + + var socksInbounds,httpInbounds; + for(k,ib in currentCore.inbounds){ + if(ib.tag == "proxy"){ + socksInbounds = ib; + socksInbounds.port = sockPort; + } + elseif(ib.tag == "http_proxy"){ + httpInbounds = ib; + httpInbounds.port = httpPort; + } + } + + if( type(socksInbounds) !="table" ){ + return null,"未找到默认 SOCKS 入站代理服务器配置节点" + } + + if( type(httpInbounds) !="table" ){ + return null,"未找到默认 HTTP 入站代理服务器配置节点" + } + + if(#outbound.tls && !outbound.sni){ + var host = outbound.host; + if(..table.isArray(host)){ host = host[1] } + outbound.sni = host ? host : outbound.address + } + + if(outbound.protocol=="vless"){ + if(!outbound.tls && outbound.port==443) outbound.tls = "tls"; + if(!outbound.tls) outbound.tls = "tls"; + + var mux = (outbound.concurrency !== null) ? { + concurrency=outbound.concurrency; + enabled=outbound.concurrency ? ( outbound.concurrency > 0) + } : { + concurrency=8; + enabled=true + }; + + var ob = { + mux = outbound.tls != "xtls" ? mux : null; + protocol="vless"; + + settings={ + vnext={ + { + address=outbound.address; + port=tonumber(outbound.port); + users={ + { + id=outbound.id; + flow=outbound.flow : (outbound.tls == "xtls" ? "xtls-rprx-direct" : null); + encryption=( (!#outbound.security) || outbound.security=="auto") ? "none" : outbound.security; + level=outbound.level : 0; + } + } + } + }; + }; + streamSettings={ + network=outbound.network : "tcp"; + security=#outbound.tls ? outbound.tls : null; + tlsSettings = (#outbound.tls && outbound.tls != "xtls") ? { + allowInsecure = !!outbound.allowInsecure; + serverName = outbound.sni : outbound.address; + alpn = outbound.alpn; + disableSessionResumption = outbound.disableSessionResumption; + } : null; + xtlsSettings = outbound.tls == "xtls" ? { + allowInsecure = !!outbound.allowInsecure; + serverName = outbound.sni : outbound.address; + alpn = outbound.alpn; + disableSessionResumption = outbound.disableSessionResumption; + } : null; + }; + tag="proxy" + }; + + if( outbound.network == "ws" ){ + ob.streamSettings.wsSettings = { + path = outbound.path; + headers = outbound.headers; + } + + if( outbound.host ) { + if(!ob.streamSettings.wsSettings.headers){ + ob.streamSettings.wsSettings.headers = {} + } + ob.streamSettings.wsSettings.headers.Host = outbound.host; + } + } + elseif( (outbound.network == "http") || (outbound.network == "h2") ){ + var host = outbound.host; + if(type.isString(host)){host = {host}}; + + ob.streamSettings.httpSettings = { + path = outbound.path; + host = host; + } + } + elseif( outbound.network == "tcp" ){ + if( outbound.type == "http" ){ + ob.streamSettings.tcpSettings = { + header = { + request={ + headers=..table.assign({ + Connection={ + "keep-alive" + }; + Host=outbound.host; + Pragma="no-cache"; + ["Accept-Encoding"]={ + "gzip, deflate" + }; + ["User-Agent"]={ + "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36"; + "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46" + } + },outbound.headers); + method = outbound.httpMethod : "GET"; + path = outbound.path; + version="1.1" + }; + type="http"; + } + } + } + } + elseif( outbound.network == "kcp" ){ + ob.streamSettings.kcpSettings = { + congestion = outbound.congestion; + seed = outbound.seed; + mtu = outbound.mtu; + tti = outbound.tti; + uplinkCapacity = outbound.uplinkCapacity; + downlinkCapacity = outbound.downlinkCapacity; + readBufferSize = outbound.readBufferSize; + writeBufferSize = outbound.writeBufferSize; + header = { + type = outbound.type; + } + } + } + elseif( outbound.network == "quic" ){ + ob.streamSettings.kcpSettings = { + key = outbound.key; + security = outbound.security ? outbound.security : "none"; + header = { + type = outbound.type; + } + } + } + + ..table.assign(proxyOutboundInCore,ob); + } + elseif(outbound.protocol=="vmess"){ + if(!#outbound.security) outbound.security = "auto"; + + var ob = { + mux = (outbound.concurrency !== null) ? { + concurrency=outbound.concurrency; + enabled=outbound.concurrency ? ( outbound.concurrency > 0) + } : { + concurrency=8; + enabled=true + }; + protocol="vmess"; + settings={ + vnext={ + { + address=outbound.address; + level=outbound.level : null; + port=tonumber(outbound.port); + users={ + { + alterId=tonumber(outbound.alterId) : 0; + email=outbound.email : "t@t.tt"; + id=outbound.id; + security=outbound.security; + } + } + } + }; + }; + streamSettings={ + network=outbound.network : "tcp"; + security=#outbound.tls ? outbound.tls : null; + tlsSettings = #outbound.tls ? { + allowInsecure = !!outbound.allowInsecure; + serverName = outbound.sni; + } : null + }; + tag="proxy" + }; + + if( outbound.network == "ws" ){ + ob.streamSettings.wsSettings = { + path = outbound.path; + headers = outbound.headers; + } + + if( outbound.host ) { + if(!ob.streamSettings.wsSettings.headers){ + ob.streamSettings.wsSettings.headers = {} + } + ob.streamSettings.wsSettings.headers.Host = outbound.host; + } + } + elseif( (outbound.network == "http") || (outbound.network == "h2") ){ + var host = outbound.host; + if(type.isString(host)){host = {host}}; + + ob.streamSettings.httpSettings = { + path = outbound.path; + host = host; + } + } + elseif( outbound.network == "tcp" ){ + if( outbound.type == "http" ){ + ob.streamSettings.tcpSettings = { + header = { + request={ + headers=..table.assign({ + Connection={ + "keep-alive" + }; + Host=outbound.host; + Pragma="no-cache"; + ["Accept-Encoding"]={ + "gzip, deflate" + }; + ["User-Agent"]={ + "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36"; + "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46" + } + },outbound.headers); + method=outbound.httpMethod : "GET"; + path = outbound.path; + version="1.1" + }; + type="http"; + } + } + } + } + elseif( outbound.network == "kcp" ){ + ob.streamSettings.kcpSettings = { + congestion = outbound.congestion; + seed = outbound.seed; + mtu = outbound.mtu; + tti = outbound.tti; + uplinkCapacity = outbound.uplinkCapacity; + downlinkCapacity = outbound.downlinkCapacity; + readBufferSize = outbound.readBufferSize; + writeBufferSize = outbound.writeBufferSize; + header = { + type = outbound.type; + } + } + } + elseif( outbound.network == "quic" ){ + ob.streamSettings.kcpSettings = { + key = outbound.key; + security = outbound.security ? outbound.security : "none"; + header = { + type = outbound.type; + } + } + } + + ..table.assign(proxyOutboundInCore,ob); + } + elseif(outbound.protocol=="trojan" || outbound.protocol=="trojan-go"){ + outbound.tls = #outbound.tls ? outbound.tls : "tls"; + var ob = { + mux = (outbound.concurrency !== null) ? { + concurrency=outbound.concurrency; + enabled=outbound.concurrency ? ( outbound.concurrency > 0) + } : { + concurrency=-1; + enabled=false + }; + protocol="trojan"; + settings={ + servers={ + { + address=outbound.address; + email=outbound.email; + password=outbound.id; + port=outbound.port; + level=outbound.level : 0; + encryption=outbound.security; + flow=outbound.flow : (outbound.tls == "xtls" ? "xtls-rprx-direct" : null); + } + }; + }; + streamSettings={ + network = outbound.network : "tcp"; + security = #outbound.tls ? outbound.tls : "tls"; + + tlsSettings = (outbound.tls === "tls") ? { + allowInsecure = !!outbound.allowInsecure; + serverName = outbound.sni; + } : null + }; + tag="proxy" + }; + + if( outbound.network == "ws" ){ + ob.streamSettings.wsSettings = { + path = outbound.path; + headers = outbound.headers; + } + + if( outbound.host ) { + if(!ob.streamSettings.wsSettings.headers){ + ob.streamSettings.wsSettings.headers = {} + } + ob.streamSettings.wsSettings.headers.Host = outbound.host; + } + } + ..table.assign(proxyOutboundInCore,ob); + } + elseif(outbound.protocol=="shadowsocks"){ + var ob = { + mux = (outbound.concurrency !== null) ? { + concurrency=outbound.concurrency; + enabled=outbound.concurrency ? ( outbound.concurrency > 0) + } : { + concurrency=-1; + enabled=false + }; + protocol="shadowsocks"; + settings={ + servers={ + { + address=outbound.address; + level=outbound.level : 0; + method=outbound.security; + ota=!!outbound.ota; + password=outbound.id; + port=outbound.port; + } + }; + }; + streamSettings={ + network = outbound.network : "tcp"; + }; + tag="proxy" + }; + + ..table.assign(proxyOutboundInCore,ob); + } + elseif(outbound.protocol=="socks"){ + + var ob = { + mux = (outbound.concurrency !== null) ? { + concurrency=outbound.concurrency; + enabled=outbound.concurrency ? ( outbound.concurrency > 0) + } : { + concurrency=-1; + enabled=false + }; + protocol="socks"; + settings={ + servers={ + { + address=outbound.address; + port=outbound.port; + } + }; + }; + streamSettings={ + network = outbound.network : "tcp"; + }; + tag="proxy" + }; + + if(#outbound.id){ + var user,password = ..string.match(outbound.id,"([^\:]+)\:(.+)"); + if(user && password){ + ob.settings.servers[1].users = { + user = user; + password = password; + level = outbound.level : 0; + } + } + else{ + ob.settings.servers[1].users = { + user = outbound.id; + level = outbound.level : 0; + } + } + } + + ..table.assign(proxyOutboundInCore,ob); + } + elseif(outbound.protocol=="https" || outbound.protocol=="http"){ + + var ob = { + protocol="http"; + settings={ + servers={ + { + address=outbound.address; + port=outbound.port; + } + }; + }; + streamSettings={ + security = outbound.protocol=="https" ? "tls" : "none"; + tlsSettings = (outbound.protocol=="https") ? { + allowInsecure = !!outbound.allowInsecure; + } : null; + }; + tag="proxy" + }; + + if(#outbound.id){ + var user,password = ..string.match(outbound.id,"([^\:]+)\:(.+)"); + if(user && password){ + ob.settings.servers[1].users = { + user = user; + password = password; + } + } + else{ + ob.settings.servers[1].users = { + user = outbound.id; + } + } + } + + ..table.assign(proxyOutboundInCore,ob); + } + + ..string.save(jsonPath,..web.json.stringify(currentCore) ); + return jsonPath; +} + + \ No newline at end of file diff --git a/lib/v2ray/core/naive.aardio b/lib/v2ray/core/naive.aardio new file mode 100644 index 0000000..3a461b5 --- /dev/null +++ b/lib/v2ray/core/naive.aardio @@ -0,0 +1,252 @@ +//naive 内核进程(NaïveProxy) +import fsys; +import wsock.tcp.server; +import process.popen; +import config; + +namespace v2ray.core.naive; + +var prcsNaive; +import process.job.limitKill; +restart = function(editor,outbound,naiveSocksPort){ + + if(prcsNaive){ + prcsNaive.terminate(); + prcsNaive = null; + } + + var corePath = getPath(editor.hwnd); + if(!corePath){ return false,"启动失败,未找到 naive.exe"; } + + var extraHeaders=null; + if(outbound.headers){ + extraHeaders = ..web.joinHeaders(outbound.headers); + if(extraHeaders){ + extraHeaders = "--extra-headers=" + extraHeaders; + } + } + + var urlInfo = { + host = outbound.address; + port = outbound.port; + scheme = outbound.network; + } + + if(outbound.id){ + var u,p = ..string.match(outbound.id,"([^\:]+)\:([^\:]+)") + if(u && p){ + urlInfo.user = u; + urlInfo.password = p; + } + else { + urlInfo.user = outbound.id; + } + } + + var err; + prcsNaive,err = ..process.popen(corePath + ,corePath //必须补上这个参数 + ,"--listen=socks://127.0.0.1:"+naiveSocksPort + ,"--proxy="+ ..inet.url.stringify(urlInfo) + ,extraHeaders + ); + + if(!prcsNaive){ + ..publish("uiCommand.print",err:"启动 NaïveProxy Core 时遇到未知错误!"); + return; + } + else{ + ..publish("uiCommand.print","NaïveProxy Core 已启动,端口:" + naiveSocksPort); + } + prcsNaive.assignToJobObject(process.job.limitKill); + prcsNaive.codepage = 65001; + prcsNaive.logResponse(editor); + + return true; +} + +stop = function(){ + if(prcsNaive){ + prcsNaive.terminate(); + prcsNaive = null; + } +} + +var getNaiveCoreUrl = function(){ + var msgDlg = ..win.dlg.message(..mainForm); + var form = msgDlg.create('正在获取 NaïveProxy 最新版本',,true) + form.icon = '\uF1D8'; + form.progress.startProgress(50); + + var url,versionTag = ..win.invoke(function(){ + import process; + import inet.http; + var http = ..inet.http(); + var url = http.location("https://github.com/klzgrad/naiveproxy/releases/latest"); + http.close(); + + if(!url)return; + + var tag = ..string.match(url,"[^/]+$") + if(!tag || (tag=="latest")) return; + + return "https://github.com/klzgrad/naiveproxy/releases/download/" + + tag + "/naiveproxy-"+tag+"-win-" + (..process().isWow64() ? "x64" : "x86") + ".zip",tag + }); + + form.close(); + + return url,versionTag; +} + +downloadCore = function(){ + ..mainForm.disabled = true; + + var url,versionTag = getNaiveCoreUrl(); + var coreDir = getCoreDir(); + if(!url) { + ..publish("uiCommand.print","请下载 NaïveProxy 解压到以下目录内:"); + ..publish("uiCommand.print",coreDir); + + ..mainForm.disabled = false; + self.lastDownloadingCoreFailed = true; + return null; + } + + import zlib.httpFile; + if( ..zlib.httpFile.download(url,"正在下载 NaïveProxy " + ,..io.appData("/winXray/download/naive") + ,coreDir,,..mainForm.hwnd) ){ + + ..fsys.enum( coreDir, "naive.exe", + function(dir,filename,fullpath,findData){ + if(filename){ + ..fsys.copy(fullpath,..io.joinpath(coreDir, "naive.exe") ) + ..fsys.delete( ..fsys.getParentDir(fullpath) ) + return false; + } + } + ); + + ..mainForm.disabled = false; + self.lastDownloadingCoreFailed = null; + + return ..io.exist(..io.joinpath(coreDir,"naive.exe")); + } + else { + ..mainForm.disabled = false; + self.lastDownloadingCoreFailed = true; + + ..publish("uiCommand.print","请到以下网址下载 NaïveProxy:"); + ..publish("uiCommand.print",url); + + ..publish("uiCommand.print","下载后请解压到以下目录内:"); + ..publish("uiCommand.print",coreDir); + } +} + + +getPath = function(hwnd){ + var path = ..io.fullpath("/v2ray-core/naive-core/naive.exe"); + if(..io.exist(path)){ + return path; + } + + var path = ..io.appData("/winXray/naive-core/naive.exe"); + if(..io.exist(path)){ + return path; + } + + if(self.lastDownloadingCoreFailed){ + return; + } + + return downloadCore(); +} + +getCoreDir = function(hwnd){ + var path = ..io.fullpath("/v2ray-core/naive-core/naive.exe"); + if(..io.exist(path)){ + return ..io.fullpath("/v2ray-core/naive-core/"); + } + + var path = ..io.appData("/winXray/naive-core/naive.exe"); + if(..io.exist(path)){ + return ..io.appData("/winXray/naive-core/");;; + } + + var path = ..io.fullpath("/v2ray-core/v2ray.exe"); + if(..io.exist(path)){ + return ..io.fullpath("/v2ray-core/naive-core/"); + } + + var path = ..io.appData("/winXray/core/v2ray.exe"); + if(..io.exist(path)){ + return ..io.appData("/winXray/naive-core/"); + } + + var path = ..io.fullpath("/v2ray-core/"); + if(..io.exist(path)){ + return ..io.fullpath("/v2ray-core/naive-core/"); + } + + return ..io.appData("/winXray/naive-core/"); +} + +updateCore = function(){ + ..mainForm.disabled = true; + + var coreDir = getCoreDir(); + var url,versionTag = getNaiveCoreUrl(); + if(!url){ + ..mainForm.disabled = false; + self.lastDownloadingCoreFailed = true; + return null; + } + + import fsys; + fsys.delete(..io.appData("/v2ray/temp/naive/")) + + import zlib.httpFile; + if( ..zlib.httpFile.download(url,"正在下载 NaïveProxy,版本:" + versionTag + ,..io.appData("/winXray/download/naive/") + ,..io.appData("/winXray/temp/naive/"),,..mainForm.hwnd) ){ + ..mainForm.disabled = false; + + var naivePath; + fsys.enum( ..io.appData("/winXray/temp/naive/"), "naive.exe", + function(dir,filename,fullpath,findData){ + if(filename){ + naivePath = fullpath; + return false; + } + } + ); + + if(naivePath){ + import sysProxy; + sysProxy.reset(false); + + import process.file; + process.file.terminate(..io.joinpath(coreDir,"naive.exe")); + + ..io.createDir(coreDir); + fsys.copy(naivePath,..io.joinpath(coreDir,"naive.exe")); + + return versionTag; + } + else { + self.lastDownloadingCoreFailed = true; + } + } + else { + ..mainForm.disabled = false; + self.lastDownloadingCoreFailed = true; + } +} + +/**intellisense(v2ray.core.naive) +restart(.(editor,outbound) = 重启启动 NaïveProxy 服务进程 +lastDownloadingCoreFailed = 上次下载 Core 是否失败,如果希望重新下载请重新赋值为 null +end intellisense**/ + diff --git a/lib/v2ray/core/rules.aardio b/lib/v2ray/core/rules.aardio new file mode 100644 index 0000000..02dbfa5 --- /dev/null +++ b/lib/v2ray/core/rules.aardio @@ -0,0 +1,66 @@ +//rules 路由规则 +import v2ray.core; +namespace v2ray.core.rules; + +var getRulesUrl = function(){ + var msgDlg = ..win.dlg.message(..mainForm); + var form = msgDlg.create('正在获取路由规则最新版本',,true) + form.icon = '\uF1D8'; + form.progress.startProgress(50); + + var url,tag = ..win.invoke(function(){ + import process; + import inet.http; + var http = ..inet.http(); + var url = http.location("https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest"); + http.close(); + + if(!url) return; + + var tag = ..string.match(url,"[^/]+$") + if(!tag || (tag=="latest")) return;; + + return "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/download/" + + tag + "/rules.zip",tag + }); + form.close(); + + return url,tag; +} + + +update = function(){ + ..mainForm.disabled = true; + + var coreDir = ..v2ray.core.getCoreDir(); + var url,versionTag = getRulesUrl(); + if(!url){ + ..mainForm.disabled = false; + return null; + } + + import fsys; + fsys.delete( ..io.appData("/winXray/temp/rules/") ); + + import zlib.httpFile; + if( ..zlib.httpFile.download(url,"正在下载最新路由规则,版本:" + versionTag + ,..io.appData("/winXray/download/") + ,..io.appData("/winXray/temp/rules/"),,..mainForm.hwnd) ){ + ..mainForm.disabled = false; + + if(..io.exist(..io.appData("/winXray/temp/rules/geoip.dat"))){ + + ..io.createDir(coreDir); + fsys.copy(..io.appData("/winXray/temp/rules/*.*"),coreDir); + return versionTag; + } + } + else { + ..mainForm.disabled = false; + } +} + +check = function(){ + var coreDir = ..v2ray.core.getCoreDir(); + if(!..io.exist( ..io.joinpath(coreDir,"geoip.dat") ) ) return update(); +} \ No newline at end of file diff --git a/lib/v2ray/core/ssr.aardio b/lib/v2ray/core/ssr.aardio new file mode 100644 index 0000000..281b882 --- /dev/null +++ b/lib/v2ray/core/ssr.aardio @@ -0,0 +1,211 @@ +//ssr 内核进程(SSR) +import wsock.tcp.server; +import v2ray.core.ssrJson; +import process.popen; +import config; + +namespace v2ray.core.ssr; + +var prcsSsr; +import process.job.limitKill; +restart = function(editor,outbound,ssrSocksPort){ + + if(prcsSsr){ + prcsSsr.terminate(); + prcsSsr = null; + } + + var corePath = getPath(editor.hwnd); + if(!corePath){ return false,"启动失败,未找到 ssr-client.exe"; } + + import v2ray.core.ssrJson; + var jsonPath,err = ..v2ray.core.ssrJson.write( + ..io.joinpath(..io.splitpath(corePath).dir,"config.json") + ,outbound,ssrSocksPort); + + if(!jsonPath){ + return false,err:"启动失败,写入 SSR 配置文件遇到错误!"; + } + + + var err; + prcsSsr,err = ..process.popen(corePath," -c=config.json" ); + if(!prcsSsr){ + ..publish("uiCommand.print",err:"启动 SSR Core 时遇到未知错误!"); + return; + } + else{ + ..publish("uiCommand.print","SSR Core 已启动,端口:" + ssrSocksPort); + } + prcsSsr.assignToJobObject(process.job.limitKill); + prcsSsr.codepage = 65001; + prcsSsr.logResponse(editor); + + return true; +} + +stop = function(){ + if(prcsSsr){ + prcsSsr.terminate(); + prcsSsr = null; + } +} + +var getSsrCoreUrl = function(){ + var msgDlg = ..win.dlg.message(..mainForm); + var form = msgDlg.create('正在获取SSR Core(ShadowsocksR-native)最新版本',,true) + form.icon = '\uF1D8'; + form.progress.startProgress(50); + + var url,versionTag = ..win.invoke(function(){ + import process; + import inet.http; + var http = ..inet.http(); + var url = http.location("https://github.com/ShadowsocksR-Live/shadowsocksr-native/releases/latest"); + http.close(); + + if(!url)return; + + var tag = ..string.match(url,"[^/]+$") + if(!tag || (tag=="latest")) return; + + return "https://github.com/ShadowsocksR-Live/shadowsocksr-native/releases/download/" + + tag + "/ssr-native-windows-" + (..process().isWow64() ? "x64" : "x86") + ".zip",tag + }); + + form.close(); + + return url,versionTag; +} + +downloadCore = function(){ + ..mainForm.disabled = true; + + var url,versionTag = getSsrCoreUrl(); + var coreDir = getCoreDir(); + if(!url) { + ..publish("uiCommand.print","请下载 SSR Core(ShadowsocksR-native)解压到以下目录内:"); + ..publish("uiCommand.print",coreDir); + + ..mainForm.disabled = false; + self.lastDownloadingCoreFailed = true; + return null; + } + + import zlib.httpFile; + if( ..zlib.httpFile.download(url,"正在下载 SSR Core(ShadowsocksR-native)" + ,..io.appData("/winXray/download/ssr") + ,coreDir,,..mainForm.hwnd) ){ + + ..mainForm.disabled = false; + self.lastDownloadingCoreFailed = null; + + return ..io.exist(..io.joinpath(coreDir,"ssr-client.exe")); + } + else { + ..mainForm.disabled = false; + self.lastDownloadingCoreFailed = true; + + ..publish("uiCommand.print","请到以下网址下载 SSR Core:"); + ..publish("uiCommand.print",url); + + ..publish("uiCommand.print","下载后请解压到以下目录内:"); + ..publish("uiCommand.print",coreDir); + } +} + + +getPath = function(hwnd){ + var path = ..io.fullpath("/v2ray-core/ssr-core/ssr-client.exe"); + if(..io.exist(path)){ + return path; + } + + var path = ..io.appData("/winXray/ssr-core/ssr-client.exe"); + if(..io.exist(path)){ + return path; + } + + if(self.lastDownloadingCoreFailed){ + return; + } + + + return downloadCore(); +} + +getCoreDir = function(hwnd){ + var path = ..io.fullpath("/v2ray-core/ssr-core/ssr-client.exe"); + if(..io.exist(path)){ + return ..io.fullpath("/v2ray-core/ssr-core/"); + } + + var path = ..io.appData("/winXray/ssr-core/ssr-client.exe"); + if(..io.exist(path)){ + return ..io.appData("/winXray/ssr-core/");;; + } + + var path = ..io.fullpath("/v2ray-core/v2ray.exe"); + if(..io.exist(path)){ + return ..io.fullpath("/v2ray-core/ssr-core/"); + } + + var path = ..io.appData("/winXray/core/v2ray.exe"); + if(..io.exist(path)){ + return ..io.appData("/winXray/ssr-core/"); + } + + var path = ..io.fullpath("/v2ray-core/"); + if(..io.exist(path)){ + return ..io.fullpath("/v2ray-core/ssr-core/"); + } + + return ..io.appData("/winXray/ssr-core/"); +} + +updateCore = function(){ + ..mainForm.disabled = true; + + var coreDir = getCoreDir(); + var url,versionTag = getSsrCoreUrl(); + if(!url){ + ..mainForm.disabled = false; + self.lastDownloadingCoreFailed = true; + return null; + } + + import fsys; + fsys.delete(..io.appData("/v2ray/temp/ssr/")) + + import zlib.httpFile; + if( ..zlib.httpFile.download(url,"正在下载 SSR Core(ShadowsocksR-native),版本:" + versionTag + ,..io.appData("/winXray/download/ssr/") + ,..io.appData("/winXray/temp/ssr/"),,..mainForm.hwnd) ){ + ..mainForm.disabled = false; + + if(..io.exist(..io.appData("/winXray/temp/ssr/ssr-client.exe"))){ + import sysProxy; + sysProxy.reset(false); + + import process.file; + process.file.terminate(..io.joinpath(coreDir,"ssr-client.exe")); + + ..io.createDir(coreDir); + fsys.copy(..io.appData("/winXray/temp/ssr/*.*"),coreDir); + + return versionTag; + } + else { + self.lastDownloadingCoreFailed = true; + } + } + else { + ..mainForm.disabled = false; + self.lastDownloadingCoreFailed = true; + } +} + +/**intellisense(v2ray.core.ssr) +restart(.(editor,outbound) = 重启启动 SSR 服务进程 +lastDownloadingCoreFailed = 上次下载 Core 是否失败,如果希望重新下载请重新赋值为 null +end intellisense**/ diff --git a/lib/v2ray/core/ssrJson.aardio b/lib/v2ray/core/ssrJson.aardio new file mode 100644 index 0000000..b76ccc4 --- /dev/null +++ b/lib/v2ray/core/ssrJson.aardio @@ -0,0 +1,40 @@ +//ssrJson 内核配置(SSR) +import web.json; + +namespace v2ray.core.ssrJson; + +write = function(jsonPath,outbound,ssrSocksPort){ + if(!outbound){ return; } + if(type(outbound.port) != type.number){ + outbound.port = tonumber(outbound.port); + } + + var current = { + client_settings = { + listen_address = "127.0.0.1"; + listen_port = ssrSocksPort; + server = outbound.address; + server_port = outbound.port + }; + connect_timeout = 6; + idle_timeout = 300; + method = outbound.security; + obfs = outbound.obfs : "plain"; + obfs_param = outbound.obfsParam:""; + over_tls_settings = { + enable = outbound.tls == "tls"; + path = outbound.path: "/abcd1234/"; + server_domain = outbound.sni : ""; + }; + password = outbound.id; + protocol = outbound.network : "origin"; + protocol_param = outbound.networkParam:""; + udp= outbound.udp === null? true : outbound.udp; + udp_timeout=6 + } + + ..string.save(jsonPath,..web.json.stringify(current) ); + return jsonPath; +} + + \ No newline at end of file diff --git a/lib/v2ray/core/xray.aardio b/lib/v2ray/core/xray.aardio new file mode 100644 index 0000000..4a12b09 --- /dev/null +++ b/lib/v2ray/core/xray.aardio @@ -0,0 +1,76 @@ +//xray 内核 +import v2ray.core; +namespace v2ray.core.xray; + +var getXrayCoreUrl = function(){ + var msgDlg = ..win.dlg.message(..mainForm); + var form = msgDlg.create('正在获取 XRay Core 最新版本',,true) + form.icon = '\uF1D8'; + form.progress.startProgress(50); + + var url,tag = ..win.invoke(function(){ + import process; + import inet.http; + var http = ..inet.http(); + var url = http.location("https://github.com/XTLS/Xray-core/releases/latest"); + http.close(); + + if(!url) return; + + var tag = ..string.match(url,"[^/]+$") + if(!tag || (tag=="latest")) return;; + + return "https://github.com/XTLS/Xray-core/releases/download/" + + tag + "/Xray-windows-" + (..process().isWow64() ? "64" : "32") + ".zip",tag + }); + form.close(); + + return url,tag; +} + + +updateCore = function(){ + ..mainForm.disabled = true; + + var coreDir = ..v2ray.core.getCoreDir(); + var url,versionTag = getXrayCoreUrl(); + if(!url){ + ..mainForm.disabled = false; + self.lastDownloadingCoreFailed = true; + return null; + } + + import fsys; + fsys.delete( ..io.appData("/winXray/temp/xray/") ); + + + import zlib.httpFile; + if( ..zlib.httpFile.download(url,"正在下载 Xray Core,版本:" + versionTag + ,..io.appData("/winXray/download/") + ,..io.appData("/winXray/temp/xray/"),,..mainForm.hwnd) ){ + ..mainForm.disabled = false; + + if(..io.exist(..io.appData("/winXray/temp/xray/xray.exe"))){ + import sysProxy; + sysProxy.reset(false); + + import process.file; + process.file.terminate(..io.joinpath(coreDir,"v2ray.exe")); + process.file.terminate(..io.joinpath(coreDir,"v2ctl.exe")); + fsys.delete(..io.joinpath(coreDir,"v2ctl.exe")); + + ..io.createDir(coreDir); + fsys.copy(..io.appData("/winXray/temp/xray/xray.exe"),..io.joinpath(coreDir,"v2ray.exe")); + + self.lastDownloadingCoreFailed = null; + return versionTag; + } + else { + self.lastDownloadingCoreFailed = true; + } + } + else { + ..mainForm.disabled = false; + self.lastDownloadingCoreFailed = true; + } +} \ No newline at end of file diff --git a/lib/v2ray/github.aardio b/lib/v2ray/github.aardio new file mode 100644 index 0000000..7f94965 --- /dev/null +++ b/lib/v2ray/github.aardio @@ -0,0 +1,46 @@ +//github 代理设置 +import v2ray.core; +import process.popen; +namespace v2ray.github; + +setProxy = function(enableProxy){ + if(enableProxy===null){ + enableProxy = (..config.proxy.mode === "pac") || (..config.proxy.mode === "proxy") + + if(!..config.proxy.enableGitConfigGithub){ + return; + } + } + + var socksPort = ..v2ray.core.socksProxyPort; + if(!socksPort && enableProxy) return; + + var git; + if(enableProxy){ + git = ..process.popen("git config --global http.https://github.com.proxy socks5://127.0.0.1:" + socksPort) + + var path = ..io.getSpecial(0x28/*_CSIDL_PROFILE*/,".ssh/config") + var str = ..string.load(path):""; + if(..string.find(str,"Host\s+github.com" ) ){ + if(!..string.find(str,"Host\s+github.com\s+ProxyCommand\s+connect\s+\-S\s+127\.0\.0\.1\:\d+ \-a none \%h \%p" )){ + str = ..string.replace(str,"Host\s+github.com",'Host github.com\r\n ProxyCommand connect -S 127.0.0.1:' + socksPort + ' -a none %h %p') + } + } + else { + str = str + '\r\n\r\nHost github.com\r\n ProxyCommand connect -S 127.0.0.1:' + socksPort + ' -a none %h %p' + } + + ..string.save(path,str) + } + else { + git = ..process.popen("git config --global --unset http.https://github.com.proxy") + var path = ..io.getSpecial(0x28/*_CSIDL_PROFILE*/,".ssh/config") + var str = ..string.load(path):""; + if(..string.find(str,"Host\s+github.com" ) ){ + if(..string.find(str,"Host\s+github.com\s+ProxyCommand\s+connect\s+\-S\s+127\.0\.0\.1\:\d+ \-a none \%h \%p" )){ + str = ..string.replace(str,"Host\s+github.com\s+ProxyCommand\s+connect\s+\-S\s+127\.0\.0\.1\:\d+ \-a none \%h \%p",'Host github.com') + ..string.save(path,str) + } + } + } +} \ No newline at end of file diff --git a/lib/v2ray/outbounds.aardio b/lib/v2ray/outbounds.aardio new file mode 100644 index 0000000..032b56e --- /dev/null +++ b/lib/v2ray/outbounds.aardio @@ -0,0 +1,1148 @@ +//outbounds 出站代理 +import web.json; +import inet.url; +import win.clip; +import crypt; +import crypt.bin; + +namespace v2ray.outbounds; + +exportSharedLinks = function(outbounds){ + var outString = {}; + for i,outbound in ..table.eachIndex(outbounds){ + if(outbound.protocol == "vmess"){ + var json = ..web.json.stringify({ + v = 2; + add = outbound.address; + aid = outbound.alterId; + id = outbound.id; + port = outbound.port; + net = outbound.network; + type = outbound.type; + path = outbound.path; + host = outbound.host; + tls = outbound.tls; + ps = outbound.ps; + }) + + var vmess = "vmess://" + ..crypt.encodeBin(json); + ..table.push(outString,vmess); + } + elseif(outbound.protocol == "shadowsocks"){ + var ss = "ss://" + ..crypt.encodeBin( outbound.security + ":" + outbound.id + "@" + outbound.address + ":" + outbound.port) + "#" + outbound.address + ":" + outbound.port; + ..table.push(outString,ss); + } + elseif(outbound.protocol == "socks"){ + var ss; + if(outbound.id) ss = outbound.protocol + "://" + ..inet.url.encode(outbound.id) + "@" + outbound.address + ":" + outbound.port; + else ss = outbound.protocol + "://" + outbound.address + ":" + outbound.port; + ..table.push(outString,ss); + } + elseif(outbound.protocol == "ssr" ){ + var ssrUrl = outbound.address + ":" + outbound.port + + ":" + (outbound.network:"origin")+ ":" + (outbound.security:"")+ ":" + (outbound.obfs:"plain") + + ":" + ..crypt.bin.encodeUrlBase64(outbound.id:""); + + var info = {}; + + if(#outbound.ps)info.remarks = ..crypt.bin.encodeUrlBase64(outbound.ps); + if(#outbound.obfsParam)info.obfsparam = ..crypt.bin.encodeUrlBase64(outbound.obfsParam); + if(#outbound.networkParam)info.protoparam = ..crypt.bin.encodeUrlBase64(outbound.networkParam); + + if(#outbound.path)info.ot_path = ..crypt.bin.encodeUrlBase64(outbound.path); + if(#outbound.sni)info.ot_domain = ..crypt.bin.encodeUrlBase64(outbound.sni); + if(outbound.tls=="tls"){ info.ot_enable = "1"; } + + if(..table.count(info)){ + ssrUrl = ssrUrl +"/?"+ ..inet.url.stringifyParameters(info) + } + + ..table.push(outString,outbound.protocol + "://" + ..crypt.encodeBin(ssrUrl) ); + } + elseif(outbound.protocol == "trojan" || outbound.protocol == "trojan-go"){ + var trojan; + if(outbound.id) trojan = outbound.protocol + "://" + ..inet.url.encode(outbound.id) + "@" + outbound.address + ":" + outbound.port; + else trojan = outbound.protocol + "://" + outbound.address + ":" + outbound.port; + + var info = {}; + if(outbound.network!="tcp") info.type = outbound.network; + if(outbound.sni){ info.sni = outbound.sni;} + info.host = outbound.host; + info.path = outbound.path; + + if(..table.count(info)){ + trojan = ..inet.url.appendExtraInfo(trojan,info) + } + + if(outbound.ps){ + trojan = trojan + "#" + ..inet.url.encode(outbound.ps); + } + ..table.push(outString,trojan); + } + elseif(outbound.protocol == "vless"){ + var vless; + if(outbound.id) vless = "vless://" + ..inet.url.encode(outbound.id) + "@" + outbound.address + ":" + outbound.port; + else vless = "vless://" + outbound.address + ":" + outbound.port; + + var info = {}; + if(outbound.network!="tcp") info.type = outbound.network ; + if(outbound.security!="none") info.encryption = outbound.security; + if(outbound.tls) info.security = outbound.tls; + if(outbound.flow) info.flow = outbound.flow; + if(outbound.allowInsecure) info.allowInsecure = outbound.allowInsecure; + if(outbound.alpn) info.alpn = outbound.alpn; + if(outbound.disableSessionResumption) info.disableSessionResumption = outbound.disableSessionResumption; + if(outbound.sni){ info.sni = outbound.sni;} + info.host = outbound.host; + info.path = outbound.path; + info.seed = info.seed; + info.key = info.key; + info.headerType = info.type; + + if(..table.count(info)){ + vless = ..inet.url.appendExtraInfo(vless,info) + } + + if(outbound.ps){ + vless = vless + "#" + ..inet.url.encode(outbound.ps); + } + ..table.push(outString,vless); + } + elseif(outbound.protocol == "naive"){ + var urlInfo = { + host = outbound.address; + port = outbound.port; + scheme = "naive+"+outbound.network; + location = outbound.ps; + } + + if(outbound.headers){ + urlInfo.extraInfo ={ + ["extra-headers"] = outbound.headers + } + } + + if(outbound.id){ + var u,p = ..string.match(outbound.id,"([^\:]+)\:([^\:]+)") + if(u && p){ + urlInfo.user = u; + urlInfo.password = p; + } + else { + urlInfo.user = outbound.id; + } + } + + ..table.push(outString,..inet.url.stringify(urlInfo)); + } + elseif((outbound.protocol == "https") || (outbound.protocol == "http")){ + var urlInfo = { + host = outbound.address; + port = outbound.port; + scheme = "proxy"; + location = outbound.ps; + } + + if(outbound.protocol == "http"){ + urlInfo.extraInfo ={ + ["tls"] = "none" + } + } + elseif(outbound.allowInsecure){ + urlInfo.extraInfo ={ + ["allowInsecure"] = 1 + } + } + + if(outbound.id){ + var u,p = ..string.match(outbound.id,"([^\:]+)\:([^\:]+)") + if(u && p){ + urlInfo.user = u; + urlInfo.password = p; + } + else { + urlInfo.user = outbound.id; + } + } + + ..table.push(outString,..inet.url.stringify(urlInfo)); + } + } + + return ..string.join(outString,'\r\n'); +} + +var _subscriptionResponseCache = { + @{_weak="kv"} +} +importFromString = function(str,subscribeUrl){ + if(!str){ return; } + str = ..string.trim(str); + + var jsonData; + if(..string.match(str,"%\[\]") || ( + ..string.match(str,"%\{\}") && !..string.match(str,"%\{\}.+%\{\}") + ) ){ + + if(subscribeUrl){ + var crc32 = ..string.crc32(str); + _subscriptionResponseCache[subscribeUrl] = crc32; + } + jsonData = ..web.json.tryParse(str); + } + + if( ..table.isArray(jsonData) ){ + for(i=#jsonData;1;-1){ + if( !validOutbound(jsonData[i]) ) { + ..table.remove(jsonData,i); + } + + if(subscribeUrl)jsonData[i].subscribeUrl = subscribeUrl; + } + + return jsonData; + } + elseif( type(jsonData) == type.table ){ + if( jsonData[["servers"]] ){ + + var servers = jsonData[["servers"]] + var outbounds = ..table.array(); + for i,v in ..table.eachIndex(servers){ + var outbound = ..table.assign(,v); + if(outbound.protocol === null){ + outbound.protocol = (outbound.server_port&&outbound.password) ? "shadowsocks":"vless" + } + + if(outbound.remarks){ + outbound.ps = outbound.remarks; + outbound.remarks = null; + } + + if(outbound.server){ + outbound.address = outbound.server; + outbound.server = null; + } + + if(outbound.server_port){ + outbound.port = outbound.server_port; + outbound.server_port = null; + } + + if(outbound.password){ + if(outbound.id){ + outbound.serverId = outbound.id; + } + outbound.id = outbound.password; + outbound.password = null; + } + + if(outbound.method){ + outbound.security = outbound.method; + outbound.method = null; + } + + if(subscribeUrl)outbound.subscribeUrl = subscribeUrl; + ..table.push(outbounds,outbound); + } + + return outbounds; + } + else { + if( validOutbound(jsonData) ) { + if(subscribeUrl)jsonData.subscribeUrl = subscribeUrl; + return {jsonData}; + } + } + } + + if( ..string.startWith(str,"http://") + || ..string.startWith(str,"https://") + || ..string.match(str,"^\s*/\N+\s*$") ){ + + import win.dlg.message; + var msgDlg = win.dlg.message(..mainForm); + + var title = '正在获取订阅源 ... '; + var cfgSubscribeUrls = ..config.proxy.subscribeUrls; + for(i=#cfgSubscribeUrls;1;-1){ + var sub = cfgSubscribeUrls[i] + if( (sub.url === str) ){ + if(#sub.ps) title = '正在获取订阅源: ' + sub.ps; + ..config.proxy.save(); + } + } + + var form = msgDlg.create(title,,true) + form.progress.startProgress(50); + + subscribeUrl = str; + + if(..string.match(subscribeUrl,"^\s*/\N+\s*$") ){ + if(!..string.find(subscribeUrl,"/|")){ + subscribeUrl = ..inet.url.append("https://raw.githubusercontent.com",subscribeUrl); + } + else { + subscribeUrl = ..inet.url.append("https://github.com",subscribeUrl); + } + } + + str = ..win.invoke( + function(subscribeUrl){ + import inet.http; + import web.rest.github; + if( string.indexOf(subscribeUrl,"github.com") + || string.indexOf(subscribeUrl,"raw.githubusercontent.com") + ){ + + var ret = web.rest.github.getContent(subscribeUrl) + if(ret) return ret; + } + + return inet.http().get(subscribeUrl); + },subscribeUrl + ) + + form.close(); + if(!str){ + return; + } + + var existIndex; + var cfgSubscribeUrls = ..config.proxy.subscribeUrls : ..table.array(); + for(i=#cfgSubscribeUrls;1;-1){ + var sub = cfgSubscribeUrls[i] + if(sub.url==subscribeUrl){ + sub.checked="启用"; + existIndex=i; + break; + } + } + if(!existIndex){ + var tUrl = ..inet.url.split(subscribeUrl); + ..table.push(cfgSubscribeUrls,{url=subscribeUrl;ps=tUrl ? tUrl.host : "";checked="启用"}) + ..publish("uiCommand.subscriptionNew",cfgSubscribeUrls[#cfgSubscribeUrls]); + } + else{ + ..publish("uiCommand.subscriptionNew",cfgSubscribeUrls[existIndex],existIndex); + } + ..config.proxy.subscribeUrls = cfgSubscribeUrls; + ..config.proxy.save(); + + var jsonData; + if(..string.match(str,"%\[\]") || ..string.match(str,"%\{\}")){ + jsonData = ..web.json.tryParse(str); + } + + if( type(jsonData) === type.table ){ + return importFromString(str,subscribeUrl); + } + } + + if(subscribeUrl){ + var crc32 = ..string.crc32(str); + _subscriptionResponseCache[subscribeUrl] = crc32; + } + + if(..string.match(str,"^\s*[\w=+/-_]+\s*$")){ + str = ..crypt.decodeBin(str); + if(!str) return; + } + + var outbounds = ..table.array(); + for(line in ..string.lines(str) ){ + if(#outbounds>=1500){ + import win.dlg.message; + var msgDlg = win.dlg.message(..mainForm); + var form = msgDlg.warn("导入的节点数目过多,已导入1500个节点并中止操作!") + + return outbounds; + } + + if(line[1]=='/'# && line[2]=='/'#){ + continue; + } + + var vmess2 = ..string.match(line,`vmess\:\/\/[^\@\s]+\@[^\?\#\s\:]+<\:\d+>*\S*`); + if( vmess2 ) { + var vmessUrl = ..inet.url.split(vmess2) + if(vmessUrl.user && vmessUrl.host && vmessUrl.port){ + var outbound = { + address = vmessUrl.host; + port = tonumber(vmessUrl.port) : 443; + id = vmessUrl.user; + network = "tcp"; + protocol = "vmess"; + tls = "tls"; + }; + + if(vmessUrl.extraInfo){ + var info = ..inet.url.splitParameters(vmessUrl.extraInfo); + outbound.sni = info.sni; + outbound.host = info.host; + outbound.path = info.path; + outbound.security = info.encryption; + outbound.seed = info.seed; + outbound.key = info.key; + + outbound.network = info.type; + outbound.type = info.headerType; //kcp || quic + + if(info.security) outbound.tls = info.security; + if(info.flow) outbound.flow = info.flow; + if(info.allowInsecure!==null) { + outbound.allowInsecure = (info.allowInsecure!=="0" ||info.allowInsecure!=="false" ) + } + if(info.disableSessionResumption) outbound.disableSessionResumption = info.disableSessionResumption; + if(info.alpn) outbound.alpn = info.alpn; + } + + if(vmessUrl.location){ + outbound.ps = ..inet.url.decode(vmessUrl.location); + } + + outbound.subscribeUrl = subscribeUrl; + ..table.push(outbounds,outbound); + } + + continue; + } + + var vmess = ..string.match(line,`vmess\:\/\/([\w=+/-_]+)`); + if( vmess ) { + var json = ..crypt.decodeBin(vmess); + var outbound = ..web.json.tryParse(json); + if(type(outbound)=="table"){ + ..table.clear(outbound@._defined); + outbound.protocol = "vmess"; + outbound.address = outbound.add; + outbound.alterId = tonumber(outbound.aid); + outbound.security = "auto"; + outbound.network = outbound.net : "tcp"; + outbound.net = null; + outbound.add = null; + outbound.aid = null; + outbound.v = null; + outbound.subscribeUrl = subscribeUrl; + + if(outbound.ps){ + var u,h,p = ..string.match(outbound.ps,"(.+)\@(.+)\:(\d+)") + if(u&&h&&p){ + if(h && ..string.endWith(h,"jamjams.net") && subscribeUrl && ..string.match(subscribeUrl,"justmysocks\d+\.net")){ + if(..string.match(outbound.address,"^\d+\.\d+\.\d+\.\d+$") ){ + outbound.address = h; + } + } + outbound.ps = h; + } + } + ..table.push(outbounds,outbound); + } + + continue; + } + + var vless = ..string.match(line,`vless\:\/\/\S+`); + if( vless ) { + var vlessUrl = ..inet.url.split(vless) + if(vlessUrl.user && vlessUrl.host && vlessUrl.port){ + var outbound = { + address = vlessUrl.host; + port = tonumber(vlessUrl.port) : 443; + id = vlessUrl.user; + network = "tcp"; + protocol = "vless"; + tls = "tls"; + }; + + if(vlessUrl.extraInfo){ + var info = ..inet.url.splitParameters(vlessUrl.extraInfo); + outbound.sni = info.sni; + outbound.host = info.host; + outbound.path = info.path; + outbound.security = info.encryption; + outbound.seed = info.seed; + outbound.key = info.key; + + outbound.network = info.type; + outbound.type = info.headerType; //kcp || quic + + if(info.security) outbound.tls = info.security; + if(info.flow) outbound.flow = info.flow; + if(info.allowInsecure!==null) { + outbound.allowInsecure = (info.allowInsecure!=="0" ||info.allowInsecure!=="false" ) + } + if(info.disableSessionResumption) outbound.disableSessionResumption = info.disableSessionResumption; + if(info.alpn) outbound.alpn = info.alpn; + } + + if(vlessUrl.location){ + outbound.ps = ..inet.url.decode(vlessUrl.location); + } + + outbound.subscribeUrl = subscribeUrl; + ..table.push(outbounds,outbound); + } + + continue; + } + + var ss,comment = ..string.match(line,`ss\:\/\/([^\s\#]+)(<#\S+>?)`); + if( ss ) { + var userinfo,address,port = ..string.match(ss,"^([^:]+)\@(.+)\:(\d+)") + if(!(userinfo&&address&&port)){ + var str = ..crypt.bin.decodeUrlBase64(ss); + if(str){ ss = str; } + + method,password,address,port = ..string.match(ss,"^(.+)\:(.+)\@(.+)\:(\d+)") + } + else { + userinfo = ..crypt.bin.decodeUrlBase64(userinfo); + if(userinfo){ + method,password = ..string.match(userinfo,"^(.+)\:(.+)$") + } + } + + if(address && password && port){ + var outbound = { + address = address; + port = tonumber(port); + security = method; + id = password; + network = "tcp"; + protocol = "shadowsocks" + }; + + if(comment){ + comment = ..string.right(comment,-2); + comment = ..inet.url.decode(comment); + var u,h,p = ..string.match(comment,"(.+)\@(.+)\:(\d+)") + if(u&&h&&p){ + if(h && ..string.endWith(h,"jamjams.net") && subscribeUrl && ..string.match(subscribeUrl,"justmysocks\d+\.net")){ + if(..string.match(outbound.address,"^\d+\.\d+\.\d+\.\d+$") ){ + outbound.address = h; + } + } + + comment = h; + } + + outbound.ps = comment; + } + + outbound.subscribeUrl = subscribeUrl; + ..table.push(outbounds,outbound); + } + + continue; + } + + var trojan = ..string.match(line,`trojan\:\/\/\S+`); + if( trojan ) { + var trojanUrl = ..inet.url.split(trojan) + if(trojanUrl.user && trojanUrl.host){ + var outbound = { + address = trojanUrl.host; + port = tonumber(trojanUrl.port) : 443; + id = trojanUrl.user; + network = "tcp"; + protocol = "trojan" + }; + + if(trojanUrl.extraInfo){ + var info = ..inet.url.splitParameters(trojanUrl.extraInfo); + outbound.sni = info.sni || info.peer; + + outbound.host = info.host; + outbound.path = info.path; + + if(info.type && info.type!=="original"){ + outbound.network = info.type; + if(outbound.network=="h2"){ + outbound.network="http" + } + } + + outbound.security = info.encryption; + } + + if(trojanUrl.location){ + outbound.ps = ..inet.url.decode(trojanUrl.location); + } + + outbound.subscribeUrl = subscribeUrl; + ..table.push(outbounds,outbound); + } + + continue; + } + + var trojan = ..string.match(line,`trojan-go\:\/\/\S+`); + if( trojan ) { + var trojanUrl = ..inet.url.split(trojan) + if(trojanUrl.user && trojanUrl.host){ + var outbound = { + address = trojanUrl.host; + port = tonumber(trojanUrl.port) : 443; + id = trojanUrl.user; + network = "tcp"; + protocol = "trojan-go" + }; + + if(trojanUrl.extraInfo){ + var info = ..inet.url.splitParameters(trojanUrl.extraInfo); + outbound.sni = info.sni || info.peer; + outbound.host = info.host; + outbound.path = info.path; + if(info.allowInsecure!==null) { + outbound.allowInsecure = (info.allowInsecure!=="0" ||info.allowInsecure!=="false" ) + } + + if(info.type && info.type!=="original"){ + outbound.network = info.type; + if(outbound.network=="h2"){ + outbound.network="http" + } + } + + outbound.security = info.encryption; + } + + if(trojanUrl.location){ + outbound.ps = ..inet.url.decode(trojanUrl.location); + } + + outbound.subscribeUrl = subscribeUrl; + ..table.push(outbounds,outbound); + } + + continue; + } + + var ssrBase64 = ..string.match(line,`ssr\:\/\/([\w=+/-_]+)`); + if( ssrBase64 ) { + var ssrUrl = ..crypt.bin.decodeUrlBase64(ssrBase64); + if(ssrUrl){ + var ssrInfo,ssrParam = ..string.match(ssrUrl,"(.+)\/\?(.+)") + var info = ..string.split(ssrInfo:ssrUrl,':'); + var outbound = { + address = info[1]; + port = info[2]; + network = info[3]; + security = info[4]; + obfs = info[5]; + protocol = "ssr"; + } + + outbound.id = ..crypt.bin.decodeUrlBase64(info[6]:""); + if(ssrParam){ + var params = ..inet.url.splitParameters(ssrParam); + if(params){ + outbound.ps = ..crypt.bin.decodeUrlBase64(params.remarks); + outbound.obfsParam = ..crypt.bin.decodeUrlBase64(params.obfsparam); + outbound.protoParam = ..crypt.bin.decodeUrlBase64(params.protoparam); + + if(params.group){ + //outbound.subscribeGroup = ..crypt.bin.decodeUrlBase64(params.group); + } + + if(params.ot_enable && (params.ot_enable!="0")){ outbound.tls = "tls"; } + outbound.path = ..crypt.bin.decodeUrlBase64(params.ot_path); + outbound.sni = ..crypt.bin.decodeUrlBase64(params.ot_domain); + } + } + + outbound.subscribeUrl = subscribeUrl; + + if(outbound.address && outbound.port){ + ..table.push(outbounds,outbound); + continue; + } + } + } + + var socks = ..string.match(line,`socks\:(\/\/\S+)`); + if( socks ) { + var socksUrl = ..inet.url.split("socks5:"+socks) + if( socksUrl.host && socksUrl.port){ + var outbound = { + address = socksUrl.host; + port = tonumber(socksUrl.port); + network = "tcp"; + protocol = "socks" + }; + + if(socksUrl.user && socksUrl.password){ + outbound.id = socksUrl.user +":"+ socksUrl.password + } + + if(socksUrl.location){ + outbound.ps = ..inet.url.decode(socksUrl.location); + } + + outbound.subscribeUrl = subscribeUrl; + ..table.push(outbounds,outbound); + } + + continue; + } + + var proxy = ..string.match(line,`proxy\:\/\/\S+`); + if( proxy ) { + var proxyUrl = ..inet.url.split(proxy) + if( proxyUrl.host && proxyUrl.port){ + var outbound = { + address = proxyUrl.host; + port = tonumber(proxyUrl.port); + network = "tcp"; + protocol = "https" + }; + + if(proxyUrl.user && proxyUrl.password){ + outbound.id = proxyUrl.user +":"+ proxyUrl.password + } + + if(proxyUrl.extraInfo){ + var info = ..inet.url.splitParameters(proxyUrl.extraInfo); + if(info.tls==="none") { + outbound.protocol = "http"; + } + + if(info.allowInsecure){ + outbound.allowInsecure = (info.allowInsecure!=="0" ||info.allowInsecure!=="false" ) + } + } + + if(proxyUrl.location){ + outbound.ps = ..inet.url.decode(proxyUrl.location); + } + + outbound.subscribeUrl = subscribeUrl; + ..table.push(outbounds,outbound); + } + + continue; + } + + var naive,naiveNetwork = ..string.match(line,`(naive\+(\w+)\:\/\/\S+)`); + if( naive ) { + var naiveUrl = ..inet.url.split(naive) + if( naiveUrl.host ){ + var outbound = { + address = naiveUrl.host; + port = tonumber(naiveUrl.port) : 443; + id = naiveUrl.user; + network = naiveNetwork; + protocol = "naive" + }; + + if(naiveUrl.user && naiveUrl.password){ + outbound.id = naiveUrl.user +":"+ naiveUrl.password + } + + if(naiveUrl.extraInfo){ + var info = ..inet.url.splitParameters(naiveUrl.extraInfo); + if(info["extra-headers"]){ + outbound.headers = info["extra-headers"]; + } + } + if(naiveUrl.location){ + outbound.ps = ..inet.url.decode(naiveUrl.location); + } + + outbound.subscribeUrl = subscribeUrl; + ..table.push(outbounds,outbound); + } + + continue; + } + + var clashJson = ..string.match(line,`^\s*-\s*(%\{\})\s*$`); + if( clashJson ) { + var outbound = ..web.json.tryParse(clashJson) + if(type(outbound)=="table"){ + if(outbound.type){ + if(outbound.type=="ssr"){ + outbound.network = outbound.protocol; + outbound.protocol = "ssr"; + + outbound.networkParam = outbound.protocol_param; + outbound.protocol_param = null; + + outbound.sni = outbound.ot_domain; + outbound.path = outbound.ot_path; + outbound.tls = outbound.ot_enable ? "tls" : null; + } + + if(outbound.type=="ss"){ + outbound.type = "shadowsocks"; + outbound.network = "tcp"; + } + outbound.protocol = outbound.type; + outbound.type = null; + } + + if( validOutbound(outbound) ){ + outbound.subscribeUrl = subscribeUrl; + ..table.push(outbounds,outbound ); + } + continue; + } + } + + var json = ..string.match(line,`^\s*%\{\}\s*$`); + if( json ) { + var outbound = ..web.json.tryParse(json) + if(type(outbound)=="table"){ + if( validOutbound(outbound) ) ..table.push(outbounds,outbound ); + continue; + } + } + } + + return outbounds; +} + +importFromClipboard = function(){ + var str = ..win.clip.read(); + if(!str){ return; } + + str = ..string.trim(str,'"\'\t\r\n '); + return importFromString(str); +} + +validAll = function(outbounds){ + for(i=#outbounds;1;-1){ + if(!validOutbound(outbounds[i])){ + ..table.remove(outbounds,i); + } + } + + return outbounds; +} + +validOutbound = function(outbound){ + if(type(outbound)!="table"){ return; } + + outbound.obfsParam = outbound.obfs_param; + outbound.obfs_param = null; + + if(outbound.aid){ + outbound.alterId = outbound.aid; + outbound.aid = null; + } + + if(outbound.add){ + outbound.address = outbound.add; + outbound.add = null; + ..table.define(outbound); + } + + if(outbound.net){ + outbound.network = outbound.net; + outbound.net = null; + ..table.define(outbound); + } + + if(outbound.peer ){ + if(#outbound.peer) outbound.sni = outbound.peer; + outbound.peer = null; + ..table.define(outbound); + } + + if(!outbound.security){ + if(outbound.method && outbound.method!="none"){ + outbound.security = outbound.method; + } + if(outbound.cipher && outbound.cipher!="none" && outbound.cipher!="auto"){ + outbound.security = outbound.cipher; + } + outbound.cipher = null; + outbound.method = null; + } + + if(!outbound.address){ + if(outbound.server){ + outbound.address = outbound.server; + outbound.server = null; + } + } + + if(!outbound.ps){ + if(outbound.remarks){ + outbound.ps = outbound.remarks; + outbound.remarks = null; + } + elseif(outbound.name){ + outbound.ps = outbound.name; + outbound.name = null; + } + } + + if(!outbound.port){ + if(outbound.server_port){ + outbound.port = outbound.server_port; + outbound.server_port = null; + + if(!outbound.protocol && outbound.password){ + outbound.protocol = "shadowsocks"; + } + } + else { + outbound.port=443; + } + } + + if(!outbound.protocol){ + outbound.protocol = "vmess"; + if(outbound.ps && (..string.find(outbound.ps,"@@vless") || ..string.find(outbound.ps,"@@xtls"))){ + outbound.protocol = "vless"; + } + } + + if(!outbound.id){ + if(outbound.password){ + outbound.id = outbound.password; + outbound.password = null; + } + if(outbound.uuid){ + outbound.id = outbound.uuid; + outbound.uuid = null; + } + } + + if(outbound["skip-cert-verify"]){ + outbound.allowInsecure = outbound["skip-cert-verify"]; + outbound["skip-cert-verify"] = null; + } + + if(outbound["ws-path"]){ + outbound.path = outbound["ws-path"]; + outbound["ws-path"] = null; + } + + if(outbound["ws-headers"]){ + outbound.headers = outbound["ws-headers"]; + outbound["ws-headers"] = null; + } + + if(type(outbound.tls)!="string"){ + if(outbound.tls) outbound.tls = "tls"; + else outbound.tls = ""; + } + + if(outbound.servername){ + outbound.host = outbound.servername; + outbound.servername = null; + } + + var httpOpts = outbound["http-opts"]; + if(httpOpts){ + if(!..table.count(httpOpts)){ + httpOpts = outbound["h2-opts"] : httpOpts; + } + + if(httpOpts.method){ + outbound.httpMethod = httpOpts.method; + } + + if(httpOpts.path){ + outbound.path = httpOpts.path; + } + + if(httpOpts.headers){ + outbound.headers = httpOpts.headers; + } + + if(httpOpts.host){ + outbound.host = httpOpts.host; + } + } + + if(outbound.headers){ + var headers = {}; + for k,v in ..table.eachName(outbound.headers){ + var k = ..string.replace("HOST","(\a)(\a+)",lambda(a,b) ..string.upper(a) + ..string.lower(b) ); + headers[k] = v; + } + outbound.headers = headers; + + if(outbound.headers.Host){ + if(outbound.headers.Host==outbound.host){ + outbound.headers.Host = null; + } + elseif(!outbound.host){ + outbound.host = outbound.headers.Host; + outbound.headers.Host = null; + } + } + + if(!..table.count(outbound.headers)){ + outbound.headers = null; + } + } + + outbound["http-opts"] = null; + outbound["h2-opts"] = null; + outbound.country = null; + outbound.v = null; + + ..table.define(outbound); + + if(outbound.address){ + return outbound; + } +} + +updateSubscription = function(outbondSubscribeUrlMap){ + + var cfgOutbounds = ..config.proxy.outbounds : ..table.array(); + if(!outbondSubscribeUrlMap) { + outbondSubscribeUrlMap = {} + + for(i=#cfgOutbounds;1;-1){ + var outbound = cfgOutbounds[i] + if(outbound.subscribeUrl){ + outbondSubscribeUrlMap[outbound.subscribeUrl] = true; + } + } + + var cfgSubscribeUrls = ..config.proxy.subscribeUrls; + for(i=#cfgSubscribeUrls;1;-1){ + var sub = cfgSubscribeUrls[i] + if(sub.checked === "启用") { + outbondSubscribeUrlMap[sub.url] = true; + } + else { + outbondSubscribeUrlMap[sub.url] = null; + } + } + + if(!..table.count(outbondSubscribeUrlMap)){ + ..mainForm.msgWarn('当前未启用任何订阅源,\n请先复制订阅源网址到剪贴板然后点击「批量导入链接」!'); + return; + } + } + + var count = 0; + for(url,data in outbondSubscribeUrlMap){ + var impOutbounds = ..v2ray.outbounds.importFromString(url); + if(#impOutbounds){ + for(i=#cfgOutbounds;1;-1){ + var outbound = cfgOutbounds[i] + if(outbound.subscribeUrl==url){ + ..table.remove( cfgOutbounds,i ); + } + } + + ..table.append(cfgOutbounds,impOutbounds); + count = count + #impOutbounds; + } + } + + ..config.proxy.save(); + ..publish("outbounds.updateConfigJson"); + ..publish("uiCommand.restartV2RayCore",cfgOutbounds) + ..mainForm.msgOk("已刷新" + count + "个订阅服务器。",1500); + + return count; +} + +autoUpdateSubscription = function(){ + var outbondSubscribeUrlMap = {} + var cfgSubscribeUrls = ..config.proxy.subscribeUrls; + for(i=#cfgSubscribeUrls;1;-1){ + var sub = cfgSubscribeUrls[i] + if(!#sub.url){ + continue; + } + + if(sub.checked === "启用") { + outbondSubscribeUrlMap[sub.url] = true; + } + } + + if(!..table.count(outbondSubscribeUrlMap)){ + return; + } + + ..thread.invoke( + function(winform,outbondSubscribeUrlMap,responseCache){ + import inet.http; + import web.rest.github; + + var http = inet.http(); + for(url,v in outbondSubscribeUrlMap){ + + if( string.indexOf(url,"github.com") + || string.indexOf(url,"raw.githubusercontent.com") + ){ + outbondSubscribeUrlMap[url] = web.rest.github.getContent(url) + } + else{ + outbondSubscribeUrlMap[url] = http.get(url); + } + + if(!outbondSubscribeUrlMap[url]){ + continue; + } + + if(responseCache){ + if(responseCache[url] && responseCache[url]===..string.crc32(outbondSubscribeUrlMap[url])){ + outbondSubscribeUrlMap[url] = null; + } + } + } + + winform.publish("thread.subscriptionUpdated",outbondSubscribeUrlMap) + },..mainForm,outbondSubscribeUrlMap,_subscriptionResponseCache + ) +} + +var currentActiveOutbound = ..globalActiveOutbound; +..subscribe("activeOutbound",function(address){ + currentActiveOutbound = address; +} ) + +..subscribe("thread.subscriptionUpdated",function(outbondSubscribeUrlMap){ + if(currentActiveOutbound){ + return; + } + + var cfgOutbounds = ..config.proxy.outbounds : ..table.array(); + + var count = 0; + for(url,data in outbondSubscribeUrlMap){ + + var impOutbounds = ..v2ray.outbounds.importFromString(data,url); + if(#impOutbounds){ + for(i=#cfgOutbounds;1;-1){ + var outbound = cfgOutbounds[i] + if(outbound.subscribeUrl==url){ + ..table.remove( cfgOutbounds,i ); + } + } + + ..table.append(cfgOutbounds,impOutbounds); + count = count + #impOutbounds; + } + } + + if(!count){ + return; + } + + ..config.proxy.outbounds = cfgOutbounds; + ..config.proxy.save(); + + ..publish("outbounds.updateConfigJson"); + ..publish("uiCommand.restartV2RayCore") + ..publish("uiCommand.print","已自动刷新" + count + "个订阅服务器。") +} ) + +/**intellisense(v2ray.outbounds) +exportSharedLinks(.(outbounds) = 导出分享链接 +importFromString(.(str,subscribeUrl) = 导入分享链接 +importFromClipboard() = 自剪贴板导入分享链接 +autoUpdateSubscription() = 自动并静默更新订阅源 +updateSubscription() = 更新或自剪贴板导入订阅源\n可选在参数中用一个表自定义要更新的订阅地址,\n参数表中键为url,值为true +end intellisense**/ diff --git a/lib/v2ray/pacServer.aardio b/lib/v2ray/pacServer.aardio new file mode 100644 index 0000000..ad61015 --- /dev/null +++ b/lib/v2ray/pacServer.aardio @@ -0,0 +1,142 @@ +//pacServer 自动代理服务 +import config; +import wsock.tcp.simpleHttpServer; +import inet.http; +import inet.url; + +namespace v2ray.pacServer; +$serverMain = ..wsock.tcp.simpleHttpServer.mainThread( + function(response,request,session){ + + if(request.path=="/proxy.pac"){ + + var pacData = ..string.load(pacPath); + var proxPorts = inboundPort.get(); + if(!proxPorts[["socksProxy"]]){ + response.errorStatus(404); + return; + } + + var reps = ..string.replace(pacData,"var\s+proxy\s+=\s+%''","var proxy = 'SOCKS5 "+ request.environ.SERVER_NAME +":"+proxPorts.socksProxy + +";SOCKS "+ request.environ.SERVER_NAME +":"+proxPorts.socksProxy + +";PROXY "+ request.environ.SERVER_NAME +":"+proxPorts.httpProxy +"'"); + + var useHttp = useHttpProxy.get(); + if(!useHttp){ + var ua = request.headers["user-agent"]; + if( ua && ..string.find(ua,"WinHttp-Autoproxy-Service/")){ + useHttp = true; + } + } + + if(useHttp){ + reps = ..string.replace(pacData,"var\s+proxy\s+=\s+%''","var proxy = 'PROXY "+ request.environ.SERVER_NAME +":"+proxPorts.httpProxy +"'"); + } + + response.contentType = "application/x-ns-proxy-autoconfig"; + response.write(reps); + } + } +); +$serverMain.threadNum = 50; + +var pacPath = ..io.appData("/winXray/pac.txt"); +resetPac = function(){ + ..string.save(pacPath,$"/pac.txt" ) +} + +if( ! ..io.exist(pacPath) ){ + resetPac(); +} + +loadPacText = function(){ + return ..io.exist(pacPath) ? ..string.load(pacPath) || $"/pac.txt"; +} + +savePacText = function(json){ + var str = ..string.replace($"/pac.txt","var\s+rules\s*=\s*%\[\]","var rules = " + json); + ..string.save(pacPath,str ); +} + +var inboundPort = ..thread.var(); +var useHttpProxy = ..thread.var(); +restart = function(){ + useHttpProxy.set(!..config.proxy.useSocksPac); + + $serverMain.threadGlobal = { + inboundPort = inboundPort; + pacPath = pacPath; + useHttpProxy = useHttpProxy; + } + + var pacPort = ..config.proxy.pacPort; + if( (! pacPort) || pacPort >= 49152 ){ pacPort = ..wsock.tcp.server.getFreePort("127.0.0.1",1083,10803,10813,44823) } + + var currentIp,currentPort = $serverMain.getLocalIp(); + if(currentIp!==..config.core.default.inbounds[[1]][["listen"]] + || currentPort != pacPort ){ + $serverMain.stop(); + + var ok,err = $serverMain.start( + ..config.core.default.inbounds[[1]][["listen"]] : "127.0.0.1",pacPort ); + if(!ok){ + ..publish("uiCommand.print","启动PAC服务器失败",err) + return false,err; + } + + ..publish("uiCommand.print","PAC服务器已启动",getUrl()) + ..publish("pacServer.restarted",pacPort); + } + + return true; +} + +stop = function(){ + if($serverMain){ + $serverMain.stop(); + } +} + +updateUseHttpProxy = function(httpProxy){ + useHttpProxy.set(httpProxy); +} + +updateConfig = function(socksProxyPort,httpProxyPort){ + if(socksProxyPort && httpProxyPort){ + inboundPort.set( {socksProxy=socksProxyPort;httpProxy=httpProxyPort} ); + } +} + +..subscribe("v2RayCore.restarted",function(socksProxyPort,httpProxyPort){ + updateConfig(socksProxyPort,httpProxyPort); +} ) + +getUrl = function(localIp){ + var url = $serverMain.getUrl("/proxy.pac?" + ..time.tick() ) + if(!url){ return } + + var tUrl = ..inet.url.split(url); + if(!localIp){ + tUrl.host = "127.0.0.1" + } + else { + tUrl.host = ..wsock.tcp.client.getLocalIp("www.baidu.com"); + } + + return tostring(tUrl); +} + +getPort = function(){ + var ip,port = $serverMain.getLocalIp(); + return port; +} + + +/**intellisense(v2ray.pacServer) +stop() = 停止PAC服务器 +restart() = 重启PAC服务器 +getUrl(.(localIp) = 返回PAC服务地址 +getPort() = 返回PAC端口 +updateConfig(.(socksProxyPort,httpProxPort) = 更新代理端口或PAC数据 +resetPac() = 重置为默认PAC +end intellisense**/ diff --git a/main.aardio b/main.aardio new file mode 100644 index 0000000..522c488 --- /dev/null +++ b/main.aardio @@ -0,0 +1,381 @@ +/*启动参数检测{{*/ +if(_ARGV.github){ + loadcodex("\forms\main\tools\github.aardio"); + return; +} +if(_ARGV.uwp){ + loadcodex("\forms\main\tools\uwpExemption.aardio"); + return; +} +elseif(_ARGV.sshInstall){ + import fsys.wow64; + import process; + import console; + console.open(); + + var prcs; + fsys.wow64.disableRedirection( + function(){ + var dest,port = string.match(_ARGV.sshInstall,"(.+)\:(\d+)"); + if(dest&&port){ + _ARGV.sshInstall = "-p" + port +" " + dest; + } + + prcs = process("ssh","-t " +_ARGV.sshInstall + ` "echo -e '安装完成以后,您可以一次性复制所有服务器账号配置 - 然后在 winXray 主界面点击\e[1;31m「批量导入链接」\e[0m即可,winXray将逐行识别有效的服务器分享链接或通用JSON配置,并忽略无效的行。如果 CentOS 8安装失败 - 可尝试更换为 CentOS 7 并重新安装。\n';firewall-cmd --permanent --add-port=80/tcp;firewall-cmd --permanent --add-port=443/tcp;firewall-cmd --reload;iptables -A INPUT -p tcp --dport 80 -j ACCEPT;iptables -A INPUT -p tcp --dport 443 -j ACCEPT;wget -P /root -N --no-check-certificate ""https://raw.githubusercontent.com/mack-a/v2ray-agent/master/install.sh"" && chmod 700 /root/install.sh && /root/install.sh"`) + if(!prcs){ + if(_WIN10_LATER){ + import process.control; + process.control("ms-settings:optionalfeatures"); + console.log("请检查是否指定了正确的SSH端口,或尝试重新安装 OpenSSH.Client"); + } + else { + console.log("此功能仅支持 Windows 10 系统"); + } + } + else { + import process.job.limitKill; + prcs.assignToJobObject(process.job.limitKill); + prcs.wait(); + } + + console.pause(); + } + ) + + return; +} +elseif(_ARGV.sshLogin){ + import fsys.wow64; + import process; + import console; + console.open(); + + var prcs; + fsys.wow64.disableRedirection( + function(){ + var dest,port = string.match(_ARGV.sshLogin,"(.+)\:(\d+)"); + if(dest&&port){ + _ARGV.sshLogin = "-p" + port +" " + dest; + } + + prcs = process("ssh","-t " +_ARGV.sshLogin + ``) + if(!prcs){ + if(_WIN10_LATER){ + import process.control; + process.control("ms-settings:optionalfeatures"); + console.log("请检查是否指定了正确的SSH端口,或尝试重新安装 OpenSSH.Client"); + } + else { + console.log("此功能仅支持 Windows 10 系统"); + } + } + else { + import process.job.limitKill; + prcs.assignToJobObject(process.job.limitKill); + prcs.wait(); + } + + console.pause(); + } + ) + + return; +} +elseif(_ARGV.sshInstallKey){ + import fsys.wow64; + import process; + import console; + console.open(); + + var prcs; + fsys.wow64.disableRedirection( + function(){ + var sshKeyPath = io.getSpecial(0x28/*_CSIDL_PROFILE*/,"/.ssh/id_rsa.pub") ; + var keyData = string.load(sshKeyPath); + if(!keyData){ + var prcs = process.popen("ssh-keygen",` -t rsa -f "`+io.getSpecial(0x28/*_CSIDL_PROFILE*/,"/.ssh/id_rsa")+`" -y`); + keyData = prcs? prcs.read(-1); + } + + if(!keyData){ + if(_WIN10_LATER){ + import process.control; + process.control("ms-settings:optionalfeatures"); + console.log("请检查是否指定了正确的SSH端口,或尝试重新安装 OpenSSH.Client"); + } + else { + console.log("此功能仅支持 Windows 10 系统"); + } + } + else{ + var dest,port = string.match(_ARGV.sshInstallKey,"(.+)\:(\d+)"); + if(dest&&port){ + _ARGV.sshInstallKey = "-p" + port +" " + dest; + } + + prcs = process("ssh","-t " +_ARGV.sshInstallKey + ` "mkdir -p ~/.ssh;chmod 700 ~/.ssh;chmod 600 ~/.ssh/authorized_keys;echo '`+keyData+`' > ~/.ssh/authorized_keys"`) + if(!prcs){ + if(_WIN10_LATER){ + import process.control; + process.control("ms-settings:optionalfeatures"); + console.log("请检查是否指定了正确的SSH端口,或尝试重新安装 OpenSSH.Client"); + } + else { + console.log("此功能仅支持 Windows 10 系统"); + } + } + else { + import process.job.limitKill; + prcs.assignToJobObject(process.job.limitKill); + prcs.wait(); + } + } + + console.pause(); + } + ) + + return; +} +elseif(_ARGV.updateTime){ + import time.ntp; + time.ntp.updateSystemTime(); + return; +} +else { + /* + import process; + import fsys.update.#simpleMain; + + if( fsys.update.simpleMain( + "winXray(V2Ray/V2Ray、Shadowsocks、Trojan通用客户端 )", + "https://raw.githubusercontent.com/win-xray/win-xray/master/release/update/version.txt", + ..io.appData("/winXray/update"), + function(version,description,status){} + ,,false)){ + return 0; + } + */ +} +/*}}*/ +import fonts.fontAwesome; +import win.ui; +/*DSG{{*/ +mainForm = win.form(text="winXray";right=1019;bottom=679;bgcolor=15793151;border="none") +mainForm.add( +caption={cls="bkplus";text="WinXray 3.8";left=67;top=9;right=727;bottom=27;align="left";color=6052956;dl=1;dt=1;font=LOGFONT(h=-14);z=7}; +custom={cls="custom";left=83;top=40;right=1022;bottom=679;bgcolor=16777215;db=1;dl=1;dr=1;dt=1;z=4}; +logo={cls="bkplus";text='\uF1D9';left=35;top=7;right=64;bottom=32;color=3054125;dl=1;dt=1;font=LOGFONT(h=-18;name='FontAwesome');z=6}; +navBar={cls="bkplus";left=0;top=37;right=83;bottom=681;bgcolor=3442175;db=1;dl=1;dt=1;z=1}; +navJsonConfig={cls="plus";text="配置";left=0;top=132;right=85;bottom=212;bkBottom=3;bkLeft=7;bkRight=8;bkTop=2;border={color=-65536};color=16777215;dl=1;dt=1;font=LOGFONT(h=-13);iconStyle={font=LOGFONT(h=-37;name='FontAwesome');padding={bottom=20}};iconText='\uF0F6';notify=1;textPadding={bottom=10};valign="bottom";x=0.5;y=0.2;z=5}; +navStart={cls="plus";text="首页";left=0;top=48;right=85;bottom=128;bkBottom=3;bkLeft=7;bkRight=8;bkTop=2;border={color=-65536};color=16777215;dl=1;dt=1;font=LOGFONT(h=-13);iconStyle={font=LOGFONT(h=-37;name='FontAwesome');padding={bottom=20}};iconText='\uF015';notify=1;textPadding={bottom=10};valign="bottom";x=0.5;y=0.2;z=3}; +navTools={cls="plus";text="工具";left=0;top=216;right=85;bottom=296;bkBottom=3;bkLeft=7;bkRight=8;bkTop=2;border={color=-65536};color=16777215;dl=1;dt=1;font=LOGFONT(h=-13);iconStyle={font=LOGFONT(h=-37;name='FontAwesome');padding={bottom=20}};iconText='\uF0AD';notify=1;textPadding={bottom=10};valign="bottom";x=0.5;y=0.2;z=8}; +titleBar={cls="bkplus";left=0;top=0;right=1022;bottom=38;bgcolor=8036607;dl=1;dr=1;dt=1;forecolor=16777215;linearGradient=180;z=2} +) +/*}}*/ + +import win.ui.atom; +var atom,hwnd = mainForm.atom("DFA5667E-1D8C-49C0-8918-C6FEC2DECCF8"); +if(!atom){ + win.showForeground(hwnd); + win.quitMessage(); + return; +} + +import win.ui.simpleWindow; +win.ui.simpleWindow( mainForm ); + +import win.dlg.message; +win.dlg.message.install(); + +import win.ui.tabs; +var tbs = win.ui.tabs( + mainForm.navStart, + mainForm.navJsonConfig, + mainForm.navTools +); + +tbs.skin({ + background={ + active=0xFFFFFFFF; + default=0x00FFFFFF; + hover=0x38FFFFFF + }; + color={ + default=0xFFFFFFFF; + }; + checked={ + background={default=0xFFFFFFFF;}; + color={default=0xff86a543;}; + } +}) + +tbs.loadForm(1,"\forms\main\v2ray.aardio" ); +tbs.loadForm(2,"\forms\main\config\jsonConfig.aardio" ); +tbs.loadForm(3,"\forms\main\tools\tools.aardio"); + +tbs.selIndex = 1; + +import v2ray.core; +import win.ui.menu; +mainForm.wndproc = { + [0xACCF/*_WM_TRAYMESSAGE*/ ] = function(hwnd,message,wParam,lParam){ + if( lParam = 0x205/*_WM_RBUTTONUP*/ ){ + win.setForeground(mainForm.hwnd) + mainForm.popmenu = win.ui.popmenu(mainForm); + mainForm.popmenu.add('自动切换到最快的服务器',function(id){ + publish("uiCommand.restartV2RayCore",) + }); + mainForm.popmenu.add('立即更新所有订阅源',function(id){ + v2ray.outbounds.updateSubscription(); + }); + mainForm.popmenu.add(); + + import v2ray.core; + var id = mainForm.popmenu.add('不使用代理',function(id){ + sysProxy.switch("direct"); + }); + mainForm.popmenu.check(id,config.proxy.mode=="direct",0/*_MF_BYCOMMAND*/); + + var id = mainForm.popmenu.add('使用全局代理',function(id){ + sysProxy.switch("proxy"); + }); + mainForm.popmenu.check(id,config.proxy.mode=="proxy",0/*_MF_BYCOMMAND*/); + + var id = mainForm.popmenu.add('使用 PAC 自动代理',function(id){ + sysProxy.switch("pac"); + }); + mainForm.popmenu.check(id,config.proxy.mode=="pac",0/*_MF_BYCOMMAND*/); + + mainForm.popmenu.add(); + + mainForm.popmenu.add('编辑 PAC 配置',function(id){ + publish("uiCommand.showPacForm"); + }); + + if(_WIN10_LATER){ + mainForm.popmenu.add('UWP 应用代理配置',function(id){ + if(_STUDIO_INVOKED){ + mainForm.msgErr("请先发布为 EXE!"); + return; + } + + import process; + process.execute(io._exepath,"/uwp","runas") + }); + } + + mainForm.popmenu.add(); + + if(_WIN10_LATER){ + mainForm.popmenu.add('打开系统代理设置',function(id){ + import process.control; + process.control("ms-settings:network-proxy") + }); + mainForm.popmenu.add('打开 Internet 代理选项',function(id){ + import process.control; + process.control("inetcpl.cpl",,4); + }); + } + else { + mainForm.popmenu.add('打开系统代理设置',function(id){ + import process.control; + process.control("inetcpl.cpl",,4); + }); + } + + mainForm.popmenu.add('打开网卡连接',function(id){ + import process; + process.explore("shell:::{7007ACC7-3202-11D1-AAD2-00805FC1270E}"); + }); + mainForm.popmenu.add(); + + mainForm.popmenu.add('获取 winXray 最新源代码',function(id){ + import process; + process.openUrl("https://www.github.com/win-xray/win-xray") + }); + + import chrome.path; + var chromePath = chrome.path(); + if(chromePath && v2ray.core.socksProxyPort){ + mainForm.popmenu.add('使用 SOCKS5 代理打开浏览器',function(id){ + import process + process.execute(chromePath,` --proxy-server="SOCKS5://127.0.0.1:`+v2ray.core.socksProxyPort + +`" --user-data-dir="` +io.appData("winXray/chrome-socks5")+ `" https://www.google.com`); + }); + } + + mainForm.popmenu.add(); + mainForm.popmenu.add('退出',function(id){ + mainForm.onClose = null; + mainForm.close() + }); + + var pt = ::POINT(); + ::User32.GetCursorPos(pt); + mainForm.popmenu.popup(pt.x,pt.y,true) + } + elseif( lParam = 0x203/*_WM_LBUTTONDBLCLK*/) { + if(win.isIconic(mainForm.hwnd)){ + mainForm.show(9/*_SW_RESTORE*/); + } + else { + mainForm.show(); + } + + win.setForeground(mainForm.hwnd); + } + } +} + +mainForm.onDestroy = function(){ + mainForm.tray.delete(); +} + +import win.util.tray; +mainForm.onClose = function(hwnd,message,wParam,lParam){ + if(!mainForm.tray){ + mainForm.tray = win.util.tray(mainForm); + } + else { + mainForm.tray.reset(); + } + + mainForm.show(false); + return true; +} + +mainForm.tray = win.util.tray(mainForm) +if(!_ARGV.tray){ + mainForm.show(); +} + +import win.image; +var trayIcons = { + direct = win.image.loadIconFromFile("\forms\ico\app-direct.ico"); + pac = win.image.loadIconFromFile("\forms\ico\app-pac.ico"); + proxy = _HAPPICON +} + +subscribe("sysProxy.modeChanged",function(active){ + mainForm.tray.icon = trayIcons[config.proxy.mode] ; +}) + +subscribe("uiCommand.HotkeyChanged",function(...){ + if(#config.proxy.hotkey){ + if(mainForm.hkProxyId){ + mainForm.unreghotkey(mainForm.hkProxyId) + mainForm.hkProxyId = null; + } + + mainForm.hkProxyId = mainForm.reghotkey( function(id,mod,vk){ + import sysProxy; + var mode = sysProxy.switchHotkey(); + var dlg = win.dlg.message(win.getForeground()) + dlg.ok(mode=="pac"?"已切换到 PAC 代理模式":"已切换到全局代理模式",1200); + },config.proxy.hotkey[1],config.proxy.hotkey[2]) + } +} ) +publish("uiCommand.HotkeyChanged"); + +return win.loopMessage(); diff --git a/pac.txt b/pac.txt new file mode 100644 index 0000000..a63f623 --- /dev/null +++ b/pac.txt @@ -0,0 +1,5694 @@ +/** + * genpac 2.1.0 https://github.com/JinnLynn/genpac + * GFWList Last-Modified: 2020-10-21 00:11:38 + */ + +var proxy = 'SOCKS5 127.0.0.1:1080'; +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", + "gravatar.com", + "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" + ], + [ + "realtimesupport.clients6.google.com", + "apis.google.com", + "fonts.gstatic.com", + "play.google.com", + "ssl.gstatic.com", + "csi.gstatic.com", + "khmdb.google.com", + "www.google-analytics.com", + "www.gstatic.com", + "support.google.com", + "mw2.google.com", + "mw1.google.com", + "kh.google.com", + "geoauth.google.com", + "maps.google.com", + "030buy.com", + "0rz.tw", + "1-apple.com.tw", + "10.tt", + "1000giri.net", + "100ke.org", + "10conditionsoflove.com", + "10musume.com", + "123rf.com", + "12bet.com", + "12vpn.com", + "12vpn.net", + "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", + "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", + "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", + "6park.com", + "6parker.com", + "6parknews.com", + "7capture.com", + "7cow.com", + "8-d.com", + "85cc.net", + "85cc.us", + "85st.com", + "881903.com", + "888.com", + "888poker.com", + "89-64.org", + "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", + "9gag.com", + "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", + "accim.org", + "aceros-de-hispania.com", + "acevpn.com", + "acg18.me", + "acgkj.com", + "acgnx.se", + "acmedia365.com", + "acmetoy.com", + "acnw.com.au", + "actfortibet.org", + "actimes.com.au", + "activpn.com", + "aculo.us", + "adcex.com", + "addictedtocoffee.de", + "adelaidebbs.com", + "admob.com", + "adpl.org.hk", + "ads-twitter.com", + "adsense.com", + "adult-sex-games.com", + "adultfriendfinder.com", + "adultkeep.net", + "advanscene.com", + "advertfan.com", + "ae.org", + "aenhancers.com", + "aex.com", + "af.mil", + "afantibbs.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", + "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", + "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", + "animeshippuuden.com", + "aniscartujo.com", + "annatam.com", + "anobii.com", + "anontext.com", + "anonymise.us", + "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", + "apetube.com", + "api.ai", + "apiary.io", + "apigee.com", + "apk-dl.com", + "apkcombo.com", + "apkmirror.com", + "apkmonk.com", + "apkplz.com", + "apkpure.com", + "aplusvpn.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", + "asianews.it", + "asianfreeforum.com", + "asiansexdiary.com", + "asianspiss.com", + "asianwomensfilm.de", + "asiatgp.com", + "asiatoday.us", + "askstudent.com", + "askynz.net", + "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", + "axureformac.com", + "azerbaycan.tv", + "azerimix.com", + "azubu.tv", + "azurewebsites.net", + "b0ne.com", + "baby-kingdom.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", + "bandwagonhost.com", + "bangbrosnetwork.com", + "bangchen.net", + "bangdream.space", + "bangyoulater.com", + "bankmobilevibe.com", + "bannedbook.org", + "bannednews.org", + "banorte.com", + "baramangaonline.com", + "barenakedislam.com", + "barnabu.co.uk", + "barton.de", + "bartvpn.com", + "bash-hackers.org", + "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", + "beijingspring.com", + "beijingzx.org", + "belamionline.com", + "bell.wiki", + "bemywife.cc", + "beric.me", + "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", + "big.one", + "bigfools.com", + "bigjapanesesex.com", + "bigmoney.biz", + "bignews.org", + "bigsound.org", + "biliworld.com", + "billypan.com", + "binance.com", + "bing.com", + "binux.me", + "binwang.me", + "bipic.net", + "bird.so", + "bit-z.com", + "bit.do", + "bit.ly", + "bitcointalk.org", + "bitcoinworld.com", + "bitfinex.com", + "bithumb.com", + "bitinka.com.ar", + "bitmex.com", + "bitshare.com", + "bitsnoop.com", + "bitterwinter.org", + "bitvise.com", + "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", + "blockcn.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", + "blueangellive.com", + "bmfinn.com", + "bnews.co", + "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", + "bookepub.com", + "books.com.tw", + "booktopia.com.au", + "boomssr.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", + "bravotube.net", + "brazzers.com", + "break.com", + "breakgfw.com", + "breaking911.com", + "breakingtweets.com", + "breakwall.net", + "briefdream.com", + "briian.com", + "brizzly.com", + "brkmd.com", + "broadbook.com", + "broadpressinc.com", + "brockbbs.com", + "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", + "bullog.org", + "bullogger.com", + "bunbunhk.com", + "busayari.com", + "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", + "bynet.co.il", + "c-est-simple.com", + "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", + "calstate.edu", + "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", + "carfax.com", + "cari.com.my", + "caribbeancom.com", + "carmotorshow.com", + "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", + "cattt.com", + "cbc.ca", + "cbsnews.com", + "cbtc.org.hk", + "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", + "cdn-apple.com", + "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", + "cftfc.com", + "cgdepot.org", + "cgst.edu", + "change.org", + "changeip.name", + "changeip.net", + "changeip.org", + "changp.com", + "changsa.net", + "channel8news.sg", + "chaoex.com", + "chapm25.com", + "chatnook.com", + "chaturbate.com", + "chengmingmag.com", + "chenguangcheng.com", + "chenpokong.com", + "chenpokong.net", + "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", + "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", + "chromeexperiments.com", + "chromercise.com", + "chromestatus.com", + "chromium.org", + "chuang-yen.org", + "chubold.com", + "chubun.com", + "chuizi.net", + "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", + "cloudfront.net", + "club1069.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", + "coingi.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", + "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", + "crrev.com", + "crucial.com", + "csdparty.com", + "csuchen.de", + "csw.org.uk", + "ct.org.tw", + "ctao.org", + "ctfriend.net", + "ctitv.com.tw", + "cts.com.tw", + "cuhk.edu.hk", + "cuhkacs.org", + "cuihua.org", + "cuiweiping.net", + "culture.tw", + "cumlouder.com", + "curvefish.com", + "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", + "dailymotion.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", + "danwei.org", + "daolan.net", + "daozhongxing.org", + "darktech.org", + "darktoy.net", + "darpa.mil", + "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", + "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", + "deaftone.com", + "debian.org", + "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", + "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", + "dlsite.com", + "dlsite.jp", + "dlyoutube.com", + "dm530.net", + "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", + "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", + "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", + "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", + "embr.in", + "emilylau.org.hk", + "emory.edu", + "empfil.com", + "emule-ed2k.com", + "emulefans.com", + "emuparadise.me", + "enanyang.my", + "encyclopedia.com", + "enewstree.com", + "enfal.de", + "engadget.com", + "engagedaily.org", + "englishforeveryone.org", + "englishfromengland.co.uk", + "englishpen.org", + "enlighten.org.tw", + "entermap.com", + "entnt.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.im", + "esurance.com", + "etaa.org.au", + "etadult.com", + "etaiwannews.com", + "etherdelta.com", + "etizer.org", + "etokki.com", + "etowns.net", + "etowns.org", + "ettoday.net", + "etvonline.hk", + "eu.org", + "eucasino.com", + "eulam.com", + "eurekavpt.com", + "euronews.com", + "europa.eu", + "evschool.net", + "exblog.co.jp", + "exblog.jp", + "exchristian.hk", + "excite.co.jp", + "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", + "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", + "fail.hk", + "faith100.org", + "faithfuleye.com", + "faiththedog.info", + "fakku.net", + "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", + "fangbinxing.com", + "fangeming.com", + "fangeqiang.com", + "fanglizhi.info", + "fangmincn.org", + "fangong.org", + "fangongheike.com", + "fanhaodang.com", + "fanqiang.tk", + "fanqiangdang.com", + "fanqianghou.com", + "fanqiangyakexi.net", + "fanqiangzhe.com", + "fanswong.com", + "fanyue.info", + "fapdu.com", + "faproxy.com", + "faqserv.com", + "fartit.com", + "farwestchina.com", + "fastly.net", + "fastpic.ru", + "fastssh.com", + "faststone.org", + "fatbtc.com", + "favotter.net", + "favstar.fm", + "fawanghuihui.org", + "faydao.com", + "fb.com", + "fb.me", + "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", + "feedly.com", + "feedx.net", + "feelssh.com", + "feer.com", + "feifeiss.com", + "feitian-california.org", + "feitianacademy.org", + "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", + "fireofliberty.org", + "firetweet.io", + "firstfivefollowers.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", + "footwiball.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", + "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", + "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", + "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", + "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", + "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", + "gcmasia.com", + "gcpnews.com", + "gcr.io", + "gdbt.net", + "gdzf.org", + "geek-art.net", + "geekerhome.com", + "geekheart.info", + "gekikame.com", + "gelbooru.com", + "geocities.co.jp", + "geocities.com", + "geocities.jp", + "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", + "getmdl.io", + "getoutline.org", + "getsocialscope.com", + "getsync.com", + "gettrials.com", + "gettyimages.com", + "getuploader.com", + "gfbv.de", + "gfgold.com.hk", + "gfsale.com", + "gfw.org.ua", + "gfw.press", + "ggpht.com", + "ggssl.com", + "ghostpath.com", + "ghut.org", + "giantessnight.com", + "gifree.com", + "giga-web.jp", + "gigacircle.com", + "giganews.com", + "gigporno.ru", + "girlbanker.com", + "git.io", + "gitbooks.io", + "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", + "gmbd.cn", + "gmhz.org", + "gmiddle.com", + "gmiddle.net", + "gmll.org", + "gmodules.com", + "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", + "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.ne.jp", + "gooday.xyz", + "gooddns.info", + "goodreaders.com", + "goodreads.com", + "goodtv.com.tw", + "goodtv.tv", + "goofind.com", + "google.ac", + "google.ad", + "google.ae", + "google.af", + "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", + "googlegroups.com", + "googlehosted.com", + "googleideas.com", + "googleinsidesearch.com", + "googlelabs.com", + "googlemail.com", + "googlemashups.com", + "googlepagecreator.com", + "googleplay.com", + "googleplus.com", + "googlescholar.com", + "googlesile.com", + "googlesource.com", + "googleusercontent.com", + "googlevideo.com", + "googleweblight.com", + "googlezip.net", + "gopetition.com", + "goproxing.net", + "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", + "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", + "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", + "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", + "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", + "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", + "heroku.com", + "heungkongdiscuss.com", + "hexieshe.com", + "hexieshe.xyz", + "hexxeh.net", + "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", + "hkchurch.org", + "hkci.org.hk", + "hkcmi.edu", + "hkcnews.com", + "hkcoc.com", + "hkctu.org.hk", + "hkdailynews.com.hk", + "hkday.net", + "hkdf.org", + "hkej.com", + "hkepc.com", + "hket.com", + "hkfaa.com", + "hkfreezone.com", + "hkfront.org", + "hkgalden.com", + "hkgolden.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", + "hkpeanut.com", + "hkptu.org", + "hkreporter.com", + "hku.hk", + "hkusu.net", + "hkvwet.com", + "hkwcc.org.hk", + "hkzone.org", + "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", + "hoovers.com", + "hopedialogue.org", + "hopto.org", + "hornygamer.com", + "hornytrip.com", + "hotav.tv", + "hotels.cn", + "hotfrog.com.tw", + "hotgoo.com", + "hotpornshow.com", + "hotpot.hk", + "hotshame.com", + "hotspotshield.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", + "humanrightsbriefing.org", + "hung-ya.com", + "hungerstrikeforaids.org", + "huobi.com", + "huobi.pro", + "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", + "iddddg.com", + "idemocracy.asia", + "identi.ca", + "idiomconnection.com", + "idlcoyote.com", + "idouga.com", + "idreamx.com", + "idsam.com", + "ieasy5.com", + "ied2k.net", + "ienergy1.com", + "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", + "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", + "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", + "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", + "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", + "izaobao.us", + "izihost.org", + "izles.net", + "izlesem.org", + "j.mp", + "jackjia.com", + "jamaat.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", + "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", + "joinmastodon.org", + "joins.com", + "journalchretien.net", + "journalofdemocracy.org", + "joymiihub.com", + "joyourself.com", + "jp.net", + "jpopforum.net", + "jqueryui.com", + "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", + "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", + "kobo.com", + "kobobooks.com", + "kodingen.com", + "kompozer.net", + "konachan.com", + "kone.com", + "koolsolutions.com", + "koornk.com", + "koranmandarin.com", + "korenan2.com", + "krtco.com.tw", + "ksdl.org", + "ksnews.com.tw", + "kspcoin.com", + "ktzhk.com", + "kucoin.com", + "kui.name", + "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", + "lalulalu.com", + "lama.com.tw", + "lamayeshe.com", + "lamenhu.com", + "lamnia.co.uk", + "lamrim.com", + "landofhope.tv", + "lanterncn.cn", + "lantosfoundation.org", + "laod.cn", + "laogai.org", + "laomiu.com", + "laoyang.info", + "laptoplockdown.com", + "laqingdan.net", + "larsgeorge.com", + "lastcombat.com", + "lastfm.es", + "latelinenews.com", + "latibet.org", + "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", + "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", + "lidecheng.com", + "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", + "linkideo.com", + "linksalpha.com", + "linkuswell.com", + "linpie.com", + "linux.org.hk", + "linuxtoy.org", + "lionsroar.com", + "lipuman.com", + "liquidvpn.com", + "list-manage.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", + "livestation.com", + "livestream.com", + "livevideo.com", + "livingonline.us", + "livingstream.com", + "liwangyang.com", + "lizhizhuangbi.com", + "lkcn.net", + "llss.me", + "load.to", + "lobsangwangyal.com", + "localbitcoins.com", + "localdomain.ws", + "localpresshk.com", + "lockestek.com", + "logbot.net", + "logiqx.com", + "logmein.com", + "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", + "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", + "mangafox.com", + "mangafox.me", + "maniash.com", + "manicur4ik.ru", + "mansion.com", + "mansionpoker.com", + "manta.com", + "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", + "matainja.com", + "material.io", + "mathable.io", + "mathiew-badimon.com", + "matome-plus.com", + "matome-plus.net", + "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.nz", + "megaproxy.com", + "megarotic.com", + "megavideo.com", + "megurineluka.com", + "meirixiaochao.com", + "meltoday.com", + "memehk.com", + "memorybbs.com", + "memri.org", + "memrijttm.org", + "mercatox.com", + "mercyprophet.org", + "mergersandinquisitions.org", + "meridian-trust.org", + "meripet.biz", + "meripet.com", + "merit-times.com.tw", + "meshrep.com", + "mesotw.com", + "messenger.com", + "metacafe.com", + "metart.com", + "metarthunter.com", + "meteorshowersonline.com", + "metro.taipei", + "metrohk.com.hk", + "metrolife.ca", + "metroradio.com.hk", + "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", + "mist.vip", + "mit.edu", + "mitao.com.tw", + "mitbbs.com", + "mitbbsau.com", + "mixero.com", + "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", + "moeaic.gov.tw", + "moeerolibrary.com", + "moegirl.org", + "mofa.gov.tw", + "mofaxiehui.com", + "mofos.com", + "mog.com", + "mohu.club", + "mohu.ml", + "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", + "moonbbs.com", + "moonbingo.com", + "mooo.com", + "morbell.com", + "morningsun.org", + "moroneta.com", + "mos.ru", + "motherless.com", + "motiyun.com", + "motor4ik.ru", + "mousebreaker.com", + "movements.org", + "moviefap.com", + "moztw.org", + "mp3buscador.com", + "mp3ye.eu", + "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", + "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", + "nationsonline.org", + "nationwide.com", + "naughtyamerica.com", + "naver.jp", + "navy.mil", + "naweeklytimes.com", + "nbc.com", + "nbtvpn.com", + "nccwatch.org.tw", + "nch.com.tw", + "ncn.org", + "ncol.com", + "nde.de", + "ndr.de", + "ned.org", + "nekoslovakia.net", + "neo-miracle.com", + "nepusoku.com", + "nesnode.com", + "net-fits.pro", + "netbig.com", + "netbirds.com", + "netcolony.com", + "netfirms.com", + "netflix.com", + "netme.cc", + "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", + "newipnow.com", + "newlandmagazine.com.au", + "newnews.ca", + "news100.com.tw", + "newsancai.com", + "newschinacomment.org", + "newscn.org", + "newsdetox.ca", + "newsdh.com", + "newsmagazine.asia", + "newspeak.cc", + "newstamago.com", + "newstapa.org", + "newstarnet.com", + "newtaiwan.com.tw", + "newtalk.tw", + "newyorktimes.com", + "nexon.com", + "next11.co.jp", + "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", + "nhentai.net", + "nhi.gov.tw", + "nhk-ondemand.jp", + "nic.google", + "nic.gov", + "nicovideo.jp", + "nighost.org", + "nightlife141.com", + "nikkei.com", + "ninecommentaries.com", + "ning.com", + "ninjacloak.com", + "ninjaproxy.ninja", + "nintendium.com", + "ninth.biz", + "nitter.net", + "niu.moe", + "niusnews.com", + "njactb.org", + "njuice.com", + "nlfreevpn.com", + "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", + "nottinghampost.com", + "novelasia.com", + "now.com", + "now.im", + "nownews.com", + "nowtorrents.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.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", + "nuuvem.com", + "nuvid.com", + "nuzcom.com", + "nvdst.com", + "nvquan.org", + "nvtongzhisheng.org", + "nwtca.org", + "nyaa.eu", + "nyaa.si", + "nydus.ca", + "nylon-angel.com", + "nylonstockingsonline.com", + "nyt.com", + "nytchina.com", + "nytcn.me", + "nytco.com", + "nyti.ms", + "nytimes.com", + "nytimg.com", + "nytlog.com", + "nytstyle.com", + "nzchinese.com", + "nzchinese.net.nz", + "oauth.net", + "observechina.net", + "obutu.com", + "ocaspro.com", + "occupytiananmen.com", + "oclp.hk", + "ocreampies.com", + "ocry.com", + "october-review.org", + "oculus.com", + "oculuscdn.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", + "olabloga.pl", + "old-cat.net", + "olumpo.com", + "olympicwatch.org", + "omgili.com", + "omni7.jp", + "omnitalk.com", + "omnitalk.org", + "omy.sg", + "on.cc", + "on2.com", + "onapp.com", + "onedumb.com", + "onejav.com", + "onion.city", + "onlinecha.com", + "onlineyoutube.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", + "opensource.google", + "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", + "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", + "overplay.net", + "ovi.com", + "ow.ly", + "owind.com", + "owl.li", + "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", + "pagodabox.com", + "palacemoon.com", + "paldengyal.com", + "paljorpublications.com", + "palmislife.com", + "paltalk.com", + "pandapow.co", + "pandapow.net", + "pandavpn-jp.com", + "pandora.com", + "pandora.tv", + "panluan.net", + "panoramio.com", + "pao-pao.net", + "paper.li", + "paperb.us", + "paradisehill.cc", + "paradisepoker.com", + "parkansky.com", + "parler.com", + "parsevideo.com", + "partycasino.com", + "partypoker.com", + "passion.com", + "passiontimes.hk", + "paste.ee", + "pastebin.com", + "pastie.org", + "pathtosharepoint.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", + "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", + "perfectgirls.net", + "perfectvpn.net", + "periscope.tv", + "persecutionblog.com", + "persiankitty.com", + "pfd.org.hk", + "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.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", + "plixi.com", + "plm.org.hk", + "plunder.com", + "plurk.com", + "plus.codes", + "plus28.com", + "plusbb.com", + "pmatehunter.com", + "pmates.com", + "po2b.com", + "pobieramy.top", + "podictionary.com", + "pokerstars.com", + "pokerstars.net", + "pokerstrategy.com", + "politicalchina.org", + "politicalconsultation.org", + "politiscales.net", + "poloniex.com", + "polymer-project.org", + "polymerhk.com", + "popo.tw", + "popvote.hk", + "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", + "procopytips.com", + "prosiben.de", + "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", + "pts.org.tw", + "ptt.cc", + "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", + "pussyspace.com", + "putihome.org", + "putlocker.com", + "putty.org", + "puuko.com", + "pwned.com", + "python.com", + "python.com.tw", + "pythonhackers.com", + "pythonic.life", + "pytorch.org", + "qanote.com", + "qgirl.com.tw", + "qhigh.com", + "qi-gong.me", + "qiandao.today", + "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", + "r18.com", + "ra.gg", + "radicalparty.org", + "radiko.jp", + "radio.garden", + "radioaustralia.net.au", + "radiohilight.net", + "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", + "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", + "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", + "religioustolerance.org", + "renminbao.com", + "renyurenquan.org", + "rerouted.org", + "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", + "rolia.net", + "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", + "rtycminnesota.org", + "ruanyifeng.com", + "rukor.org", + "runbtx.com", + "rushbee.com", + "ruten.com.tw", + "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", + "safervpn.com", + "safety.google", + "saintyculture.com", + "saiq.me", + "sakuralive.com", + "sakya.org", + "salvation.org.hk", + "samair.ru", + "sambhota.org", + "sandscotaicentral.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", + "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", + "secretchina.com", + "secretgarden.no", + "secretsline.biz", + "securetunnel.com", + "securityinabox.org", + "securitykiss.com", + "seed4.me", + "seehua.com", + "seesmic.com", + "seevpn.com", + "seezone.net", + "sejie.com", + "sellclassics.com", + "sendsmtp.com", + "sendspace.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", + "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", + "shenzhoufilm.com", + "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", + "shutterstock.com", + "shvoong.com", + "shwchurch.org", + "shwchurch3.com", + "siddharthasintent.org", + "sidelinesnews.com", + "sidelinessportseatery.com", + "sierrafriendsoftibet.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", + "sinocast.com", + "sinocism.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", + "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", + "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", + "softsmirror.cf", + "softwarebychuck.com", + "sogclub.com", + "sogoo.org", + "sogrady.me", + "soh.tw", + "sohcradio.com", + "sohfrance.org", + "soifind.com", + "sokamonline.com", + "sokmil.com", + "solidaritetibet.org", + "solidfiles.com", + "somee.com", + "songjianjun.com", + "sonicbbs.cc", + "sonidodelaesperanza.org", + "sopcast.com", + "sopcast.org", + "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", + "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", + "srocket.us", + "ss-link.com", + "ssglobal.co", + "ssglobal.me", + "ssh91.com", + "ssl443.org", + "sspanel.net", + "sspro.ml", + "ssr.tools", + "ssrshare.com", + "sss.camp", + "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", + "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", + "stranabg.com", + "straplessdildo.com", + "streamate.com", + "streamingthe.net", + "streema.com", + "streetvoice.com", + "strikingly.com", + "strongvpn.com", + "strongwindpress.com", + "student.tw", + "studentsforafreetibet.org", + "stumbleupon.com", + "stupidvideos.com", + "successfn.com", + "sueddeutsche.de", + "sugarsync.com", + "sugobbs.com", + "sugumiru18.com", + "suissl.com", + "sulian.me", + "summify.com", + "sumrando.com", + "sun1911.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", + "suroot.com", + "surrenderat20.net", + "sustainability.google", + "suyangg.com", + "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", + "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", + "taiwan-sex.com", + "taiwanbible.com", + "taiwancon.com", + "taiwandaily.net", + "taiwandc.org", + "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", + "techviz.net", + "teck.in", + "teco-hk.org", + "teco-mo.org", + "teddysun.com", + "teeniefuck.net", + "teensinasia.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", + "tew.org", + "textnow.me", + "tfhub.dev", + "thaicn.com", + "thb.gov.tw", + "theatrum-belli.com", + "thebcomplex.com", + "theblemish.com", + "thebobs.com", + "thebodyshop-usa.com", + "thechinabeat.org", + "thechinastory.org", + "thedalailamamovie.com", + "thedw.us", + "thefacebook.com", + "thefrontier.hk", + "thegay.com", + "thegioitinhoc.vn", + "thegly.com", + "theguardian.com", + "thehots.info", + "thehousenews.com", + "thehun.net", + "theinitium.com", + "thenewslens.com", + "thepiratebay.org", + "theporndude.com", + "theportalwiki.com", + "thereallove.kr", + "therock.net.nz", + "thespeeder.com", + "thestandnews.com", + "thetibetcenter.org", + "thetibetconnection.org", + "thetibetmuseum.org", + "thetibetpost.com", + "thetinhat.com", + "thetrotskymovie.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", + "tibetanfeministcollective.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", + "tiltbrush.com", + "timdir.com", + "time.com", + "timsah.com", + "tinc-vpn.org", + "tiney.com", + "tineye.com", + "tintuc101.com", + "tiny.cc", + "tinychat.com", + "tinypaste.com", + "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", + "torproject.org", + "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", + "traffichaus.com", + "transparency.org", + "treemall.com.tw", + "trendsmap.com", + "trialofccp.org", + "trickip.net", + "trickip.org", + "trimondi.de", + "trouw.nl", + "trt.net.tr", + "trtc.com.tw", + "truebuddha-md.org", + "trulyergonomic.com", + "truthontour.org", + "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", + "tunnelr.com", + "tuo8.blue", + "tuo8.cc", + "tuo8.club", + "tuo8.fit", + "tuo8.hk", + "tuo8.in", + "tuo8.ninja", + "tuo8.org", + "tuo8.pw", + "tuo8.red", + "tuo8.space", + "turansam.org", + "turbobit.net", + "turbohide.com", + "turbotwitter.com", + "turkistantimes.com", + "turntable.fm", + "tushycash.com", + "tutanota.com", + "tuvpn.com", + "tuzaijidi.com", + "tv.com", + "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", + "twskype.com", + "twstar.net", + "twt.tl", + "twtkr.com", + "twtrland.com", + "twttr.com", + "twurl.nl", + "twyac.org", + "txxx.com", + "tycool.com", + "typepad.com", + "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", + "untraceable.us", + "uocn.org", + "updatestar.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", + "urbansurvival.com", + "urchin.com", + "url.com.tw", + "url.tw", + "urlborg.com", + "urlparser.com", + "us.to", + "usacn.com", + "usaip.eu", + "usc.edu", + "usembassy.gov", + "usfk.mil", + "usma.edu", + "usmc.mil", + "usocctn.com", + "uspto.gov", + "ustream.tv", + "usunitednews.com", + "usus.cc", + "utopianpal.com", + "uu-gg.com", + "uukanshu.com", + "uvwxyz.xyz", + "uwants.com", + "uwants.net", + "uyghur-j.org", + "uyghur.co.uk", + "uyghuramerican.org", + "uyghurcanadiansociety.org", + "uyghurcongress.org", + "uyghurensemble.co.uk", + "uyghurpen.org", + "uyghurpress.com", + "uyghurstudies.org", + "uygur.org", + "uymaarip.com", + "v2ex.com", + "v2ray.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", + "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", + "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", + "vivatube.com", + "vivthomas.com", + "vizvaz.com", + "vjav.com", + "vjmedia.com.hk", + "vllcs.org", + "vmixcore.com", + "vmpsoft.com", + "vnet.link", + "voa.mobi", + "voacantonese.com", + "voachinese.com", + "voachineseblog.com", + "voagd.com", + "voanews.com", + "voatibetan.com", + "voatibetanenglish.com", + "vocativ.com", + "vocn.tv", + "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", + "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", + "waiwaier.com", + "wallmama.com", + "wallornot.org", + "wallpapercasa.com", + "wallproxy.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", + "waselpro.com", + "washeng.net", + "washingtonpost.com", + "watch8x.com", + "watchinese.com", + "watchmygf.net", + "wattpad.com", + "wav.tv", + "waveprotocol.org", + "waymo.com", + "wda.gov.tw", + "wdf5.com", + "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", + "weekmag.info", + "wefightcensorship.org", + "wefong.com", + "weiboleak.com", + "weihuo.org", + "weijingsheng.org", + "weiming.info", + "weiquanwang.org", + "weisuo.ws", + "welovecock.com", + "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", + "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", + "wikinews.org", + "wikipedia.org", + "wikisource.org", + "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", + "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", + "woolyss.com", + "woopie.jp", + "woopie.tv", + "wordpress.com", + "workatruna.com", + "workerdemo.org.hk", + "workerempowerment.org", + "workersthebig.net", + "workflow.is", + "worldcat.org", + "worldjournal.com", + "worldvpn.net", + "wow-life.net", + "wow.com", + "wowgirls.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.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", + "xiezhua.com", + "xihua.es", + "xinbao.de", + "xing.com", + "xinhuanet.org", + "xinmiao.com.hk", + "xinsheng.net", + "xinshijue.com", + "xinyubbs.net", + "xiongpian.com", + "xiuren.org", + "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--czq75pvv1aj5c.org", + "xn--i2ru8q2qg.com", + "xn--ngstr-lra8j.com", + "xn--oiq.cc", + "xn--p8j9a0d9c9a.xn--q9jyb4c", + "xnxx.com", + "xpdo.net", + "xpud.org", + "xrentdvd.com", + "xskywalker.com", + "xskywalker.net", + "xtube.com", + "xuchao.net", + "xuchao.org", + "xuehua.us", + "xuite.net", + "xuzhiyong.net", + "xvideo.cc", + "xvideos.com", + "xvideos.es", + "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", + "yahoo.co.jp", + "yahoo.com", + "yahoo.com.hk", + "yahoo.com.tw", + "yahoo.net", + "yakbutterblues.com", + "yam.com", + "yam.org.tw", + "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", + "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", + "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", + "yzzk.com", + "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", + "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", + "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", + "zorrovpn.com", + "zozotown.com", + "zpn.im", + "zspeeder.me", + "zsrhao.com", + "zuo.la", + "zuobiao.me", + "zuola.com", + "zvereff.com", + "zynaima.com", + "zynamics.com", + "zyns.com", + "zyzc9.com", + "zzcartoon.com", + "zzcloud.me", + "zzux.com", + "149.154.160.0/22", + "149.154.164.0/22", + "149.154.172.0/22", + "91.108.4.0/22", + "91.108.20.0/22", + "91.108.56.0/22", + "91.108.8.0/22", + "95.161.64.0/20", + "91.108.12.0/22" + ] + ] +]; + +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) { + if( /^\d+\.\d+\.\d+\.\d+$/.test(host) && ( typeof isInNetEx !== "undefined" ) ){ + 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) || ( lastRule.indexOf("/") && isInNetEx(host, lastRule) ) ){ + return i % 2 == 0 ? 'DIRECT' : proxy; + } + } + } + return; + } + + 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; + }; +} \ No newline at end of file diff --git a/release/winXray.7z b/release/winXray.7z new file mode 100644 index 0000000..0a1139f Binary files /dev/null and b/release/winXray.7z differ diff --git a/release/winXray32.7z b/release/winXray32.7z new file mode 100644 index 0000000..9ebcf13 Binary files /dev/null and b/release/winXray32.7z differ diff --git a/screenshots/config.advanced.png b/screenshots/config.advanced.png new file mode 100644 index 0000000..2149235 Binary files /dev/null and b/screenshots/config.advanced.png differ diff --git a/screenshots/config.json.png b/screenshots/config.json.png new file mode 100644 index 0000000..7e0dba3 Binary files /dev/null and b/screenshots/config.json.png differ diff --git a/screenshots/outbound.png b/screenshots/outbound.png new file mode 100644 index 0000000..4600f43 Binary files /dev/null and b/screenshots/outbound.png differ diff --git a/screenshots/pac.png b/screenshots/pac.png new file mode 100644 index 0000000..fd670de Binary files /dev/null and b/screenshots/pac.png differ diff --git a/screenshots/telegram.gif b/screenshots/telegram.gif new file mode 100644 index 0000000..b99d158 Binary files /dev/null and b/screenshots/telegram.gif differ diff --git a/screenshots/winXray.png b/screenshots/winXray.png new file mode 100644 index 0000000..85be3ba Binary files /dev/null and b/screenshots/winXray.png differ diff --git a/sub/introduce.md b/sub/introduce.md new file mode 100644 index 0000000..c4e9b62 --- /dev/null +++ b/sub/introduce.md @@ -0,0 +1,58 @@ +# winXray 小技巧 + +### 一、批量导入链接技巧 + +winXray 可通过【批量导入链接】功能导入以下格式的分享链接、订阅源、或JSON配置: + + 1、一行或多行(忽略无效行)分享链接或服务器JSON配置。 + 支持 vmess://,vless://,ss://,ssr://,trojan://, trojan-go://,native+http://,socks://, proxy:// 等通用分享链接。 + + 2、包含多个服务器配置的JSON数组,支持winXray格式以及通用格式JSON。 + + 3、单个 http:// 或 https:// 开头的通用订阅源地址。 + 可直接使用浏览器地址栏的github文件地址(含blob或raw目录名)。 + 也可以仅复制单斜杆开始的github文件路径。 + + 订阅源可用BASE64编码或明文返回以上1、2条规定的配置或分享链接。 + + +[网络免费 vmess 服务器订阅链接](https://proxypool.ga/vmess/sub) +[网络免费 Shadowsocks 服务器订阅链接](https://proxypool.ga/ss/sub) +[网络免费 clash 服务器订阅链接](https://proxypoolss.tk/clash/proxies?speed=100&type=vmess,trojan) + +可复制上面各种格式订阅链接,在 winXray 中点击【批量导入链接】体验 winXray 有强大的兼容性。 + +支持以下格式的 Github 项目文件地址作为订阅源( 可省略域名并以斜杆开头 ): +https://github.com/winXray/winXray/blob/master/sub/sample.json +[/winXray/blob/master/sub/sample.json](./sample.json) +https://github.com/winXray/winXray/raw/master/sub/sample.json +[/winXray/winXray/raw/master/sub/sample.json](./sample.json) +https://raw.githubusercontent.com/winXray/winXray/master/sub/sample.json + +### 二、使用新增、编辑服务器配置的对话框 + +winXray 新版已经添加了新增、编辑服务器配置的对话框,请直接在 winXray 首页服务器列表点右键菜单,然后点【新增、编辑代理服务器】即可。 + +![新增、编辑服务器](./../screenshots/winXray.png) + +![代理服务器配置](./../screenshots/outbound.png) + +### 三、使用JSON配置服务器 +![三、使用JSON配置服务器](./../screenshots/config.json.png) +JSON配置界面里点击任意字段都会显示该字段的用法说明。个人认为做很多对话框来配置服务器的参数其实是把简单的事搞复杂了,winXray已经把各种代理协议的配置简化为几个统一命名的JSON字段( **也可以作为一种标准的、统一的、通用的订阅响应格式使用** ),只要稍加学习就可以非常熟练的添加、修改各种代理协议的配置。而且对于大多数用户根本不需要改配置 - 简单的复制导入分享链接就可以,我们不必要把简单的事搞复杂。 + +### 四、使用 PAC 编辑器 +可以直接复制网址( 不需要去截取域名 ) ,然后打开 PAC 编辑器,这时候 winXray 会自动从剪贴板把域名取出来并且输入好,只要点一下设为代理,然后添加域名就可以了。也可以一次复制多个域名,域名可以任何空白字符(或者换行)分隔,然后点右键菜单,再点批量导入域名即可。 + +winXray 里的 PAC 支持 CIDR 格式的 IP 地址段, 使用此功能可以轻松的让 PAC 代理支持 Telegram。 + +![使用 PAC 编辑器](./../screenshots/pac.png) + +### 五、Telegram 代理设置 +有很多软件的 PAC 代理不支持 Telegram,但 winXray 的 PAC 代理有良好的兼容性 - 可以完美支持 Telegram IP 地址库( 旧版本升级请在 PAC 编辑器右键添加 Telegram IP 地址库 ) 。 + +当然我们也可以直接告诉 Telegram 他要使用的代理服务器地址的操作非常简单,请看下面的动画: +![Telegram 代理设置](./../screenshots/telegram.gif) + + + diff --git a/sub/sample.json b/sub/sample.json new file mode 100644 index 0000000..e7ab7e5 --- /dev/null +++ b/sub/sample.json @@ -0,0 +1,87 @@ +[ + { + "address":"www.aech.cc", + "alterId":64, + "host":"", + "id":"ef3c6aa0-e5f2-4332-bad8-17c0438dfaa3", + "network":"ws", + "path":"/ray", + "port":443, + "protocol":"vmess", + "ps":"香港4", + "security":"auto", + "tls":"tls", + "type":"none" + }, + { + "address":"23.225.125.86", + "alterId":64, + "host":"www.56626173.xyz", + "id":"8fb921c0-564d-4d5a-9b13-384c01820126", + "network":"ws", + "path":"/footers", + "port":443, + "protocol":"vmess", + "ps":"美国4", + "security":"auto", + "tls":"tls", + "type":"none" + }, + { + "address":"104.16.160.20", + "alterId":2, + "host":"freeus.mcan.tech", + "id":"9e6ceeff-2546-3690-ac00-6fcdf31dec94", + "network":"ws", + "path":"/y284", + "port":443, + "protocol":"vmess", + "ps":"美国4", + "security":"auto", + "sni":"freeus.mcan.tech", + "tls":"tls", + "type":"none" + }, + { + "address":"llajv.rebldp.tech", + "alterId":64, + "host":"llajv.rebldp.tech", + "id":"3b5e258e-8c5e-45d3-b7d2-02c8f5fc0bb2", + "network":"ws", + "path":"/", + "port":443, + "protocol":"vmess", + "ps":"德国4", + "security":"auto", + "tls":"tls", + "type":"none" + }, + { + "address":"154.84.1.140", + "alterId":64, + "host":"154.84.1.140", + "id":"2a7349d6-994a-434b-9589-c0020685e528", + "network":"tcp", + "path":"/", + "port":54671, + "protocol":"vmess", + "ps":"荷兰4", + "security":"auto", + "tls":"", + "type":"none" + }, + { + "address":"consum2.cukee.cc", + "alterId":64, + "host":"consum2.cukee.cc", + "id":"02914F25-41C8-3114-50F3-19359B631C77", + "network":"ws", + "path":"/", + "port":443, + "protocol":"vmess", + "ps":"法国4", + "security":"auto", + "tls":"tls", + "type":"none" + } +] \ No newline at end of file diff --git a/v2ray-core-32/LICENSE b/v2ray-core-32/LICENSE new file mode 100644 index 0000000..ac130ba --- /dev/null +++ b/v2ray-core-32/LICENSE @@ -0,0 +1 @@ +https://github.com/v2fly/v2ray-core/blob/master/LICENSE \ No newline at end of file diff --git a/v2ray-core-32/v2ctl.exe b/v2ray-core-32/v2ctl.exe new file mode 100644 index 0000000..afcf69b Binary files /dev/null and b/v2ray-core-32/v2ctl.exe differ diff --git a/v2ray-core-32/v2ray.exe b/v2ray-core-32/v2ray.exe new file mode 100644 index 0000000..ec6e01a Binary files /dev/null and b/v2ray-core-32/v2ray.exe differ diff --git a/v2ray-core-32/winXray-default-servers.json b/v2ray-core-32/winXray-default-servers.json new file mode 100644 index 0000000..a52ea5d --- /dev/null +++ b/v2ray-core-32/winXray-default-servers.json @@ -0,0 +1,19 @@ +// 号开头为注释行。 +// 本文件用于指定默认服务器列表。 +// 本文件可以直接输入json格式的服务器数组( 服务器可以使用subscribeUrl字段指定订阅源地址,可以指定"autoConnect":false字段禁止自动连接 ) +// 也可以每行一个 vless://、vmess://、trojan、trojan-go、ss://、ssr://, 等分享链接 +[ + { + "address":"服务器地址", + "port":443, // 服务器端口 + "id":"UUID或密码", // v2ray就指定UUID,shadowsocks在这里指定密码 + "network":"tcp", // 网络协议可以改为 "tcp", "ws" 等 + "security":"none", // 加密方法,vmess 默认为 auto, vless 默认为 none, shadowsocks也可以在这里指定加密方法,例如:"aes-256-gcm", + "protocol":"vless", // 协议可以更换为 "vless","vmess","shadowsocks","trojan","trojan-go" 等 + "host":"伪装主机域名", // 例如ws协议通过这个指定HTTP头里的host字段。 + "sni":"TLS域名", // 不指定使用host的值,如果host也没指定就使用 address的值 + "tls":"xtls", // 可以不写,值可以指定为 "","tls","xtls" 等 + "flow":"流控", // xtls需要用到的字段,可以不指定使用默认值 "xtls-rprx-direct" + "ps":"描述文本" + } +] \ No newline at end of file diff --git a/v2ray-core/LICENSE b/v2ray-core/LICENSE new file mode 100644 index 0000000..ac130ba --- /dev/null +++ b/v2ray-core/LICENSE @@ -0,0 +1 @@ +https://github.com/v2fly/v2ray-core/blob/master/LICENSE \ No newline at end of file diff --git a/v2ray-core/v2ctl.exe b/v2ray-core/v2ctl.exe new file mode 100644 index 0000000..79e4316 Binary files /dev/null and b/v2ray-core/v2ctl.exe differ diff --git a/v2ray-core/v2ray.exe b/v2ray-core/v2ray.exe new file mode 100644 index 0000000..5095f88 Binary files /dev/null and b/v2ray-core/v2ray.exe differ diff --git a/v2ray-core/winXray-default-servers.json b/v2ray-core/winXray-default-servers.json new file mode 100644 index 0000000..a52ea5d --- /dev/null +++ b/v2ray-core/winXray-default-servers.json @@ -0,0 +1,19 @@ +// 号开头为注释行。 +// 本文件用于指定默认服务器列表。 +// 本文件可以直接输入json格式的服务器数组( 服务器可以使用subscribeUrl字段指定订阅源地址,可以指定"autoConnect":false字段禁止自动连接 ) +// 也可以每行一个 vless://、vmess://、trojan、trojan-go、ss://、ssr://, 等分享链接 +[ + { + "address":"服务器地址", + "port":443, // 服务器端口 + "id":"UUID或密码", // v2ray就指定UUID,shadowsocks在这里指定密码 + "network":"tcp", // 网络协议可以改为 "tcp", "ws" 等 + "security":"none", // 加密方法,vmess 默认为 auto, vless 默认为 none, shadowsocks也可以在这里指定加密方法,例如:"aes-256-gcm", + "protocol":"vless", // 协议可以更换为 "vless","vmess","shadowsocks","trojan","trojan-go" 等 + "host":"伪装主机域名", // 例如ws协议通过这个指定HTTP头里的host字段。 + "sni":"TLS域名", // 不指定使用host的值,如果host也没指定就使用 address的值 + "tls":"xtls", // 可以不写,值可以指定为 "","tls","xtls" 等 + "flow":"流控", // xtls需要用到的字段,可以不指定使用默认值 "xtls-rprx-direct" + "ps":"描述文本" + } +] \ No newline at end of file