├── .gitignore
├── DOCUMENT.md
├── LICENSE
├── LICENSE.html
├── LICENSE.md
├── README.md
├── src
└── bridgehouse
│ ├── __init__.py
│ ├── bridge.py
│ ├── build.py
│ ├── editMap
│ ├── __init__.py
│ ├── apiTAB.py
│ ├── cafeteriaTAB.py
│ ├── dnsTAB.py
│ ├── inbound
│ │ ├── __init__.py
│ │ ├── dokodemodoorPanel.py
│ │ ├── httpPanel.py
│ │ ├── mtPanel.py
│ │ ├── shadowsocksPanel.py
│ │ ├── socksPanel.py
│ │ └── vmessPanel.py
│ ├── logTAB.py
│ ├── nauticalChartPanel.py
│ ├── outbound
│ │ ├── __init__.py
│ │ ├── blackholePanel.py
│ │ ├── freedomPanel.py
│ │ ├── shadowsocksPanel.py
│ │ ├── socksPanel.py
│ │ └── vmessPanel.py
│ ├── policyTAB.py
│ ├── port
│ │ ├── __init__.py
│ │ ├── inboundPanel.py
│ │ ├── openV2rayJSONFile.py
│ │ ├── outboundPanel.py
│ │ ├── treasureChest.py
│ │ └── updateListSignal.py
│ ├── router
│ │ ├── __init__.py
│ │ ├── codegen.py
│ │ ├── geoSite.proto
│ │ ├── geoSiteEditorPanel.py
│ │ ├── geoSite_pb2.py
│ │ ├── geoSite_pb2_grpc.py
│ │ └── readgfwlist.py
│ ├── routingTAB.py
│ ├── statsTAB.py
│ ├── toolbox
│ │ ├── __init__.py
│ │ └── toolbox.py
│ ├── transport
│ │ ├── __init__.py
│ │ ├── certificatesPanel.py
│ │ ├── dsPanel.py
│ │ ├── http2Panel.py
│ │ ├── mkcpPanel.py
│ │ ├── muxPanel.py
│ │ ├── tcpPanel.py
│ │ ├── transportPanel.py
│ │ └── wsPanel.py
│ └── transportTAB.py
│ ├── extension
│ ├── __init__.py
│ ├── bridgePreference.py
│ ├── bridgetreasureChest.py
│ ├── bugReport.py
│ ├── proxyTest.py
│ ├── runV2raycore.py
│ └── updatePanel.py
│ ├── icons
│ ├── rocket.psd
│ ├── start.ico
│ ├── start.png
│ └── stop.png
│ └── v2ray-shell.spec
├── translations
├── en_US.qm
├── en_US.ts
├── tr.py
├── zh_CN.qm
└── zh_CN.ts
├── v2ray-shell.pyw
└── v2rayshell.pro
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 | MANIFEST
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 | .pytest_cache/
49 |
50 | # Translations
51 | *.mo
52 | *.pot
53 |
54 | # Django stuff:
55 | *.log
56 | .static_storage/
57 | .media/
58 | local_settings.py
59 |
60 | # Flask stuff:
61 | instance/
62 | .webassets-cache
63 |
64 | # Scrapy stuff:
65 | .scrapy
66 |
67 | # Sphinx documentation
68 | docs/_build/
69 |
70 | # PyBuilder
71 | target/
72 |
73 | # Jupyter Notebook
74 | .ipynb_checkpoints
75 |
76 | # pyenv
77 | .python-version
78 |
79 | # celery beat schedule file
80 | celerybeat-schedule
81 |
82 | # SageMath parsed files
83 | *.sage.py
84 |
85 | # Environments
86 | .env
87 | .venv
88 | env/
89 | venv/
90 | ENV/
91 | env.bak/
92 | venv.bak/
93 | venv_linux/
94 | .venv_linux/
95 |
96 | # Spyder project settings
97 | .spyderproject
98 | .spyproject
99 |
100 | # Rope project settings
101 | .ropeproject
102 |
103 | # mkdocs documentation
104 | /site
105 |
106 | # mypy
107 | .mypy_cache/
108 |
109 | # kde
110 | .directory
111 |
112 | # simplegitserver
113 | os
114 | .project
115 | .pydevproject
116 | .settings/
117 | simplegitweb.conf
118 |
--------------------------------------------------------------------------------
/DOCUMENT.md:
--------------------------------------------------------------------------------
1 | ## [帮助文档](https://github.com/v2ray/V2Ray-shell_alpha/wiki/%E5%B8%AE%E5%8A%A9%E6%96%87%E6%A1%A3)
2 |
3 | **注意**:此脚本还属于内测中。很多功能都没有经过严格测试。
4 | **测试前请备份好V2Ray-core配置文件**
5 | **测试前请备份好V2Ray-core配置文件**
6 | **测试前请备份好V2Ray-core配置文件**
7 |
8 | ### 目标人群
9 | 由于脚本还在内测中。所以目前脚本针对的目标人群不是所有人。
10 | 如果你是下列人群,欢迎测试这个脚本帮助改进。
11 | * 对技术感觉兴趣,愿意学习新技术
12 | * 熟悉Qt程序,可以指正脚本中的错误地方
13 | * 脚本使用过程中出错,知道如何修改相应的代码解决问题
14 | * 脚本使用过程中出错,知道如何复现出错问题,定位出错原因
15 | * 脚本导入导出JSON配置错误,并知道如何修改成正确配置
16 | * 熟习[V2Ray官方文档](https://www.v2ray.com/chapter_02/01_overview.html),并且知道如何配置v2ray-core JSON配置文件
17 | * 不怕被冷落
18 |
19 | ### BUG提交
20 | 如果你[提交一个BUG](https://www.chiark.greenend.org.uk/~sgtatham/bugs-cn.html),但无法提供复现方法与步骤或者解决方法。不会得到优先处理。
21 | 任何要求增加新功能的要求将不会被优生处理。
22 | 复现步骤时,translations, config.v2rayshell这个三个文件放到src/bridgehouse/目录中。
23 | 在命令行运行`python3 bridge.py`,以便获得Python Traceback数据。
24 |
25 | * 编辑器不支持编辑带有注释的JSON文件。请自行移除注释。 [原因](https://plus.google.com/+DouglasCrockfordEsq/posts/RK8qyGVaGSr)
26 | * 编辑器生成的配置只能保证符合文档规范,无法保证配置是否有用。
27 | * 使用编辑器生成的配置文件之前请使用如下命令检查配置是否正确 `v2ray -test config.json` (暂无计划将此功能集成在脚本中)
28 | * 编辑JSON文档暂无错误提示。
29 | * 编辑器不对输入的数据做合法验证。比如IP地址可以输入IPv4,IPv6,域名,或者其他任意数据
30 | * 如果想直接使用编辑器,可以在src/bridgehouse/editMap/ 目录找到 nauticalChartPanel.py
31 | * 代理服务器延迟测试,并非为本地计算机到VPS的延迟。这个延迟是访问http://www.google.com的延迟。
32 | * 如果频繁测试google.com服务器可能会引起DDOS。VPS有被拉黑的风险。最小测试时间间隔为60秒。
33 | 对此,你可以在自己的VPS开启http协议用作代理连接状态检查。(当然检查V2Ray-core的日志文件也是个有效的方法,同样暂无计划将此功能集成在脚本中。)
34 | * 编辑JSON文档时,不会自动分析in/outbound(Detour)已有的policy level。
在面板中添加新的in/outbound(Detour)时,所有的policy level会出现在PolicyTAB列表中(V2Ray-core V3.1之前的配置文件会有此问题)。
35 | * 测试服务器连接状态功能关闭,服务器延迟测试也会自己关闭。
36 | * 编译二进制文件,使用二进制文件的一切问题无法处理。
37 | * build.py文件为开发人员使用,可以删除。
38 |
39 | ### 参与开发
40 | 欢迎任何对此脚本感兴趣的开发者参与开发。
41 | 但请知道,参与这个脚本的开发者必须放弃对脚本的一切权利(开发者同样也包括原始作者)。
42 | 如果你无法接受这个条件,你可以自由复制这个脚本单独发行。
43 | 但请注意如果使用PyQt请遵循Riverbank公司的[协议](https://www.riverbankcomputing.com/commercial/license-faq)。
44 | 或者使用PySide请遵循Qt公司[相应协议](http://code.qt.io/cgit/pyside/pyside-setup.git/tree/?h=5.9)
45 | 为了兼顾两家公司的协议,所以此脚本才会使用[公有领域协议](https://zh.wikipedia.org/wiki/%E5%85%AC%E6%9C%89%E9%A2%86%E5%9F%9F)
46 | 如果你购买了Riverbank或Qt的商业授权。闭源是被允许。
47 | PySide2可以在这[下载](http://download.qt.io/snapshots/ci/pyside/5.9/latest/pyside2/)。
48 | PyQt5可以直接用pip安装。
49 |
50 | ### 维护
51 | 由于作者还有其他工作。只能用业余时间去维护这个项目。
52 | 有一年的有效维护保证。
53 | 到2018年12月会视下一年安排,会作出如何接着维护这个项目的决定。
54 | 一但项目稳定版本发行,需要维护的地方将很少。
55 |
56 | ### 新功能增加
57 | 由于这个脚本支持多平台运行。为了减少维护成本,很多功能不增加。
58 | 如设置系统代理,向导生成配置,自动生成配置,配置模板,二维码等等...
59 | 也无法提供[负载均衡](https://zh.wikipedia.org/wiki/%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1),[服务质量](https://zh.wikipedia.org/wiki/%E6%9C%8D%E5%8A%A1%E8%B4%A8%E9%87%8F)等等...
60 | 脚本中路由配置暂时支持 GeoSite.dat 的编辑,还没有完善...
61 | 学习golang中...
62 |
63 | ### 二进制文件
64 | 此脚本不直接提供二进制文件。请自行编译。
65 | 编译方法:
66 | 先安装pyinstaller,安装方法之一 `pip install pyinstaller`
67 | 然后到/src/bridgehouse/目录,在命令行中执行如下编译命令:
68 |
69 | `pyinstaller -F --noconsole -name v2ray-shell bridge.py`
70 | 或者使用 `pyinstaller v2ray-shell.spec` 生成可独立运行的二进制文件可在dist目录中找到。
71 | windows平台亦可直接使用build.py直接生成二进制文件,有可能失败。
72 | windows平台确保有libeay32.dll与ssleay32.dll与安装包同目录。
73 | 这两个文件可以在Python PyQt5安装目录中找到(../Lib/site-packages/PyQt5/Qt/bin/)
74 | 请确保icons与translations与二进制文件同一个目录,以便使用相应功能。
75 |
76 | ubuntu-17.10测试时,pyinstaller使用的是python2.7。请改为python3.6运行。
77 | 命令行中使用which pyinstaller找到pyinstaller文件。
78 | 修改 `#!/usr/bin/python` 为 `#!/usr/bin/python3`
79 | GNOME桌面可以试着用下面代码制作一个桌面程序的启动器,[相关文档](https://standards.freedesktop.org/desktop-entry-spec/latest/index.html)。
80 | V2Ray-shell_path修改为相应的V2Ray-shell存放的绝对路径。
81 | ```Desktop Entry
82 | [Desktop Entry]
83 | Version=1.0
84 | Name=v2rayshell
85 | Comment=This is my v2ray-shell
86 | Exec=V2Ray-shell_path/v2ray-shell.pyw
87 | Icon=V2Ray-shell_path/src/bridgehouse/icons/start.png
88 | Path=V2Ray-shell_path/
89 | Terminal=false
90 | Type=Application
91 | Categories=Utility;Application;
92 | Name[en_US]=v2rayshell
93 | ```
94 |
95 | 发布二进制文件时,请附带此脚本的源代码与相应协议。
96 | **备注** :*这个测试在windows 10 平台通过,其他平台未知。对于编译二进制文件, 与其出现的一切问题无法处理*
97 | **谨慎使用第三方发布的二进制文件**
98 | **谨慎使用第三方发布的二进制文件**
99 | **谨慎使用第三方发布的二进制文件**
100 |
101 | ### 翻译
102 | 欢迎有能力与时间的朋友参与脚本的翻译与修正。
103 | 或者帮助设计无版权图标(带Alpha通道的PSD或者TIF文件受欢迎)。
104 | 翻译方法:
105 | > 1. [下载QT开发包](https://download.qt.io/archive/qt/)
106 | > 2. 打开v2rayshell.pro文件,在TRANSLATIONS项目里增加相应语言。
107 | > 3. 命令行中找到v2ray-shell的v2rayshell.pro文件。执行此命令`pylupdate5 v2rayshell.pro `生成ts文件。
108 | > 4. 到translations目录找到相应的ts目标文件。
109 | > 5. 找到QT开发包的Qt Linguist,使用Linguist打开ts文件并开始翻译。Qt Linguist的使用方法可以查看帮助文档Qt Linguist Manual。
110 | > 6. 翻译好后文件后,在Qt Linguist中找到File->Release As 发布翻译好的qm文件。
111 | > 7. 最后打开v2ray-shell脚本,在Option->Preference设置相应的翻译文件并重新启动脚本测试。
112 |
113 | ### PyQt5学习
114 | 此脚本是自底向上开发,几乎所有的脚本都可以单独运行并测试。
115 | 开发者也是第一次接触QT编程。学习过程并不困难。欢迎大家一起来学习,交流指正代码中的错误地方。
116 | 在学习的过程中请善用[搜索引擎](https://en.wikipedia.org/wiki/Category:Internet_search_engines),与使用[stackoverflow](https://stackoverflow.com/) [提问](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/master/README-zh_CN.md)。
117 | 其中QT开发文档是最有力的助手。虽然使用的编程语言不同,但并不影响文档的使用。
118 | [PyQt5的Demo代码参考](https://riverbankcomputing.com/software/pyqt/download5)。
119 | 一些学习网站:
120 | * [Pythonspot](https://pythonspot.com/en/pyqt5/)
121 | * [zetcode](http://zetcode.com/gui/pyqt5/)
122 | * [PythonBlogs](http://pythonthusiast.pythonblogs.com/index.php?op=Search&blogId=230&searchTerms=pyqt)
123 | * [Python wiki](https://wiki.python.org/moin/PyQt)
124 | * [PySide for Android](http://wiki.qt.io/PySide_for_Android_guide)
125 | * [Archi的中文教程](http://www.cnblogs.com/archisama/tag/PyQt5/)
126 | * [皮皮blog](http://blog.csdn.net/column/details/py-qt.html)
127 |
128 | ### 其他
129 | 这个脚本在2017年10月1日开始编写。使用PyQt5的原因是比较熟悉Python语言。选择QT是因为跨平台友好。
130 | 原计划只做个v2ray-core的JSON配置编辑器,写着写着又写了个启动器,现在变成坑了。精力有限,不想搞太深...
131 | 在将来的版本中可能会改写成C++与QML结合(有点渺茫)......
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | V2Ray-shell License
2 |
3 | WARNING, ANY PROBLEMS (INCLUDING, BUT NOT LIMITED TO, NATIONAL SECURITY, LEGAL, HARDWARE, SOFTWARE, COPYRIGHT, ETHICS, PERSONAL INJURIES) FOR THE USE OF THE V2RAY-SHELL. V2RAY-SHELL AUTHORS DO NOT TAKE ANY RESPONSIBILITY.
4 |
5 | V2Ray-shell License is public domain.
6 | All of the code and documentation in V2Ray-shell has been dedicated to the public domain by the authors(however, the authors are anonymous).
7 |
8 | If you want to release again, you need to know PyQt5 is released under the GPL v3 license and under a commercial license that allows for the development of proprietary applications.
9 | Of course if you do not want to publish this script in GPL v3. You can use PySide to publish this script using LGPL.
10 | If you use the two companies (QT or Riverbank Computing) any one of the commercial license, closed source is allowed.
--------------------------------------------------------------------------------
/LICENSE.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | V2Ray-shell License
8 |
9 | WARNING, ANY PROBLEMS (INCLUDING, BUT NOT LIMITED TO, NATIONAL SECURITY, LEGAL, HARDWARE, SOFTWARE, COPYRIGHT, ETHICS, PERSONAL INJURIES) FOR THE USE OF THE V2RAY-SHELL. V2RAY-SHELL AUTHORS DO NOT TAKE ANY RESPONSIBILITY.
10 |
11 | V2Ray-shell License is
12 | public domain. 
13 | All of the code and documentation in V2Ray-shell has been dedicated to the public domain by the authors(however, the authors are anonymous).
14 | If you want to release again, you need to know
15 | PyQt5 is released under the GPL v3 license and under a commercial license that allows for the development of proprietary applications.
16 | Of course if you do not want to publish this script under the GPL v3. You can use
17 | PySide to publish this script using LGPL.
18 | If you use the two companies (QT or Riverbank Computing) any one of the commercial license, closed source is allowed.
19 |
20 |
21 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # V2Ray-shell License
2 |
3 | **WARNING, ANY PROBLEMS (INCLUDING, BUT NOT LIMITED TO, NATIONAL SECURITY, LEGAL, HARDWARE, SOFTWARE, COPYRIGHT, ETHICS, PERSONAL INJURIES) FOR THE USE OF THE V2RAY-SHELL. V2RAY-SHELL AUTHORS DO NOT TAKE ANY RESPONSIBILITY.**
4 |
5 | V2Ray-shell License is [public domain](https://en.wikipedia.org/wiki/Public_domain). 
6 | All of the code and documentation in V2Ray-shell has been dedicated to the public domain by the authors(however, the authors are anonymous).
7 | If you want to release again, you need to know [PyQt5](https://www.riverbankcomputing.com/commercial/license-faq) is released under the GPL v3 license and under a commercial license that allows for the development of proprietary applications.
8 | Of course if you do not want to publish this script under the GPL v3. You can use [PySide](https://wiki.qt.io/PySide2) to publish this script using LGPL.
9 | If you use the two companies (QT or Riverbank Computing) any one of the commercial license, closed source is allowed.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## V2Ray-shell [alpha-version](https://en.wiktionary.org/wiki/alpha_version)
2 |
3 | ### Project description
4 | A [GUI](https://en.wikipedia.org/wiki/Graphical_user_interface) for [V2Ray-core](https://github.com/v2ray/v2ray-core).
5 | This [script](https://en.wikipedia.org/wiki/Scripting_language) is written in [PyQt5](https://www.riverbankcomputing.com/software/pyqt/intro). It is still under test and the basic functions have been completed.
And PyQt is available for Windows, UNIX/Linux, Mac OS X and the Sharp Zaurus.
That means you can use this script on many platforms.
6 |
7 | ### Before use V2Ray-shell
8 | 1. [install Python](https://tutorial.djangogirls.org/en/python_installation/) with pip. ([pip](https://pip.pypa.io/en/stable/), which can download and install other Python packages.)
Python version higher than 3.5 is recommended.
9 | 2. [install PyQt5](http://pyqt.sourceforge.net/Docs/PyQt5/installation.html) in [command line](https://tutorial.djangogirls.org/en/intro_to_command_line/) as [root](http://www.linfo.org/root.html) or [administrator](https://technet.microsoft.com/en-us/library/cc947813%28v%3Dws.10%29.aspx).(Of course you can also use this script on the command line to install PyQt5 as root or administrator permission.)
10 | > `pip3 install PyQt5`
11 | 3. in UNIX/Linux, Mac OS X make sure scripts have [execute permission](https://superuser.com/questions/117704/what-does-the-execute-permission-do). such like below:
12 | > `chmod +x v2ray-shell.pyw ./src/bridgehouse/bridge.py`
13 |
14 | ### How use it
15 | 1. run v2ray-shell.pyw
16 | 2. in the system tray find v2ray-shell icon, right click show panel.
17 | 3. in the v2ray-shell panel, find the menu "options->Preferences", set v2ray file path. and click "aplly and close" button
18 | 4. in the v2ray-shell panel, find the menu "File->Add V2Ray-core config file", and add the v2ray-core's config.json file to panel.
19 | 5. in the v2ray-shell panel, click the v2ray-shell icon (a darkgreen rocket), enable this config.json.
20 | 6. and find the black triangle, click it to run v2ray-core.
21 | 7. in the v2ray-shell panel, find the menu "File->Save V2Ray-shell config file", click it to save v2ray-shell config file.
22 |
23 | ### GeoSite.dat File Edit Support (but not perfect complete)
24 | 1. python -m pip install protobuf grpcio grpcio-tools
25 | 2. this new feature is unstable, you can try another preject https://github.com/onplus/v2ray-SiteDAT
26 |
27 | ### Document and Help
28 | [see the wiki page](https://github.com/v2ray/V2Ray-shell_alpha/wiki/%E5%B8%AE%E5%8A%A9%E6%96%87%E6%A1%A3)
29 |
30 | ### LICENSE
31 | see the LICENSE file details.
--------------------------------------------------------------------------------
/src/bridgehouse/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from bridgehouse.editMap import logTAB
4 | logbook = logTAB.logBook()
5 |
--------------------------------------------------------------------------------
/src/bridgehouse/build.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pathlib import Path
4 | import shutil, os, sys
5 | from PyInstaller.__main__ import run
6 |
7 | is_win = sys.platform.startswith('win')
8 | spec = "v2ray-shell.spec"
9 |
10 | if (Path("bridge.py").exists() and Path(spec).exists()):
11 | """
12 | DEVELOPER USE ONLY, NO ANY SUPPORT OR BUG REPORT!!
13 | """
14 | file = "v2ray-shell"
15 | if is_win:
16 | import site
17 | file = "v2ray-shell.exe"
18 | packages = site.getsitepackages()
19 | libeay32 = packages[1] + "/PyQt5/Qt/bin/libeay32.dll"
20 | ssleay32 = packages[1] + "/PyQt5/Qt/bin/ssleay32.dll"
21 | if (Path(libeay32).exists() and Path(ssleay32).exists()):
22 | try:
23 | shutil.copy(libeay32, "./")
24 | shutil.copy(ssleay32, "./")
25 | except Exception: pass
26 |
27 | if len(sys.argv) == 1:
28 | sys.argv.append(spec)
29 | run()
30 |
31 | if (Path(file).exists()):os.remove(file)
32 | try:
33 | shutil.rmtree("./build")
34 | shutil.move("./dist/" + file, "./")
35 | shutil.rmtree("./dist")
36 | shutil.rmtree("./__pycache__")
37 | except Exception: pass
38 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/apiTAB.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QWidget, QTextEdit, QVBoxLayout, QApplication,
4 | QGroupBox, QLineEdit, QPushButton, QHBoxLayout, QLabel)
5 | from PyQt5.QtCore import QFileInfo, QCoreApplication
6 | import sys, json, copy, re
7 |
8 | v2rayshellDebug = False
9 |
10 | if __name__ == "__main__":
11 | v2rayshellDebug = True
12 | # this for debug test
13 | path = QFileInfo(sys.argv[0])
14 | srcPath = path.absoluteFilePath().split("/")
15 | sys.path.append("/".join(srcPath[:-3]))
16 |
17 | from bridgehouse.editMap.port import treasureChest
18 |
19 |
20 | class apiTAB(QWidget):
21 | def __init__(self, CaptainstreasureChest=False):
22 | super(apiTAB, self).__init__()
23 | self.apiJSONFILE = {
24 | "tag": "api",
25 | "services": [
26 | "HandlerService",
27 | "LoggerService"
28 | ]
29 | }
30 |
31 | self.translate = QCoreApplication.translate
32 | if (CaptainstreasureChest):
33 | self.treasureChest = CaptainstreasureChest
34 | else:
35 | self.treasureChest = treasureChest.treasureChest()
36 |
37 | def createapiTAB(self):
38 | self.groupBoxAPI = QGroupBox("API")
39 | self.groupBoxAPI.setCheckable(True)
40 | self.groupBoxAPI.setChecked(False)
41 |
42 | labelAPI = QLabel(self.translate("apiTAB","API's Tag: "))
43 | self.lineEditTagName = QLineEdit("api")
44 | hboxApi = QHBoxLayout()
45 | hboxApi.addWidget(labelAPI)
46 | hboxApi.addWidget(self.lineEditTagName)
47 | hboxApi.addStretch()
48 |
49 | hboxServices = QHBoxLayout()
50 | labelServices = QLabel(self.translate("apiTAB", "Services: "))
51 | self.lineEditServices = QLineEdit("HandlerService, LoggerService, StatsService")
52 | hboxServices.addWidget(labelServices)
53 | hboxServices.addWidget(self.lineEditServices)
54 |
55 | vbox = QVBoxLayout()
56 | vbox.addLayout(hboxApi)
57 | vbox.addLayout(hboxServices)
58 | vbox.addStretch()
59 |
60 | self.groupBoxAPI.setLayout(vbox)
61 | self.lineEditTagName.editingFinished.connect(
62 | lambda:self.treasureChest.setApitag([x.strip() for x in re.split(r"[,;]", self.lineEditTagName.text())]))
63 |
64 | if v2rayshellDebug:
65 | self.__debugBtn = QPushButton("__debugTest", self)
66 | vbox.addWidget(self.__debugBtn)
67 | self.__debugBtn.clicked.connect(self.__debugTest)
68 |
69 | return self.groupBoxAPI
70 |
71 | def settingAPITabFromJSONFile(self, apiJSONFile):
72 | if not apiJSONFile:
73 | apiJSONFile = {}
74 | self.groupBoxAPI.setChecked(False)
75 | else:
76 | self.groupBoxAPI.setChecked(True)
77 |
78 | try:
79 | apiJSONFile['tag']
80 | except Exception:
81 | apiJSONFile['tag'] = 'api'
82 |
83 | try:
84 | apiJSONFile["services"]
85 | except Exception:
86 | apiJSONFile["services"] = "HandlerService, LoggerService, StatsService"
87 |
88 | self.lineEditServices.clear()
89 | self.lineEditTagName.clear()
90 | self.lineEditTagName.setText(apiJSONFile['tag'])
91 | try:
92 | if isinstance(apiJSONFile["services"], list):
93 | self.lineEditServices.setText(", ".join(apiJSONFile["services"]))
94 | else:
95 | self.lineEditServices.setText(apiJSONFile["services"])
96 | except Exception:
97 | pass
98 |
99 | def createApiJSONFile(self):
100 | if self.groupBoxAPI:
101 | api = {}
102 | api["tag"] = self.lineEditTagName.text()
103 | api["services"] = [x.strip() for x in re.split(r"[,;]", self.lineEditServices.text())]
104 | return api
105 | return None
106 |
107 | def __debugTest(self):
108 | print(json.dumps(self.createApiJSONFile(), indent=4, sort_keys=False))
109 |
110 | if __name__ == "__main__":
111 | app = QApplication(sys.argv)
112 | ex = apiTAB()
113 | v = QVBoxLayout()
114 | v.addWidget(ex.createapiTAB())
115 | ex.setLayout(v)
116 | ex.setGeometry(200, 100, 400, 300)
117 | ex.show()
118 | sys.exit(app.exec_())
119 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/cafeteriaTAB.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/inbound/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from bridgehouse.editMap import logTAB
4 |
5 | logbook = logTAB.logBook()
6 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/inbound/dokodemodoorPanel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QWidget, QLabel, QLineEdit, QSpinBox,
4 | QCheckBox, QGroupBox, QHBoxLayout, QVBoxLayout,
5 | QToolTip, QPushButton)
6 | from PyQt5.QtGui import QCursor
7 | from PyQt5.QtCore import QFileInfo, QCoreApplication
8 | import sys, re, platform
9 |
10 | v2rayshellDebug = False
11 |
12 | if __name__ == "__main__":
13 | v2rayshellDebug = True
14 | # this for debug test
15 | path = QFileInfo(sys.argv[0])
16 | srcPath = path.absoluteFilePath().split("/")
17 | sys.path.append("/".join(srcPath[:-4]))
18 |
19 | from bridgehouse.editMap.inbound import logbook
20 |
21 |
22 | class DokodemodoorPanel(QWidget):
23 |
24 | def __init__(self):
25 | super().__init__()
26 | self.dokodemodoorJSONFile = {
27 | "address": "",
28 | "port": 443,
29 | "network": "",
30 | "timeout": 300,
31 | "followRedirect": False,
32 | "userLevel": 0
33 | }
34 | self.translate = QCoreApplication.translate
35 |
36 | def createDokodemodoorSettingPanel(self):
37 | labelAddress = QLabel(
38 | self.translate("DokodemodoorPanel", "Address: "), self)
39 | self.lineEditDokodemodoorAddress = QLineEdit()
40 | labelPort = QLabel(
41 | self.translate("DokodemodoorPanel", "Port: "), self)
42 | self.spinBoxDokodemodoorPort = QSpinBox()
43 | labelNetwork = QLabel(
44 | self.translate("DokodemodoorPanel", "Network: "), self)
45 | self.checkBoxDokodemodoorTCP = QCheckBox("TCP", self)
46 | self.checkBoxDokodemodoorUDP = QCheckBox("UDP", self)
47 | labelTimeout = QLabel(
48 | self.translate("DokodemodoorPanel", "Timeout: "), self)
49 | self.spinBoxDokodemodoorTimeout = QSpinBox()
50 | self.checkBoxDokodemodoorFollowRedirect = QCheckBox(
51 | self.translate("DokodemodoorPanel", "Follow Redirect"), self)
52 |
53 | labeluserLevel = QLabel(
54 | self.translate("DokodemodoorPanel", "User Level: "))
55 | self.spinBoxDokodemodooruserLevel = QSpinBox()
56 | self.spinBoxDokodemodooruserLevel.setRange(0, 65535)
57 | self.spinBoxDokodemodooruserLevel.setValue(0)
58 |
59 | hboxuserLevel = QHBoxLayout()
60 | hboxuserLevel.addWidget(labeluserLevel)
61 | hboxuserLevel.addWidget(self.spinBoxDokodemodooruserLevel)
62 | hboxuserLevel.addStretch()
63 |
64 | self.spinBoxDokodemodoorPort.setRange(0, 65535)
65 | self.spinBoxDokodemodoorTimeout.setRange(0, 999)
66 | self.spinBoxDokodemodoorTimeout.setValue(300)
67 | self.spinBoxDokodemodoorPort.setValue(443)
68 | self.checkBoxDokodemodoorFollowRedirect.setChecked(False)
69 |
70 | hboxAdress = QHBoxLayout()
71 | hboxAdress.addWidget(labelAddress)
72 | hboxAdress.addWidget(self.lineEditDokodemodoorAddress)
73 | hboxAdress.addWidget(labelPort)
74 | hboxAdress.addWidget(self.spinBoxDokodemodoorPort)
75 | hboxAdress.addStretch()
76 |
77 | hboxNetwork = QHBoxLayout()
78 | hboxNetwork.addWidget(labelNetwork)
79 | hboxNetwork.addWidget(self.checkBoxDokodemodoorTCP)
80 | hboxNetwork.addWidget(self.checkBoxDokodemodoorUDP)
81 | hboxNetwork.addStretch()
82 |
83 | hboxTimeout = QHBoxLayout()
84 | hboxTimeout.addWidget(labelTimeout)
85 | hboxTimeout.addWidget(self.spinBoxDokodemodoorTimeout)
86 | hboxTimeout.addWidget(self.checkBoxDokodemodoorFollowRedirect)
87 | hboxTimeout.addStretch()
88 |
89 | groupBoxDokodemodoor = QGroupBox(
90 | self.translate("DokodemodoorPanel", "Dokodemo-door"), self)
91 | vboxDokodemodoor = QVBoxLayout()
92 | vboxDokodemodoor.addLayout(hboxAdress)
93 | vboxDokodemodoor.addLayout(hboxTimeout)
94 | vboxDokodemodoor.addLayout(hboxNetwork)
95 | vboxDokodemodoor.addLayout(hboxuserLevel)
96 |
97 | groupBoxDokodemodoor.setLayout(vboxDokodemodoor)
98 |
99 | if (v2rayshellDebug):
100 | self.__debugBtn = QPushButton("__debugTest", self)
101 | self.__debugBtn.clicked.connect(self.__debugTest)
102 | vboxDokodemodoor.addWidget(self.__debugBtn)
103 | self.settingdokodemodoorPanelFromJSONFile(self.dokodemodoorJSONFile, True)
104 |
105 | self.createDokodemodoorSignals()
106 | return groupBoxDokodemodoor
107 |
108 | def createDokodemodoorSignals(self):
109 | self.checkBoxDokodemodoorFollowRedirect.clicked.connect(self.oncheckBoxDokodemodoorFollowRedirect)
110 |
111 | def oncheckBoxDokodemodoorFollowRedirect(self):
112 | if (platform.system() == "Linux"):
113 | self.checkBoxDokodemodoorFollowRedirect.setCheckable(True)
114 | else:
115 | QToolTip.showText(QCursor.pos(),
116 | self.translate("DokodemodoorPanel", "Only suport Linux System."),
117 | self.checkBoxDokodemodoorFollowRedirect)
118 |
119 | def settingdokodemodoorPanelFromJSONFile(self, dokodemodoorJSONFile={}, openFromJSONFile=False):
120 | logbook.setisOpenJSONFile(openFromJSONFile)
121 |
122 | if (not dokodemodoorJSONFile): dokodemodoorJSONFile = {}
123 |
124 | try:
125 | dokodemodoorJSONFile["address"]
126 | except KeyError as e:
127 | logbook.writeLog("dokodemodoor", "KeyError", e)
128 | dokodemodoorJSONFile["address"] = ""
129 |
130 | try:
131 | dokodemodoorJSONFile["port"]
132 | except KeyError as e:
133 | logbook.writeLog("dokodemodoor", "KeyError", e)
134 | dokodemodoorJSONFile["port"] = 443
135 |
136 | try:
137 | dokodemodoorJSONFile["network"]
138 | except KeyError as e:
139 | logbook.writeLog("dokodemodoor", "KeyError", e)
140 | dokodemodoorJSONFile["network"] = ""
141 |
142 | try:
143 | dokodemodoorJSONFile["timeout"]
144 | except KeyError as e:
145 | logbook.writeLog("dokodemodoor", "KeyError", e)
146 | dokodemodoorJSONFile["timeout"] = 300
147 |
148 | try:
149 | dokodemodoorJSONFile["followRedirect"]
150 | except KeyError as e:
151 | logbook.writeLog("dokodemodoor", "KeyError", e)
152 | dokodemodoorJSONFile["followRedirect"] = False
153 |
154 | try:
155 | dokodemodoorJSONFile["userLevel"]
156 | except KeyError as e:
157 | logbook.writeLog("dokodemodoor", "KeyError", e)
158 | dokodemodoorJSONFile["userLevel"] = 0
159 |
160 | self.lineEditDokodemodoorAddress.setText(str(dokodemodoorJSONFile["address"]))
161 | try:
162 | self.spinBoxDokodemodoorPort.setValue(int(dokodemodoorJSONFile["port"]))
163 | except (ValueError, TypeError) as e:
164 | logbook.writeLog("dokodemodoor", "ValueError or TypeError", e)
165 | self.spinBoxDokodemodoorPort.setValue(443)
166 |
167 | try:
168 | self.spinBoxDokodemodoorTimeout.setValue(int(dokodemodoorJSONFile["timeout"]))
169 | except (ValueError, TypeError) as e:
170 | logbook.writeLog("dokodemodoor", "ValueError or TypeError", e)
171 | self.spinBoxDokodemodoorTimeout.setValue(300)
172 | self.checkBoxDokodemodoorFollowRedirect.setChecked(bool(dokodemodoorJSONFile["followRedirect"]))
173 |
174 | try:
175 | self.spinBoxDokodemodooruserLevel.setValue(int(dokodemodoorJSONFile["userLevel"]))
176 | except (ValueError, TypeError) as e:
177 | logbook.writeLog("dokodemodoor", "ValueError or TypeError", e)
178 | self.spinBoxDokodemodooruserLevel.setValue(0)
179 |
180 | try:
181 | self.treasureChest.addLevel(self.spinBoxDokodemodooruserLevel.value())
182 | except Exception:pass
183 |
184 | udp = re.search("udp", dokodemodoorJSONFile["network"].lower())
185 | tcp = re.search("tcp", dokodemodoorJSONFile["network"].lower())
186 | if (bool(tcp)):self.checkBoxDokodemodoorTCP.setChecked(True)
187 | if (bool(udp)):self.checkBoxDokodemodoorUDP.setChecked(True)
188 |
189 | def createDokodemodorrJSONFile(self):
190 | dokodemodoorJSONFile = {}
191 | tcp = self.checkBoxDokodemodoorTCP.isChecked()
192 | udp = self.checkBoxDokodemodoorUDP.isChecked()
193 | port = "" # defaut
194 | if (tcp):
195 | port = "tcp"
196 | if (udp):
197 | port = "udp"
198 | if (tcp and udp):
199 | port = "tcp,udp"
200 | dokodemodoorJSONFile["address"] = self.lineEditDokodemodoorAddress.text()
201 | dokodemodoorJSONFile["port"] = self.spinBoxDokodemodoorPort.value()
202 | dokodemodoorJSONFile["network"] = port
203 | dokodemodoorJSONFile["timeout"] = self.spinBoxDokodemodoorTimeout.value()
204 | dokodemodoorJSONFile["followRedirect"] = self.checkBoxDokodemodoorFollowRedirect.isChecked()
205 | dokodemodoorJSONFile["userLevel"] = self.spinBoxDokodemodooruserLevel.value()
206 |
207 | try:
208 | self.treasureChest.addLevel(self.spinBoxDokodemodooruserLevel.value())
209 | except Exception:
210 | pass
211 | return dokodemodoorJSONFile
212 |
213 | def cleardokodemodoorPanel(self):
214 | self.lineEditDokodemodoorAddress.clear()
215 | self.spinBoxDokodemodoorPort.setValue(443)
216 | self.spinBoxDokodemodoorTimeout.setValue(300)
217 | self.checkBoxDokodemodoorFollowRedirect.setChecked(False)
218 | self.spinBoxDokodemodooruserLevel.setValue(0)
219 | self.checkBoxDokodemodoorTCP.setChecked(False)
220 | self.checkBoxDokodemodoorUDP.setChecked(False)
221 |
222 | def __debugTest(self):
223 | import json
224 | print(json.dumps(self.createDokodemodorrJSONFile(), indent=4, sort_keys=False))
225 |
226 |
227 | if __name__ == "__main__":
228 | from PyQt5.QtWidgets import QApplication
229 | app = QApplication(sys.argv)
230 | ex = DokodemodoorPanel()
231 | ex.createDokodemodoorSettingPanel()
232 | ex.setGeometry(300, 300, 680, 230)
233 | ex.show()
234 | sys.exit(app.exec_())
235 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/inbound/httpPanel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QWidget, QLabel, QSpinBox,
4 | QHBoxLayout, QGroupBox, QPushButton,
5 | QTableWidget, QAbstractItemView, QButtonGroup,
6 | QVBoxLayout, QTableWidgetItem,
7 | QCheckBox)
8 | from PyQt5.QtCore import QFileInfo, QCoreApplication
9 |
10 | import sys, copy
11 |
12 | v2rayshellDebug = False
13 |
14 | if __name__ == "__main__":
15 | v2rayshellDebug = True
16 | # this for debug test
17 | path = QFileInfo(sys.argv[0])
18 | srcPath = path.absoluteFilePath().split("/")
19 | sys.path.append("/".join(srcPath[:-4]))
20 |
21 | from bridgehouse.editMap.inbound import logbook
22 |
23 |
24 | class HttpPanel(QWidget):
25 |
26 | def __init__(self):
27 | super().__init__()
28 | self.httpJSONFile = {
29 | "timeout": 300,
30 | "accounts": [
31 | {
32 | "user": "my-username",
33 | "pass": "my-password"
34 | }
35 | ],
36 | "allowTransparent": False,
37 | "userLevel": 0
38 | }
39 | self.translate = QCoreApplication.translate
40 |
41 | self.labelUserHttpPanel = (self.translate("HttpPanel", "User"),
42 | self.translate("HttpPanel", "Password"))
43 |
44 | def createHttpSettingPanel(self):
45 | labelTimeout = QLabel(self.translate("HttpPanel", "Timeout: "), self)
46 | self.spinBoxHttpTimeout = QSpinBox()
47 |
48 | self.spinBoxHttpTimeout.setRange(0, 999)
49 | self.spinBoxHttpTimeout.setValue(300)
50 |
51 | self.checkBoxallowTransparent = QCheckBox(
52 | self.translate("HttpPanel", "Allow Transparent"), self)
53 | self.checkBoxallowTransparent.setChecked(False)
54 |
55 | hboxTimeout = QHBoxLayout()
56 | hboxTimeout.addWidget(labelTimeout)
57 | hboxTimeout.addWidget(self.spinBoxHttpTimeout)
58 | hboxTimeout.addStretch()
59 |
60 | labeluserLevel = QLabel(self.translate("HttpPanel", "User Level: "))
61 | self.spinBoxHttpuserLevel = QSpinBox()
62 | self.spinBoxHttpuserLevel.setRange(0, 65535)
63 | self.spinBoxHttpuserLevel.setValue(0)
64 |
65 | hboxuserLevel = QHBoxLayout()
66 | hboxuserLevel.addWidget(labeluserLevel)
67 | hboxuserLevel.addWidget(self.spinBoxHttpuserLevel)
68 | hboxuserLevel.addStretch()
69 |
70 | btnHttpNew = QPushButton(
71 | self.translate("HttpPanel", "New"), self)
72 | btnHttpDelete = QPushButton(
73 | self.translate("HttpPanel", "Delete"), self)
74 |
75 | self.groupButtonHttp = QButtonGroup()
76 | self.groupButtonHttp.addButton(btnHttpNew)
77 | self.groupButtonHttp.addButton(btnHttpDelete)
78 |
79 | vboxButtonHttp = QVBoxLayout()
80 | vboxButtonHttp.addWidget(QLabel())
81 | vboxButtonHttp.addWidget(QLabel())
82 | vboxButtonHttp.addWidget(QLabel())
83 | vboxButtonHttp.addWidget(QLabel())
84 | vboxButtonHttp.addWidget(btnHttpNew)
85 | vboxButtonHttp.addWidget(btnHttpDelete)
86 |
87 | self.tableWidgetHttp = QTableWidget()
88 | self.tableWidgetHttp.setColumnCount(2)
89 | self.tableWidgetHttp.adjustSize()
90 | self.tableWidgetHttp.setHorizontalHeaderLabels(self.labelUserHttpPanel)
91 | self.tableWidgetHttp.setSelectionMode(QAbstractItemView.SingleSelection)
92 | self.tableWidgetHttp.setSelectionBehavior(QAbstractItemView.SelectRows)
93 | #self.tableWidgetHttp.setEditTriggers(QAbstractItemView.NoEditTriggers)
94 | self.tableWidgetHttp.horizontalHeader().setStretchLastSection(True)
95 |
96 | hboxHttpTableWidget = QHBoxLayout()
97 | hboxHttpTableWidget.addWidget(self.tableWidgetHttp)
98 | hboxHttpTableWidget.addLayout(vboxButtonHttp)
99 |
100 | vboxHttpTableWidget = QVBoxLayout()
101 | vboxHttpTableWidget.addLayout(hboxHttpTableWidget)
102 |
103 | self.groupBoxHttpAuth = QGroupBox(
104 | self.translate("HttpPanel", "Requires Authentication: "), self)
105 | self.groupBoxHttpAuth.setCheckable(True)
106 | self.groupBoxHttpAuth.setChecked(False)
107 | self.groupBoxHttpAuth.setLayout(vboxHttpTableWidget)
108 |
109 | vboxHttp = QVBoxLayout()
110 | vboxHttp.addLayout(hboxTimeout)
111 | vboxHttp.addLayout(hboxuserLevel)
112 | vboxHttp.addWidget(self.checkBoxallowTransparent)
113 | vboxHttp.addWidget(self.groupBoxHttpAuth)
114 |
115 | self.createHttpPanelSignals()
116 |
117 | if (v2rayshellDebug):
118 | self.__debugBtn = QPushButton("__debugTest", self)
119 | self.__debugBtn.clicked.connect(self.__debugTest)
120 | vboxHttp.addWidget(self.__debugBtn)
121 | self.settinghttpPanelFromJSONFile(self.httpJSONFile, True)
122 |
123 | groupBoxHttp = QGroupBox(self.translate("HttpPanel", "Http"), self)
124 | groupBoxHttp.setLayout(vboxHttp)
125 |
126 | return groupBoxHttp
127 |
128 | def createHttpPanelSignals(self):
129 | self.groupButtonHttp.buttonClicked.connect(self.ongroupButtonHttp)
130 |
131 | def ongroupButtonHttp(self, e):
132 | if (e.text() == self.translate("HttpPanel", "Delete")):
133 | self.onbtnHttpDelete()
134 | if (e.text() == self.translate("HttpPanel", "New")):
135 | self.onbtnHttpNew()
136 |
137 | def onbtnHttpNew(self):
138 | row = self.tableWidgetHttp.rowCount()
139 | if (not row):
140 | self.tableWidgetHttp.setRowCount(row + 1)
141 | else:
142 | user = self.tableWidgetHttp.item(row-1, 0)
143 | password = self.tableWidgetHttp.item(row-1, 1)
144 | if (user and password):
145 | self.tableWidgetHttp.setRowCount(row + 1)
146 |
147 | def onbtnHttpDelete(self):
148 | if (not self.tableWidgetHttp.rowCount()): return
149 | row = self.tableWidgetHttp.currentRow()
150 | self.tableWidgetHttp.removeRow(row)
151 |
152 | def settinghttpPanelFromJSONFile(self, httpJSONFile={}, openFromJSONFile=False):
153 | logbook.setisOpenJSONFile(openFromJSONFile)
154 | self.tableWidgetHttp.setRowCount(0)
155 |
156 | if (not httpJSONFile): httpJSONFile = {}
157 |
158 | try:
159 | httpJSONFile["timeout"]
160 | except KeyError as e:
161 | logbook.writeLog("http", "KeyError", e)
162 | httpJSONFile["timeout"] = 300
163 |
164 | try:
165 | httpJSONFile["allowTransparent"]
166 | except KeyError as e:
167 | logbook.writeLog("http", "KeyError", e)
168 | httpJSONFile["allowTransparent"] = False
169 |
170 | try:
171 | httpJSONFile["accounts"]
172 | except KeyError as e:
173 | logbook.writeLog("http", "KeyError", e)
174 | httpJSONFile["accounts"] = {}
175 |
176 | try:
177 | httpJSONFile["userLevel"]
178 | except KeyError as e:
179 | logbook.writeLog("http", "KeyError", e)
180 | httpJSONFile["userLevel"] = 0
181 |
182 | try:
183 | self.spinBoxHttpTimeout.setValue(int(self.httpJSONFile["timeout"]))
184 | except (ValueError, TypeError) as e:
185 | logbook.writeLog("http", "ValueError or TypeError", e)
186 | self.spinBoxHttpTimeout.setValue(300)
187 |
188 | try:
189 | self.checkBoxallowTransparent.setChecked(bool(httpJSONFile["allowTransparent"]))
190 | except (ValueError, TypeError) as e:
191 | logbook.writeLog("http", "ValueError or TypeError", e)
192 | self.checkBoxallowTransparent.setChecked(False)
193 |
194 | try:
195 | self.spinBoxHttpuserLevel.setValue(int(httpJSONFile["userLevel"]))
196 | except (ValueError, TypeError) as e:
197 | logbook.writeLog("http", "ValueError or TypeError", e)
198 | self.spinBoxHttpuserLevel.setValue(0)
199 | try:
200 | self.treasureChest.addLevel(self.spinBoxHttpuserLevel.value())
201 | except Exception:pass
202 |
203 | accountsNumber = len(httpJSONFile["accounts"])
204 | if (accountsNumber):
205 | accounts = httpJSONFile["accounts"]
206 | self.tableWidgetHttp.setRowCount(accountsNumber)
207 | self.groupBoxHttpAuth.setChecked(True)
208 | for i in range(accountsNumber):
209 | try:user = accounts[i]["user"]
210 | except Exception: user = ""
211 | try:password = accounts[i]["pass"]
212 | except Exception: password = ""
213 |
214 | self.tableWidgetHttp.setItem(i, 0, QTableWidgetItem(str(user)))
215 | self.tableWidgetHttp.setItem(i, 1, QTableWidgetItem(str(password)))
216 | self.tableWidgetHttp.resizeColumnsToContents()
217 | else:self.groupBoxHttpAuth.setChecked(False)
218 |
219 | def createHttpJSONFile(self):
220 | httpJSONFile = {}
221 | httpJSONFile["timeout"] = self.spinBoxHttpTimeout.value()
222 |
223 | if (self.groupBoxHttpAuth.isChecked()):
224 | httpJSONFile["accounts"] = []
225 | accountsNumber = self.tableWidgetHttp.rowCount()
226 | if (accountsNumber):
227 | account = {}
228 | for i in range(accountsNumber):
229 | account["user"] = self.tableWidgetHttp.item(i, 0).text()
230 | account["pass"] = self.tableWidgetHttp.item(i, 1).text()
231 | httpJSONFile["accounts"].append(copy.deepcopy(account))
232 | else:del httpJSONFile["accounts"]
233 |
234 | httpJSONFile["allowTransparent"] = self.checkBoxallowTransparent.isChecked()
235 | httpJSONFile["userLevel"] = self.spinBoxHttpuserLevel.value()
236 |
237 | try:self.treasureChest.addLevel(self.spinBoxHttpuserLevel.value())
238 | except Exception:pass
239 |
240 | return httpJSONFile
241 |
242 | def clearinboundHttpPanel(self):
243 | self.tableWidgetHttp.setRowCount(0)
244 | self.spinBoxHttpTimeout.setValue(300)
245 | self.spinBoxHttpuserLevel.setValue(0)
246 | self.checkBoxallowTransparent.setChecked(False)
247 | self.groupBoxHttpAuth.setChecked(False)
248 | self.tableWidgetHttp.setRowCount(0)
249 |
250 | def __debugTest(self):
251 | import json
252 | print(json.dumps(self.createHttpJSONFile(), indent=4, sort_keys=False))
253 |
254 |
255 | if __name__ == "__main__":
256 | from PyQt5.QtWidgets import QApplication
257 | app = QApplication(sys.argv)
258 | ex = HttpPanel()
259 | ex.createHttpSettingPanel()
260 | ex.setGeometry(300, 300, 600, 420)
261 | ex.show()
262 | sys.exit(app.exec_())
263 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/inbound/mtPanel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QWidget, QLabel, QTableView,
4 | QHBoxLayout, QGroupBox, QPushButton,
5 | QTableWidget, QAbstractItemView, QButtonGroup,
6 | QVBoxLayout, QTableWidgetItem)
7 |
8 | from PyQt5.QtCore import QFileInfo, QCoreApplication
9 | from PyQt5.Qt import QStandardItemModel, QModelIndex
10 |
11 | import sys, copy
12 |
13 | v2rayshellDebug = False
14 |
15 | if __name__ == "__main__":
16 | v2rayshellDebug = True
17 | # this for debug test
18 | path = QFileInfo(sys.argv[0])
19 | srcPath = path.absoluteFilePath().split("/")
20 | sys.path.append("/".join(srcPath[:-4]))
21 |
22 | from bridgehouse.editMap.toolbox import toolbox
23 |
24 | class InboundMtPanel(QWidget):
25 | def __init__(self):
26 | super().__init__()
27 | self.mtJSONFile = {
28 | "users": [{
29 | "email": "love@v2ray.com",
30 | "level": 0,
31 | "secret": "b0cbcef5a486d9636472ac27f8e11a9d"
32 | }]
33 | }
34 | self.translate = QCoreApplication.translate
35 |
36 | self.labelUsermtPanel = (self.translate("InboundMtPanel", "Email"),
37 | self.translate("InboundMtPanel", "Level"),
38 | self.translate("InboundMtPanel", "Password"))
39 |
40 | def createmtSettingPanel(self):
41 | UUIDdelegate = toolbox.UUIDLineEditDelegate(
42 | self.translate("InboundMtPanel", "Gerate UUID"))
43 |
44 | self.model = QStandardItemModel(0, 3)
45 | self.tableViewInMtUser = tableViewUser = QTableView(self)
46 | tableViewUser.setModel(self.model)
47 | self.model.setHorizontalHeaderLabels(self.labelUsermtPanel)
48 | tableViewUser.setSelectionMode(QAbstractItemView.SingleSelection)
49 | tableViewUser.setSelectionBehavior(QAbstractItemView.SelectRows)
50 |
51 | tableViewUser.setItemDelegateForColumn(2, UUIDdelegate)
52 |
53 | self.btnInMtNew = QPushButton(
54 | self.translate("InboundMtPanel", "New"), self)
55 | self.btnInMtDelete = QPushButton(
56 | self.translate("InboundMtPanel", "Delete"), self)
57 |
58 | self.btnGroup = QButtonGroup()
59 | self.btnGroup.addButton(self.btnInMtNew)
60 | self.btnGroup.addButton(self.btnInMtDelete)
61 |
62 | vboxBtn = QVBoxLayout()
63 | vboxBtn.addWidget(QLabel())
64 | vboxBtn.addWidget(QLabel())
65 | vboxBtn.addWidget(QLabel())
66 | vboxBtn.addWidget(self.btnInMtNew)
67 | vboxBtn.addWidget(self.btnInMtDelete)
68 |
69 | hbox = QHBoxLayout()
70 | hbox.addWidget(tableViewUser)
71 | hbox.addLayout(vboxBtn)
72 |
73 | self.groupInboudnMtPanel = QGroupBox(
74 | self.translate("InboundMtPanel", "MTProto"), self)
75 | self.groupInboudnMtPanel.setLayout(hbox)
76 |
77 | self.createInboundMtPanelSignals()
78 |
79 | if (v2rayshellDebug):
80 | self.__debugBtn = QPushButton("__debugTest", self)
81 | vboxBtn.addWidget(self.__debugBtn)
82 | self.__debugBtn.clicked.connect(self.__debugTest)
83 | self.settingInboundMtPanelFromJSONFile(self.mtJSONFile, True)
84 |
85 | return self.groupInboudnMtPanel
86 |
87 | def createInboundMtPanelSignals(self):
88 | self.btnGroup.buttonClicked.connect(self.onInboundMtbtnGroup)
89 |
90 | def onInboundMtbtnGroup(self, e):
91 | if e.text() == self.translate("InboundMtPanel", "New"):
92 | self.onbtnInboundMtNew()
93 | if e.text() == self.translate("InboundMtPanel", "Delete"):
94 | self.onbtnInboundMtDelete()
95 |
96 | def onbtnInboundMtNew(self):
97 | row = self.model.rowCount()
98 | if not row:
99 | self.model.setRowCount(row+1)
100 | self.setRowData(row)
101 | else:
102 | if (self.model.index(row-1, 2, QModelIndex()).data()):
103 | self.model.setRowCount(row+1)
104 | self.setRowData(row)
105 |
106 | def setRowData(self, row, email=None, level=None, secret=None):
107 | indexEmail = self.model.index(row, 0, QModelIndex())
108 | indexLevel = self.model.index(row, 1, QModelIndex())
109 | indexSecret = self.model.index(row, 2, QModelIndex())
110 |
111 | self.model.setData(indexEmail, "" if not email else email)
112 | self.model.setData(indexLevel, 0 if not level else level)
113 | self.model.setData(indexSecret, 0 if not secret else secret)
114 |
115 | try:
116 | if level: self.treasureChest.addLevel(int(level))
117 | if email: self.treasureChest.addEmail(str(email))
118 | except Exception: pass
119 |
120 | def onbtnInboundMtDelete(self):
121 | row = self.tableViewInMtUser.selectedIndexes()
122 | if row:
123 | self.model.removeRow(row[0].row())
124 |
125 | def settingInboundMtPanelFromJSONFile(self, inboundMtJSONFile=None, openFromJSONFile=False):
126 | if not inboundMtJSONFile:
127 | inboundMtJSONFile = {}
128 |
129 | try:
130 | inboundMtJSONFile['users']
131 | except KeyError:
132 | inboundMtJSONFile['users'] = list()
133 |
134 | if inboundMtJSONFile['users']:
135 | for row, user in enumerate(inboundMtJSONFile['users']):
136 | email = level = secret = None
137 | try:
138 | email = user['email']
139 | except KeyError:
140 | pass
141 | try:
142 | level = user['level']
143 | except KeyError:
144 | pass
145 | try:
146 | secret = user['secret']
147 | except KeyError:
148 | pass
149 | self.model.setRowCount(row+1)
150 | self.setRowData(row, email, level, secret)
151 |
152 | def createInboundMtJSONFile(self):
153 | inboundMtJSONFile = {}
154 | inboundMtJSONFile['users'] = list()
155 |
156 | usersNumber = self.model.rowCount()
157 | for row in range(usersNumber):
158 | userData = {}
159 | userData['email'] = self.model.index(row, 0, QModelIndex()).data()
160 | userData['level'] = self.model.index(row, 1, QModelIndex()).data()
161 | userData['secret'] = ''.join(str(self.model.index(row, 2, QModelIndex()).data()).split('-'))
162 | inboundMtJSONFile['users'].append(copy.deepcopy(userData))
163 |
164 | return inboundMtJSONFile
165 |
166 | def clearinboundMtPanel(self):
167 | self.model.setRowCount(0)
168 |
169 | def __debugTest(self):
170 | import json
171 | print(json.dumps(self.createInboundMtJSONFile(), indent=4, sort_keys=False))
172 |
173 |
174 | if __name__ == "__main__":
175 | from PyQt5.QtWidgets import QApplication
176 | app = QApplication(sys.argv)
177 | ex = InboundMtPanel()
178 | ex.createmtSettingPanel()
179 | ex.setGeometry(300, 300, 600, 420)
180 | ex.show()
181 | sys.exit(app.exec_())
182 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/inbound/shadowsocksPanel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QWidget, QLabel, QLineEdit, QComboBox, QSpinBox,
4 | QCheckBox, QGridLayout, QVBoxLayout,
5 | QGroupBox, QPushButton, QHBoxLayout)
6 | from PyQt5.QtCore import QFileInfo, QCoreApplication
7 |
8 | import sys
9 |
10 | v2rayshellDebug = False
11 |
12 | if __name__ == "__main__":
13 | v2rayshellDebug = True
14 | # this for debug test
15 | path = QFileInfo(sys.argv[0])
16 | srcPath = path.absoluteFilePath().split("/")
17 | sys.path.append("/".join(srcPath[:-4]))
18 |
19 | from bridgehouse.editMap.inbound import logbook
20 |
21 |
22 | class InboundShadowsocksPanel(QWidget):
23 |
24 | def __init__(self):
25 | super().__init__()
26 | self.inboundShadowsocksJSONFile = {
27 | "email": "",
28 | "method": "",
29 | "password": "",
30 | "udp": False,
31 | "level": 1,
32 | "ota": True,
33 | "network": "tcp,udp"
34 | }
35 | self.listMethodShadowsocksPanel = "aes-256-cfb", "aes-128-cfb", "chacha20", "chacha20-ietf", "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305"
36 | self.translate = QCoreApplication.translate
37 |
38 | def createShadowsocksSettingPanel(self):
39 | labelEmail = QLabel(
40 | self.translate("InboundShadowsocksPanel", "Email: "), self)
41 | self.lineEditInboundShadowsocksEmail = QLineEdit()
42 | labelMethod = QLabel(
43 | self.translate("InboundShadowsocksPanel", "Method: "), self)
44 | self.comboBoxInboundShadowsocksMethod = QComboBox()
45 | labelPassowrd = QLabel(
46 | self.translate("InboundShadowsocksPanel", "Password: "), self)
47 | self.lineEditInboundShadowsocksPassowrd = QLineEdit()
48 | self.checkBoxInboundShadowsocksUDP = QCheckBox(
49 | self.translate("InboundShadowsocksPanel", "open UDP forwarding"), self)
50 | labelLevel = QLabel(
51 | self.translate("InboundShadowsocksPanel", "User Level: "), self)
52 | self.spinBoxInboundShadowsocksLevel = QSpinBox()
53 | self.checkBoxInboundShadowsocksOTA = QCheckBox(
54 | self.translate("InboundShadowsocksPanel", "One Time Auth (OTA)"), self)
55 | labelNetwork = QLabel(self.translate("InboundShadowsocksPanel", "Network: "), self)
56 | self.checkBoxNewtworkTCP = QCheckBox("TCP", self)
57 | self.checkBoxNewtworkUDP = QCheckBox("UDP", self)
58 | hboxNetwork = QHBoxLayout()
59 | hboxNetwork.addWidget(self.checkBoxNewtworkTCP)
60 | hboxNetwork.addWidget(self.checkBoxNewtworkUDP)
61 | hboxNetwork.addStretch()
62 |
63 | self.comboBoxInboundShadowsocksMethod.addItems(self.listMethodShadowsocksPanel)
64 | self.checkBoxInboundShadowsocksUDP.setChecked(False)
65 | self.spinBoxInboundShadowsocksLevel.setRange(0, 65535)
66 | self.spinBoxInboundShadowsocksLevel.setValue(0)
67 | self.checkBoxNewtworkTCP.setChecked(True)
68 | self.checkBoxNewtworkUDP.setChecked(False)
69 | self.checkBoxInboundShadowsocksUDP.setVisible(False)
70 | self.checkBoxInboundShadowsocksUDP.setChecked(False)
71 |
72 | gridBoxInboundShadowsocks = QGridLayout(self)
73 | gridBoxInboundShadowsocks.addWidget(labelEmail, 0, 0)
74 | gridBoxInboundShadowsocks.addWidget(self.lineEditInboundShadowsocksEmail, 0, 1)
75 | gridBoxInboundShadowsocks.addWidget(labelMethod, 1, 0)
76 | gridBoxInboundShadowsocks.addWidget(self.comboBoxInboundShadowsocksMethod, 1, 1)
77 | gridBoxInboundShadowsocks.addWidget(labelPassowrd, 2, 0)
78 | gridBoxInboundShadowsocks.addWidget(self.lineEditInboundShadowsocksPassowrd, 2, 1)
79 | gridBoxInboundShadowsocks.addWidget(labelLevel, 3, 0)
80 | gridBoxInboundShadowsocks.addWidget(labelNetwork, 6, 0)
81 | gridBoxInboundShadowsocks.addLayout(hboxNetwork, 6, 1)
82 |
83 | hboxLevel = QHBoxLayout()
84 | hboxLevel.addWidget(self.spinBoxInboundShadowsocksLevel)
85 | hboxLevel.addStretch()
86 | gridBoxInboundShadowsocks.addLayout(hboxLevel, 3, 1)
87 |
88 | gridBoxInboundShadowsocks.addWidget(self.checkBoxInboundShadowsocksUDP, 4, 0)
89 | gridBoxInboundShadowsocks.addWidget(self.checkBoxInboundShadowsocksOTA, 5, 0)
90 |
91 | if (v2rayshellDebug):
92 | self.__debugBtn = QPushButton("__debugTest", self)
93 | gridBoxInboundShadowsocks.addWidget(self.__debugBtn, 7, 0)
94 | self.__debugBtn.clicked.connect(self.__debugTest)
95 | self.settingInboundShadowsocksPanelFromJSONFile(self.inboundShadowsocksJSONFile, True)
96 |
97 | groupBoxInboundShadowsocks = QGroupBox(
98 | self.translate("InboundShadowsocksPanel", "Shadowsocks"), self)
99 | groupBoxInboundShadowsocks.setLayout(gridBoxInboundShadowsocks)
100 |
101 | self.createShadowsocksPanelSignals()
102 |
103 | return groupBoxInboundShadowsocks
104 |
105 | def createShadowsocksPanelSignals(self):
106 | pass
107 |
108 | def settingInboundShadowsocksPanelFromJSONFile(self, inboundShadowsocksJSONFile=None, openFromJSONFile=False):
109 | logbook.setisOpenJSONFile(openFromJSONFile)
110 |
111 | if (not inboundShadowsocksJSONFile): inboundShadowsocksJSONFile = {}
112 |
113 | try:
114 | inboundShadowsocksJSONFile["email"]
115 | except KeyError as e:
116 | logbook.writeLog("InboundShadowsocks", "KeyError", e)
117 | inboundShadowsocksJSONFile["email"] = ""
118 | try:
119 | inboundShadowsocksJSONFile["method"]
120 | except KeyError as e:
121 | logbook.writeLog("InboundShadowsocks", "KeyError", e)
122 | inboundShadowsocksJSONFile["method"] = ""
123 |
124 | try:
125 | inboundShadowsocksJSONFile["password"]
126 | except KeyError as e:
127 | logbook.writeLog("InboundShadowsocks", "KeyError", e)
128 | inboundShadowsocksJSONFile["password"] = ""
129 |
130 | try:
131 | inboundShadowsocksJSONFile["udp"]
132 | except KeyError as e:
133 | logbook.writeLog("InboundShadowsocks", "KeyError", e)
134 | inboundShadowsocksJSONFile["udp"] = False
135 |
136 | try:
137 | inboundShadowsocksJSONFile["level"]
138 | except KeyError as e:
139 | logbook.writeLog("InboundShadowsocks", "KeyError", e)
140 | inboundShadowsocksJSONFile["level"] = 1
141 |
142 | try:
143 | inboundShadowsocksJSONFile["ota"]
144 | except KeyError as e:
145 | logbook.writeLog("InboundShadowsocks", "KeyError", e)
146 | inboundShadowsocksJSONFile["ota"] = True
147 |
148 | try:
149 | inboundShadowsocksJSONFile["network"]
150 | except KeyError as e:
151 | logbook.writeLog("InboundShadowsocks", "KeyError", e)
152 | inboundShadowsocksJSONFile["network"] = "tcp"
153 |
154 | self.lineEditInboundShadowsocksEmail.setText(str(inboundShadowsocksJSONFile["email"]))
155 | self.comboBoxInboundShadowsocksMethod.setCurrentText(str(inboundShadowsocksJSONFile["method"]))
156 | self.lineEditInboundShadowsocksPassowrd.setText(str(inboundShadowsocksJSONFile["password"]))
157 | self.checkBoxInboundShadowsocksUDP.setChecked(bool(inboundShadowsocksJSONFile["udp"]))
158 | self.checkBoxInboundShadowsocksOTA.setChecked(bool(inboundShadowsocksJSONFile["ota"]))
159 |
160 | try:
161 | self.spinBoxInboundShadowsocksLevel.setValue(int(inboundShadowsocksJSONFile["level"]))
162 | except (TypeError, ValueError) as e:
163 | logbook.writeLog("InboundShadowsocks", "KeyError", e)
164 | self.spinBoxInboundShadowsocksLevel.setValue(1)
165 |
166 | try:
167 | self.treasureChest.addLevel(self.spinBoxInboundShadowsocksLevel.value())
168 | self.treasureChest.addEmail(self.lineEditInboundShadowsocksEmail.text())
169 | except Exception:
170 | pass
171 |
172 | network = [x.strip() for x in str(inboundShadowsocksJSONFile["network"]).split(",")]
173 |
174 | if (network):
175 | if "tcp" in network:
176 | self.checkBoxNewtworkTCP.setChecked(True)
177 | else:
178 | self.checkBoxNewtworkTCP.setChecked(False)
179 | if "udp" in network:
180 | self.checkBoxNewtworkUDP.setChecked(True)
181 | else:
182 | self.checkBoxNewtworkUDP.setChecked(False)
183 |
184 | def createInboundShadowsocksJSONFile(self):
185 | inboundShadowsocksJSONFile = {}
186 | inboundShadowsocksJSONFile["email"] = self.lineEditInboundShadowsocksEmail.text()
187 | inboundShadowsocksJSONFile["method"] = self.comboBoxInboundShadowsocksMethod.currentText()
188 | inboundShadowsocksJSONFile["password"] = self.lineEditInboundShadowsocksPassowrd.text()
189 | inboundShadowsocksJSONFile["udp"] = self.checkBoxInboundShadowsocksUDP.isChecked()
190 | inboundShadowsocksJSONFile["level"] = self.spinBoxInboundShadowsocksLevel.value()
191 | inboundShadowsocksJSONFile["ota"] = self.checkBoxInboundShadowsocksOTA.isChecked()
192 |
193 | network = None
194 | tcp = "tcp" if self.checkBoxNewtworkTCP.isChecked() else None
195 | udp = "udp" if self.checkBoxInboundShadowsocksUDP.isChecked() else None
196 | udp = "udp" if self.checkBoxNewtworkUDP.isChecked() else None
197 |
198 | if (not tcp and udp):
199 | network = udp
200 | if (tcp and not udp):
201 | network = tcp
202 | if (tcp and udp):
203 | network = None
204 | network = tcp + "," + udp
205 |
206 | inboundShadowsocksJSONFile["network"] = network
207 | if not network:
208 | inboundShadowsocksJSONFile["network"] = "tcp" # V2Ray 3.16+ default is "tcp"
209 |
210 | try:
211 | self.treasureChest.addLevel(self.spinBoxInboundShadowsocksLevel.value())
212 | self.treasureChest.addEmail(self.lineEditInboundShadowsocksEmail.text())
213 | except Exception:
214 | pass
215 |
216 | return inboundShadowsocksJSONFile
217 |
218 | def clearinboundShadowsocksPanel(self):
219 | self.lineEditInboundShadowsocksEmail.clear()
220 | self.comboBoxInboundShadowsocksMethod.setCurrentIndex(0)
221 | self.lineEditInboundShadowsocksPassowrd.clear()
222 | self.checkBoxInboundShadowsocksUDP.setChecked(False)
223 | self.checkBoxInboundShadowsocksOTA.setChecked(False)
224 | self.checkBoxNewtworkTCP.setChecked(False)
225 | self.checkBoxNewtworkUDP.setChecked(False)
226 | self.spinBoxInboundShadowsocksLevel.setValue(0)
227 |
228 | def __debugTest(self):
229 | import json
230 | print(json.dumps(self.createInboundShadowsocksJSONFile(), indent=4, sort_keys=False))
231 |
232 |
233 | if __name__ == "__main__":
234 | from PyQt5.QtWidgets import QApplication
235 | app = QApplication(sys.argv)
236 | ex = InboundShadowsocksPanel()
237 | v = QVBoxLayout()
238 | v.addWidget(ex.createShadowsocksSettingPanel())
239 | ex.setLayout(v)
240 | ex.setGeometry(300, 300, 680, 260)
241 | ex.show()
242 | sys.exit(app.exec_())
243 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/logTAB.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QLabel, QWidget, QHBoxLayout, QVBoxLayout,
4 | QPushButton, QButtonGroup, QLineEdit,
5 | QFileDialog, QComboBox, QGroupBox)
6 | from PyQt5.QtCore import QDate, QTime, qWarning, QFileInfo, QCoreApplication
7 |
8 | import sys, json
9 | v2rayshellDebug = False
10 |
11 | if __name__ == "__main__":
12 | v2rayshellDebug = True
13 | # this for debug test
14 | path = QFileInfo(sys.argv[0])
15 | srcPath = path.absoluteFilePath().split("/")
16 | sys.path.append("/".join(srcPath[:-3]))
17 |
18 |
19 | class logBook():
20 | """
21 | Check the status of the v2ray before departure
22 | """
23 |
24 | def __init__(self, openFromJSONFile=False):
25 | # only record the debug message when use open conf.json file
26 | self.openFile = openFromJSONFile
27 |
28 | def setisOpenJSONFile(self, openFromJSONFile):
29 | self.openFile = openFromJSONFile
30 |
31 | def getTime(self):
32 | return QDate.currentDate().toString() + " " + QTime.currentTime().toString("HH:mm:ss")
33 |
34 | def writeLog(self, cabin, situation, log="unkonw"):
35 | if (self.openFile):
36 | if (situation == "KeyError"):
37 | qWarning("Date: {} ---> {} Panel analysis of JSON file error. can not find the key {}, use default value.".format(self.getTime(), cabin, log))
38 | elif (situation == "ValueError or TypeError" or
39 | situation == "ValueError" or
40 | situation == "TypeError"):
41 | qWarning("Date: {} ---> {} Panel analysis of JSON file error. can not use this value {}, use default value.".format(self.getTime(), cabin, log))
42 | else:
43 | qWarning("Date: {} ---> {} Panel analysis of JSON file error. have a error:--> {} <--".format(self.getTime(), cabin, log))
44 |
45 |
46 | class logTab(QWidget):
47 |
48 | def __init__(self):
49 | super().__init__()
50 | self.logJSONFile = {
51 | "access": "",
52 | "error": "",
53 | "loglevel": "warning"
54 | }
55 | self.translate = QCoreApplication.translate
56 |
57 | def createLogTab(self):
58 | labelAccess = QLabel(
59 | self.translate("logTab", "Access File: "))
60 | labelError = QLabel(
61 | self.translate("logTab", "Error File: "))
62 | self.lineEditAccess = QLineEdit()
63 | self.lineEditError = QLineEdit()
64 |
65 | btnSaveAccess = QPushButton(
66 | self.translate("logTab", "&Save"), self)
67 | btnSaveError = QPushButton(
68 | self.translate("logTab", "S&ave"), self)
69 |
70 | labelLogLevel = QLabel(self.translate("logTab", "Log Level: "), self)
71 | self.comboxLogLevel = QComboBox()
72 | self.comboxLogLevel.addItems(("warning", "debug", "info", "error" , "none"))
73 |
74 | self.buttonGroupSave = QButtonGroup()
75 | self.buttonGroupSave.addButton(btnSaveAccess)
76 | self.buttonGroupSave.addButton(btnSaveError)
77 |
78 | hboxAccess = QHBoxLayout()
79 | hboxAccess.addWidget(labelAccess)
80 | hboxAccess.addWidget(self.lineEditAccess)
81 | hboxAccess.addWidget(btnSaveAccess)
82 |
83 | hboxError = QHBoxLayout()
84 | hboxError.addWidget(labelError)
85 | hboxError.addWidget(self.lineEditError)
86 | hboxError.addWidget(btnSaveError)
87 |
88 | hboxLogLevel = QHBoxLayout()
89 | hboxLogLevel.addWidget(labelLogLevel)
90 | hboxLogLevel.addWidget(self.comboxLogLevel)
91 | hboxLogLevel.addStretch()
92 |
93 | vboxLogPanel = QVBoxLayout()
94 | vboxLogPanel.addLayout(hboxAccess)
95 | vboxLogPanel.addLayout(hboxError)
96 | vboxLogPanel.addLayout(hboxLogLevel)
97 | vboxLogPanel.addStretch()
98 |
99 | self.setLayout(vboxLogPanel)
100 |
101 | groupBoxLogTAB = QGroupBox("", self)
102 | groupBoxLogTAB.setLayout(vboxLogPanel)
103 |
104 | self.createLogTabSignals()
105 |
106 | if (v2rayshellDebug):
107 | self.__debugBtn = QPushButton("__debugTest", self)
108 | vboxLogPanel.addWidget(self.__debugBtn)
109 | self.__debugBtn.clicked.connect(self.__debugTest)
110 | self.settingLogTabFromJSONFile(self.logJSONFile, True)
111 |
112 | return groupBoxLogTAB
113 |
114 | def createLogTabSignals(self):
115 | self.buttonGroupSave.buttonClicked.connect(self.onbuttonGroupSave)
116 |
117 | def onbuttonGroupSave(self, e):
118 | options = QFileDialog.Options()
119 | if (e.text() == self.translate("logTab", "&Save")):
120 | fileName, _ = QFileDialog.getSaveFileName(self,
121 | self.translate("logTab", "Save V2ray Access log file"),
122 | "_access",
123 | "Log Files (*.log)",
124 | options=options)
125 | self.lineEditAccess.setText(fileName)
126 |
127 | if (e.text() == self.translate("logTab", "S&ave")):
128 | fileName, _ = QFileDialog.getSaveFileName(self,
129 | self.translate("logTab", "Save V2ray Error log file"),
130 | "_error",
131 | "Log Files (*.log)",
132 | options=options)
133 | self.lineEditError.setText(fileName)
134 |
135 | def settingLogTabFromJSONFile(self, logJSONFile={}, openFromJSONFile=False):
136 | logTagslog = logBook(openFromJSONFile)
137 |
138 | if (not logJSONFile): logJSONFile = {}
139 |
140 | try:
141 | logJSONFile["access"]
142 | except KeyError as e:
143 | logTagslog.writeLog("LogTAB", "KeyError", e)
144 | logJSONFile["access"] = ""
145 |
146 | try:
147 | logJSONFile["error"]
148 | except KeyError as e:
149 | logTagslog.writeLog("LogTAB", "KeyError", e)
150 | logJSONFile["error"] = ""
151 |
152 | try:
153 | logJSONFile["loglevel"]
154 | except KeyError as e:
155 | logTagslog.writeLog("LogTAB", "KeyError", e)
156 | logJSONFile["loglevel"] = "warning"
157 |
158 | self.lineEditAccess.setText(str(logJSONFile["access"]))
159 | self.lineEditError.setText(str(logJSONFile["error"]))
160 | try:
161 | self.comboxLogLevel.setCurrentText(str(logJSONFile["loglevel"]))
162 | except (ValueError, TypeError) as e:
163 | logTagslog.writeLog("LogTAB", "ValueError or TypeError", e)
164 |
165 | def createLogJSONFile(self):
166 | logJSONFile = {}
167 | logJSONFile["access"] = self.lineEditAccess.text()
168 | logJSONFile["error"] = self.lineEditError.text()
169 | logJSONFile["loglevel"] = self.comboxLogLevel.currentText()
170 |
171 | return logJSONFile
172 |
173 | def __debugTest(self):
174 | print(json.dumps(self.createLogJSONFile(), indent=4, sort_keys=False))
175 |
176 |
177 | if __name__ == "__main__":
178 | from PyQt5.QtWidgets import QApplication
179 | app = QApplication(sys.argv)
180 | ex = logTab()
181 | ex.createLogTab()
182 | ex.setGeometry(200, 100, 380, 180)
183 | ex.show()
184 | sys.exit(app.exec_())
185 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/nauticalChartPanel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QWidget, QButtonGroup, QVBoxLayout, QApplication,
4 | QTabWidget, QScrollArea, QHBoxLayout, QPushButton,
5 | QDialog, QFileDialog)
6 | from PyQt5.QtCore import QFileInfo, QCoreApplication
7 | import sys, json
8 |
9 | v2rayshellDebug = False
10 |
11 | if __name__ == "__main__":
12 | v2rayshellDebug = True
13 | # this for debug test
14 | path = QFileInfo(sys.argv[0])
15 | srcPath = path.absoluteFilePath().split("/")
16 | sys.path.append("/".join(srcPath[:-3]))
17 |
18 | from bridgehouse.editMap.port import (inboundPanel, outboundPanel, logbook, openV2rayJSONFile, treasureChest)
19 | from bridgehouse.editMap import (logTAB, dnsTAB, transportTAB, routingTAB, policyTAB, apiTAB)
20 |
21 |
22 | class nauticalChartPanel(QDialog):
23 |
24 | def __init__(self, filePath=False):
25 | super().__init__()
26 | self.configJSONFile = {
27 | "log": {},
28 | "dns": {},
29 | "api": {},
30 | "stats": {},
31 | "routing": {},
32 | "policy": {},
33 | "inbound": {},
34 | "outbound": {},
35 | "inboundDetour": [],
36 | "outboundDetour": [],
37 | "transport": {}
38 | }
39 | self.filePath = filePath
40 | self.treasureChest = treasureChest.treasureChest()
41 | self.translate = QCoreApplication.translate
42 |
43 | def createPanel(self):
44 | hboxButton = QHBoxLayout()
45 | btnSave = QPushButton(self.translate("nauticalChartPanel", "Save"))
46 | btnExit = QPushButton(self.translate("nauticalChartPanel", "Exit"))
47 | self.groupButtonConfigure = QButtonGroup()
48 | self.groupButtonConfigure.addButton(btnSave)
49 | self.groupButtonConfigure.addButton(btnExit)
50 |
51 | hboxButton.addStretch()
52 | hboxButton.addWidget(btnSave)
53 | hboxButton.addWidget(btnExit)
54 |
55 | self.inbound = inboundPanel.InboundPanel(self.treasureChest)
56 | self.outbound = outboundPanel.OutboundPanel(self.treasureChest)
57 |
58 | tabWidgetConfigurePanel = QTabWidget()
59 | tabWidgetConfigurePanel.addTab(
60 | self.inbound.createInboundPanel(),
61 | self.translate("nauticalChartPanel", "Inbound"))
62 | tabWidgetConfigurePanel.addTab(
63 | self.outbound.createOutboundPanel(),
64 | self.translate("nauticalChartPanel", "Outbound"))
65 |
66 | self.transportTAB = transportTAB.transportTab()
67 | tabWidgetConfigurePanel.addTab(
68 | self.transportTAB.createTransportPanel(),
69 | self.translate("nauticalChartPanel", "Transport Setting"))
70 |
71 | self.dnsTAB = dnsTAB.dnsTab()
72 | tabWidgetConfigurePanel.addTab(
73 | self.dnsTAB.createDnsTab(),
74 | self.translate("nauticalChartPanel", "DNS Server"))
75 |
76 | self.routingTAB = routingTAB.routingTab()
77 | tabWidgetConfigurePanel.addTab(
78 | self.routingTAB.createRoutingTab(),
79 | self.translate("nauticalChartPanel", "Router Setting"))
80 |
81 | self.policyTAB = policyTAB.policyTab(self.treasureChest)
82 | tabWidgetConfigurePanel.addTab(
83 | self.policyTAB.createPolicyTab(),
84 | self.translate("nauticalChartPanel", "Policy"))
85 |
86 | self.logTAB = logTAB.logTab()
87 | tabWidgetConfigurePanel.addTab(
88 | self.logTAB.createLogTab(),
89 | self.translate("nauticalChartPanel", "Log Files"))
90 |
91 | self.apiTAB = apiTAB.apiTAB(self.treasureChest)
92 | tabWidgetConfigurePanel.addTab(self.apiTAB.createapiTAB(), "Api")
93 |
94 | vboxConfigure = QVBoxLayout()
95 | vboxConfigure.addWidget(tabWidgetConfigurePanel)
96 | vboxConfigure.addLayout(hboxButton)
97 | self.ScrollLayout(vboxConfigure)
98 |
99 | if (v2rayshellDebug):
100 | self.__debugBtn = QPushButton("__debugTest", self)
101 | self.__debugRefresh = QPushButton("__RefreshTest", self)
102 | self.__printTags = QPushButton("__PrintTags", self)
103 | self.__printAllLevels = QPushButton("__PrintAllLevels", self)
104 | self.__printAllEmails = QPushButton("__PrintAllEmails", self)
105 |
106 | hboxBtn = QHBoxLayout(self)
107 | hboxBtn.addWidget(self.__debugBtn)
108 | hboxBtn.addWidget(self.__printTags)
109 | hboxBtn.addWidget(self.__printAllLevels)
110 | hboxBtn.addWidget(self.__printAllEmails)
111 | hboxBtn.addWidget(self.__debugRefresh)
112 | vboxConfigure.addLayout(hboxBtn)
113 |
114 | self.__debugBtn.clicked.connect(self.__debugTest)
115 | self.__debugRefresh.clicked.connect(self.__debugRefreshTest)
116 | self.__printTags.clicked.connect(lambda: print(self.treasureChest.getAllTags()))
117 | self.__printAllLevels.clicked.connect(lambda: print(self.treasureChest.getLevels()))
118 | self.__printAllEmails.clicked.connect(lambda: print(self.treasureChest.getEmails()))
119 |
120 | self.editV2rayJSONFile = openV2rayJSONFile.editV2rayJSONFile(self.treasureChest)
121 | tabWidgetConfigurePanel.addTab(self.editV2rayJSONFile.createPanel(), "open V2ray File")
122 | self.settingv2rayshellPanelFromJSONFile(True)
123 |
124 | if (self.filePath):
125 | openV2rayJSONFile.openV2rayJSONFile(self.filePath, self.treasureChest).initboundJSONData()
126 | self.settingv2rayshellPanelFromJSONFile(openFromJSONFile=True)
127 |
128 | self.createnauticalChartPanelSignals()
129 |
130 | def createnauticalChartPanelSignals(self):
131 | self.groupButtonConfigure.buttonClicked.connect(self.ongroupButtonConfigureclicked)
132 |
133 | def ongroupButtonConfigureclicked(self, e):
134 | if e.text() == self.translate("nauticalChartPanel", "Exit"):
135 | self.close()
136 | elif e.text() == self.translate("nauticalChartPanel", "Save"):
137 | self.savenauticalChart(self.createv2rayJSONFile())
138 |
139 | def savenauticalChart(self, JSONData):
140 | JSONData = json.dumps(JSONData, indent=4, sort_keys=False)
141 | options = QFileDialog.Options()
142 | filePath, _ = QFileDialog.getSaveFileName(self,
143 | self.translate("nauticalChartPanel", "Save V2Ray config.json File"),
144 | "config.json",
145 | """
146 | json file (*.json);;
147 | All Files (*)
148 | """,
149 | options=options)
150 | if (filePath):
151 | openV2rayJSONFile.openV2rayJSONFile().saveTextdata(filePath=filePath,
152 | data=JSONData)
153 |
154 | def settingv2rayshellPanelFromJSONFile(self, openFromJSONFile=False):
155 | logbook.setisOpenJSONFile(openFromJSONFile)
156 | if (openFromJSONFile):
157 | self.inbound.refreshInboundPaneltableWidget()
158 | self.outbound.refreshOutboundPaneltableWidget()
159 | self.routingTAB.settingRoutingTABFromJSONFile(
160 | routingJSONFile=self.treasureChest.getRouting(), openFromJSONFile=True)
161 | self.logTAB.settingLogTabFromJSONFile(
162 | logJSONFile=self.treasureChest.getLog(), openFromJSONFile=True)
163 | tansportJSONData = self.treasureChest.getTransport()
164 | if (tansportJSONData):
165 | self.transportTAB.settingtransportPanelFromJSONFile(
166 | transportJSONFile=tansportJSONData, openFromJSONFile=True)
167 | self.transportTAB.groupTransportPanel.setChecked(True)
168 | else:
169 | pass
170 | self.dnsTAB.settingDnsTabFromJSONFile(
171 | dnsJSONFile=self.treasureChest.getDns(), openFromJSONFile=True)
172 | self.policyTAB.settingPolicyTabFromJSONFile(
173 | policyJSONFile=self.treasureChest.getPolicy())
174 | self.apiTAB.settingAPITabFromJSONFile(self.treasureChest.getApi())
175 |
176 | def createv2rayJSONFile(self):
177 | self.treasureChest.setDns(self.dnsTAB.createDnsJSONFile())
178 | self.treasureChest.setLog(self.logTAB.createLogJSONFile())
179 | self.treasureChest.setRouting(self.routingTAB.createRoutingJSONFile())
180 | self.treasureChest.setPolicy(JSONDataPolicy=self.policyTAB.createPolicyJSONFile())
181 | if (self.transportTAB.groupTransportPanel.isChecked()):
182 | self.treasureChest.setTransport(self.transportTAB.createtransportSettingJSONFile())
183 | else:
184 | self.treasureChest.setTransport(JSONDataTransport=False)
185 |
186 | if (self.apiTAB.groupBoxAPI.isChecked()):
187 | self.treasureChest.setApi(self.apiTAB.createApiJSONFile())
188 |
189 | v2rayJSONFile = self.treasureChest.exportV2rayJSONFile()
190 |
191 | return v2rayJSONFile
192 |
193 | def __debugTest(self):
194 | print(json.dumps(self.createv2rayJSONFile(), indent=4, sort_keys=False))
195 |
196 | def __debugRefreshTest(self):
197 | self.inbound.refreshInboundPaneltableWidget()
198 | self.outbound.refreshOutboundPaneltableWidget()
199 | self.routingTAB.settingRoutingTABFromJSONFile(
200 | routingJSONFile=self.treasureChest.getRouting(), openFromJSONFile=True)
201 | self.logTAB.settingLogTabFromJSONFile(
202 | logJSONFile=self.treasureChest.getLog(), openFromJSONFile=True)
203 | tansportJSONData = self.treasureChest.getTransport()
204 | if (tansportJSONData):
205 | self.transportTAB.settingtransportPanelFromJSONFile(
206 | transportJSONFile=tansportJSONData, openFromJSONFile=True)
207 | self.transportTAB.groupTransportPanel.setChecked(True)
208 | else:
209 | self.transportTAB.groupTransportPanel.setChecked(False)
210 | self.dnsTAB.settingDnsTabFromJSONFile(
211 | dnsJSONFile=self.treasureChest.getDns(), openFromJSONFile=True)
212 | self.policyTAB.settingPolicyTabFromJSONFile(
213 | policyJSONFile=self.treasureChest.getPolicy())
214 | self.apiTAB.settingAPITabFromJSONFile(self.treasureChest.getApi())
215 |
216 |
217 | def ScrollLayout(self, layout):
218 | box = QVBoxLayout(self)
219 | scroll = QScrollArea(self)
220 | box.addWidget(scroll)
221 | scroll.setWidgetResizable(True)
222 | scrollContent = QWidget(scroll)
223 |
224 | scrollLayout = QVBoxLayout(scrollContent)
225 | scrollContent.setLayout(scrollLayout)
226 |
227 | scrollLayout.addLayout(layout)
228 | scroll.setWidget(scrollContent)
229 |
230 |
231 | if __name__ == "__main__":
232 | app = QApplication(sys.argv)
233 | ex = nauticalChartPanel()
234 | ex.createPanel()
235 | ex.setGeometry(500, 40, 1024, 950)
236 | ex.show()
237 | sys.exit(app.exec_())
238 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/outbound/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from bridgehouse.editMap import logTAB
4 |
5 | logbook = logTAB.logBook()
6 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/outbound/blackholePanel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QWidget, QGroupBox, QRadioButton, QHBoxLayout, QPushButton)
4 | from PyQt5.QtCore import QFileInfo, QCoreApplication
5 | import sys
6 |
7 | v2rayshellDebug = False
8 |
9 | if __name__ == "__main__":
10 | v2rayshellDebug = True
11 | # this for debug test
12 | path = QFileInfo(sys.argv[0])
13 | srcPath = path.absoluteFilePath().split("/")
14 | sys.path.append("/".join(srcPath[:-4]))
15 |
16 | from bridgehouse.editMap.inbound import logbook
17 |
18 |
19 | class BlackholePanel(QWidget):
20 |
21 | def __init__(self):
22 | super().__init__()
23 | self.blackholeJSONFile = {
24 | "response": {
25 | "type": "none"
26 | }
27 | }
28 | self.translate = QCoreApplication.translate
29 |
30 | def createBlackholeSettingPanel(self):
31 | self.radioBtnBlackholeNone = QRadioButton("None", self)
32 | self.radioBtnBlackholeHttp = QRadioButton("Http", self)
33 |
34 | self.radioBtnBlackholeNone.setChecked(True)
35 |
36 | hboxBlackholeSetting = QHBoxLayout()
37 | hboxBlackholeSetting.addWidget(self.radioBtnBlackholeNone)
38 | hboxBlackholeSetting.addWidget(self.radioBtnBlackholeHttp)
39 | hboxBlackholeSetting.addStretch()
40 |
41 | self.groupBoxBlackhole = QGroupBox(self.translate("BlackholePanel", "Blackhole"), self)
42 | self.groupBoxBlackhole.setLayout(hboxBlackholeSetting)
43 |
44 | if (v2rayshellDebug):
45 | self.__debugBtn = QPushButton("__debugTest", self)
46 | hboxBlackholeSetting.addWidget(self.__debugBtn)
47 | self.__debugBtn.clicked.connect(self.__debugTest)
48 | self.settingblackholePanelFromJSONFile(self.blackholeJSONFile, True)
49 |
50 | return self.groupBoxBlackhole
51 |
52 | def settingblackholePanelFromJSONFile(self, blackholeJSONFile={}, openFromJSONFile=False):
53 | logbook.setisOpenJSONFile(openFromJSONFile)
54 |
55 | if (not blackholeJSONFile): blackholeJSONFile = {}
56 |
57 | try:
58 | blackholeJSONFile["response"]
59 | except KeyError as e:
60 | logbook.writeLog("blackhole", "KeyError", e)
61 | blackholeJSONFile["response"] = {}
62 | try:
63 | blackholeJSONFile["response"]["type"]
64 | except KeyError as e:
65 | logbook.writeLog("blackhole", "KeyError", e)
66 | blackholeJSONFile["response"]["type"] = "none"
67 |
68 | blackholetype = blackholeJSONFile["response"]["type"]
69 | if (blackholetype == "http"):
70 | self.radioBtnBlackholeHttp.setChecked(True)
71 | if (blackholetype == "none"):
72 | self.radioBtnBlackholeNone.setChecked(True)
73 |
74 | def createblackholeJSONFile(self):
75 | blackholeJSONFile = {}
76 | blackholeJSONFile["response"] = {}
77 | if (self.radioBtnBlackholeHttp.isChecked()):
78 | blackholeJSONFile["response"]["type"] = "http"
79 | if (self.radioBtnBlackholeNone.isChecked()):
80 | blackholeJSONFile["response"]["type"] = "none"
81 |
82 | return blackholeJSONFile
83 |
84 | def clearblackholePanel(self):
85 | self.radioBtnBlackholeNone.setChecked(True)
86 | self.radioBtnBlackholeHttp.setChecked(False)
87 |
88 | def __debugTest(self):
89 | import json
90 | print(json.dumps(self.createblackholeJSONFile(), indent=4, sort_keys=False))
91 |
92 |
93 | if __name__ == "__main__":
94 | from PyQt5.QtWidgets import QApplication
95 | app = QApplication(sys.argv)
96 | ex = BlackholePanel()
97 | ex.createBlackholeSettingPanel()
98 | ex.setGeometry(300, 300, 680, 600)
99 | ex.show()
100 | sys.exit(app.exec_())
101 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/outbound/freedomPanel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QGroupBox, QLabel, QRadioButton,
4 | QLineEdit, QWidget, QSpinBox, QGridLayout,
5 | QHBoxLayout, QPushButton)
6 | from PyQt5.QtCore import QFileInfo, QCoreApplication
7 | import sys
8 |
9 | v2rayshellDebug = False
10 |
11 | if __name__ == "__main__":
12 | v2rayshellDebug = True
13 | # this for debug test
14 | path = QFileInfo(sys.argv[0])
15 | srcPath = path.absoluteFilePath().split("/")
16 | sys.path.append("/".join(srcPath[:-4]))
17 |
18 | from bridgehouse.editMap.inbound import logbook
19 |
20 |
21 | class FreedomPanel(QWidget):
22 |
23 | def __init__(self):
24 | super().__init__()
25 | self.freedomJSONFile = {
26 | "domainStrategy": "AsIs",
27 | "timeout": 0,
28 | "redirect": "",
29 | "userLevel": 0
30 | }
31 | self.translate = QCoreApplication.translate
32 |
33 | def createFreedomSettingPanel(self):
34 | labelDomainStrategy = QLabel(self.translate("FreedomPanel", "Domain Strategy: "), self)
35 | self.radioBtnFreedomAsIs = QRadioButton(self.translate("FreedomPanel", "AsIs"), self)
36 | self.radioBtnFreedomUseIP = QRadioButton(self.translate("FreedomPanel", "UseIP"), self)
37 | labelTimeout = QLabel(self.translate("FreedomPanel", "Timeout: "), self)
38 | self.spinBoxFreedomTime = QSpinBox(self)
39 | labelRedirect = QLabel(self.translate("FreedomPanel", "Redirect Address: "), self)
40 | self.lineEditFreedomRedirect = QLineEdit(self)
41 |
42 | labeluserLevel = QLabel(
43 | self.translate("FreedomPanel", "User Level: "))
44 | self.spinBoxFreedomsuserLevel = QSpinBox()
45 | self.spinBoxFreedomsuserLevel.setRange(0, 65535)
46 | self.spinBoxFreedomsuserLevel.setValue(0)
47 | hboxuserLevel = QHBoxLayout()
48 | hboxuserLevel.addWidget(labeluserLevel)
49 | hboxuserLevel.addWidget(self.spinBoxFreedomsuserLevel)
50 | hboxuserLevel.addStretch()
51 |
52 | self.radioBtnFreedomAsIs.setChecked(True)
53 | self.spinBoxFreedomTime.setRange(0, 999)
54 |
55 | groupBoxFreedom = QGroupBox(self.translate("FreedomPanel", "Freedom"), self)
56 |
57 | hboxRdBtn = QHBoxLayout()
58 | hboxRdBtn.addWidget(labelDomainStrategy)
59 | hboxRdBtn.addWidget(self.radioBtnFreedomAsIs)
60 | hboxRdBtn.addWidget(self.radioBtnFreedomUseIP)
61 | hboxRdBtn.addStretch()
62 |
63 | hboxTimeout = QHBoxLayout()
64 | hboxRedirct = QHBoxLayout()
65 | hboxTimeout.addWidget(labelTimeout)
66 | hboxTimeout.addWidget(self.spinBoxFreedomTime)
67 | hboxTimeout.addStretch()
68 |
69 | hboxRedirct.addWidget(labelRedirect)
70 | hboxRedirct.addWidget(self.lineEditFreedomRedirect)
71 | hboxRedirct.addStretch()
72 |
73 | gridLayoutFreedom = QGridLayout()
74 | gridLayoutFreedom.addLayout(hboxRdBtn, 0, 0)
75 | gridLayoutFreedom.addLayout(hboxRedirct, 1, 0)
76 | gridLayoutFreedom.addLayout(hboxTimeout, 2, 0)
77 | gridLayoutFreedom.addLayout(hboxuserLevel, 3, 0)
78 |
79 | groupBoxFreedom.setLayout(gridLayoutFreedom)
80 |
81 | if (v2rayshellDebug):
82 | self.__debugBtn = QPushButton("__debugTest", self)
83 | gridLayoutFreedom.addWidget(self.__debugBtn, 4, 0)
84 | self.__debugBtn.clicked.connect(self.__debugTest)
85 |
86 | self.settingfreedomPanelFromJSONFile(self.freedomJSONFile, True)
87 |
88 | return groupBoxFreedom
89 |
90 | def settingfreedomPanelFromJSONFile(self, freedomJSONFile=None, openFromJSONFile=False):
91 | logbook.setisOpenJSONFile(openFromJSONFile)
92 |
93 | if (not freedomJSONFile): freedomJSONFile = {}
94 |
95 | try:
96 | freedomJSONFile["domainStrategy"]
97 | except KeyError as e:
98 | logbook.writeLog("freedom", "KeyError", e)
99 | freedomJSONFile["domainStrategy"] = "AsIs"
100 |
101 | try:
102 | freedomJSONFile["timeout"]
103 | except KeyError as e:
104 | logbook.writeLog("freedom", "KeyError", e)
105 | freedomJSONFile["timeout"] = 0
106 |
107 | try:
108 | freedomJSONFile["redirect"]
109 | except KeyError as e:
110 | logbook.writeLog("freedom", "KeyError", e)
111 | freedomJSONFile["redirect"] = ""
112 |
113 | try:
114 | freedomJSONFile["userLevel"]
115 | except KeyError as e:
116 | logbook.writeLog("freedom", "KeyError", e)
117 | freedomJSONFile["userLevel"] = 0
118 |
119 | domainStrategy = freedomJSONFile["domainStrategy"]
120 |
121 | if (domainStrategy == "AsIs"):
122 | self.radioBtnFreedomAsIs.setChecked(True)
123 | if (domainStrategy == "UseIP"):
124 | self.radioBtnFreedomUseIP.setChecked(True)
125 |
126 | self.lineEditFreedomRedirect.setText(str(freedomJSONFile["redirect"]))
127 |
128 | try:
129 | self.spinBoxFreedomTime.setValue(int(freedomJSONFile["timeout"]))
130 | except (TypeError, ValueError) as e:
131 | logbook.writeLog("freedom", "ValueError or TypeError", e)
132 | self.spinBoxFreedomTime.setValue(0)
133 |
134 | try:
135 | self.spinBoxFreedomsuserLevel.setValue(int(freedomJSONFile["userLevel"]))
136 | except (TypeError, ValueError) as e:
137 | logbook.writeLog("freedom", "ValueError or TypeError", e)
138 | self.spinBoxFreedomsuserLevel.setValue(0)
139 |
140 | try:
141 | self.treasureChest.addLevel(int(freedomJSONFile["userLevel"]))
142 | except Exception:
143 | pass
144 |
145 | def createFreedomJSONFile(self):
146 | freedomJSONFile = {}
147 | if (self.radioBtnFreedomAsIs.isChecked()):
148 | freedomJSONFile["domainStrategy"] = "AsIs"
149 | if (self.radioBtnFreedomUseIP.isChecked()):
150 | freedomJSONFile["domainStrategy"] = "UseIP"
151 | freedomJSONFile["timeout"] = int(self.spinBoxFreedomTime.value())
152 | freedomJSONFile["redirect"] = self.lineEditFreedomRedirect.text()
153 | freedomJSONFile["userLevel"] = int(self.spinBoxFreedomsuserLevel.value())
154 |
155 | return freedomJSONFile
156 |
157 | def clearfreedomPanel(self):
158 | self.radioBtnFreedomAsIs.setChecked(True)
159 | self.radioBtnFreedomUseIP.setChecked(False)
160 | self.lineEditFreedomRedirect.clear()
161 | self.spinBoxFreedomsuserLevel.setValue(0)
162 | self.spinBoxFreedomTime.setValue(0)
163 |
164 | def __debugTest(self):
165 | import json
166 | print(json.dumps(self.createFreedomJSONFile(), indent=4, sort_keys=False))
167 |
168 |
169 | if __name__ == "__main__":
170 | from PyQt5.QtWidgets import QApplication
171 | app = QApplication(sys.argv)
172 | ex = FreedomPanel()
173 | ex.createFreedomSettingPanel()
174 | ex.setGeometry(300, 350, 380, 160)
175 | ex.show()
176 | sys.exit(app.exec_())
177 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/outbound/shadowsocksPanel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QTableWidget, QLabel, QLineEdit, QSpinBox, QComboBox,
4 | QCheckBox, QWidget, QGroupBox, QGridLayout, QPushButton,
5 | QHBoxLayout, QVBoxLayout, QAbstractItemView,
6 | QTableWidgetItem)
7 | from PyQt5.QtCore import QFileInfo, QCoreApplication
8 | import sys, copy
9 | from PyQt5.Qt import QStandardItem
10 |
11 | v2rayshellDebug = False
12 |
13 | if __name__ == "__main__":
14 | v2rayshellDebug = True
15 | # this for debug test
16 | path = QFileInfo(sys.argv[0])
17 | srcPath = path.absoluteFilePath().split("/")
18 | sys.path.append("/".join(srcPath[:-4]))
19 |
20 | from bridgehouse.editMap.inbound import logbook
21 |
22 |
23 | class OutboundShadowsocksPanel(QWidget):
24 |
25 | def __init__(self):
26 | super().__init__()
27 | self.outboundShadowsocksJSONFile = {
28 | "servers": [
29 | {
30 | "email": "love@v2ray.com",
31 | "address": "127.0.0.1",
32 | "port": 495,
33 | "method": "chacha20-poly1305",
34 | "password": "password",
35 | "ota": True,
36 | "level": 0
37 | }
38 | ]
39 | }
40 | self.translate = QCoreApplication.translate
41 | self.listMethodShadowsocksPanel = "aes-256-cfb", "aes-128-cfb", "chacha20", "chacha20-ietf", "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305"
42 | self.labelHeaderShadowsocksPanel = (self.translate("OutboundShadowsocksPanel", "Adress"),
43 | self.translate("OutboundShadowsocksPanel", "Port"),
44 | self.translate("OutboundShadowsocksPanel", "Method"),
45 | self.translate("OutboundShadowsocksPanel", "Password"),
46 | self.translate("OutboundShadowsocksPanel", "Email"),
47 | self.translate("OutboundShadowsocksPanel", "User Level"),
48 | self.translate("OutboundShadowsocksPanel", "OTA"))
49 |
50 | def createShadowsocksSettingPanel(self):
51 | self.tableWidgetOutShadowsocks = tableWidget = QTableWidget(self)
52 | tableWidget.setRowCount(0)
53 | tableWidget.setColumnCount(7)
54 | tableWidget.setHorizontalHeaderLabels(self.labelHeaderShadowsocksPanel)
55 | tableWidget.setSelectionMode(QAbstractItemView.SingleSelection)
56 | tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)
57 |
58 | self.btnOutShadowsocksNew= QPushButton(
59 | self.translate("OutboundShadowsocksPanel", "New"), self)
60 | self.btnOutShadowsocksDelete = QPushButton(
61 | self.translate("OutboundShadowsocksPanel", "Delete"), self)
62 |
63 | vboxBtn = QVBoxLayout()
64 | vboxBtn.addWidget(QLabel())
65 | vboxBtn.addWidget(QLabel())
66 | vboxBtn.addWidget(QLabel())
67 | vboxBtn.addWidget(QLabel())
68 | vboxBtn.addWidget(self.btnOutShadowsocksNew)
69 | vboxBtn.addWidget(self.btnOutShadowsocksDelete)
70 |
71 | hboxTableWidgetUser = QHBoxLayout()
72 | hboxTableWidgetUser.addWidget(tableWidget)
73 | hboxTableWidgetUser.addLayout(vboxBtn)
74 |
75 | vboxShadowsocksSettingPanel = QVBoxLayout()
76 | vboxShadowsocksSettingPanel.addLayout(hboxTableWidgetUser)
77 |
78 | groupBoxShadowsocksSetting = QGroupBox(
79 | self.translate("OutboundShadowsocksPanel", "Shadowsocks"), self)
80 | groupBoxShadowsocksSetting.setLayout(vboxShadowsocksSettingPanel)
81 |
82 | if (v2rayshellDebug):
83 | self.__btnDebug = QPushButton("__DebugTest", self)
84 | vboxShadowsocksSettingPanel.addWidget(self.__btnDebug)
85 | self.__btnDebug.clicked.connect(self.__DebugTest)
86 | self.settingOutboundShadowsocksPanelFromJSONFile(self.outboundShadowsocksJSONFile, True)
87 |
88 | self.createOutShadowsocksSignales()
89 |
90 | return groupBoxShadowsocksSetting
91 |
92 | def createOutShadowsocksSignales(self):
93 | self.btnOutShadowsocksDelete.clicked.connect(self.onbtnOutShadowsocksDelete)
94 | self.btnOutShadowsocksNew.clicked.connect(self.onbtnOutShadowsocksNew)
95 |
96 | def tableWidgetNewRowItem(
97 | self, row, address=None, port=None, method=None, password=None, email=None, level=None, ota=False):
98 | spinBoxPort = QSpinBox()
99 | spinBoxLevel = QSpinBox()
100 | checkBoxOTA = QCheckBox()
101 | comboBoxMethod = QComboBox()
102 | comboBoxMethod.addItems(self.listMethodShadowsocksPanel)
103 | spinBoxPort.setMinimum(0)
104 | spinBoxPort.setMaximum(65535)
105 |
106 | spinBoxLevel.setMinimum(0)
107 | spinBoxLevel.setMaximum(65535)
108 | spinBoxLevel.setValue(0)
109 | checkBoxOTA.setCheckable(True)
110 | checkBoxOTA.setChecked(ota)
111 | if port:
112 | spinBoxPort.setValue(int(port))
113 | if level:
114 | spinBoxLevel.setValue(int(level))
115 | if method:
116 | comboBoxMethod.setCurrentText(method)
117 | self.tableWidgetOutShadowsocks.setItem(row, 0, QTableWidgetItem("" if not address else address))
118 | self.tableWidgetOutShadowsocks.setCellWidget(row, 1, spinBoxPort)
119 | self.tableWidgetOutShadowsocks.setCellWidget(row, 2, comboBoxMethod)
120 | self.tableWidgetOutShadowsocks.setItem(row, 3, QTableWidgetItem("" if not password else password))
121 | self.tableWidgetOutShadowsocks.setItem(row, 4, QTableWidgetItem("" if not email else email))
122 | self.tableWidgetOutShadowsocks.setCellWidget(row, 5, spinBoxLevel)
123 | self.tableWidgetOutShadowsocks.setCellWidget(row, 6, checkBoxOTA)
124 |
125 | def onbtnOutShadowsocksNew(self):
126 | row = self.tableWidgetOutShadowsocks.rowCount()
127 | if (not row):
128 | self.tableWidgetOutShadowsocks.setRowCount(row+1)
129 | self.tableWidgetNewRowItem(row)
130 | else:
131 | password = self.tableWidgetOutShadowsocks.item(row-1, 3)
132 | address = self.tableWidgetOutShadowsocks.item(row-1, 0)
133 | if (address and address.text() and password and password.text()):
134 | self.tableWidgetOutShadowsocks.setRowCount(row+1)
135 | self.tableWidgetNewRowItem(row)
136 |
137 | def onbtnOutShadowsocksDelete(self):
138 | self.tableWidgetOutShadowsocks.removeRow(self.tableWidgetOutShadowsocks.currentRow())
139 |
140 | def settingOutboundShadowsocksPanelFromJSONFile(self, outboundShadowsocksJSONFile=None, openFromJSONFile=False):
141 | logbook.setisOpenJSONFile(openFromJSONFile)
142 | self.tableWidgetOutShadowsocks.setRowCount(0)
143 |
144 | if (not outboundShadowsocksJSONFile): outboundShadowsocksJSONFile = {}
145 |
146 | try:
147 | outboundShadowsocksJSONFile["servers"]
148 | except KeyError as e:
149 | logbook.writeLog("OutboundShadowsocks", "KeyError", e)
150 | outboundShadowsocksJSONFile["servers"] = []
151 |
152 | serverNumber = len(outboundShadowsocksJSONFile["servers"])
153 | servers = outboundShadowsocksJSONFile["servers"]
154 |
155 | if (serverNumber):
156 | self.tableWidgetOutShadowsocks.setRowCount(serverNumber)
157 | try:
158 | for i in range(serverNumber):
159 | self.tableWidgetOutShadowsocks.setRowCount(i+1)
160 | address = servers[i]["address"]
161 | port = servers[i]["port"]
162 | method = servers[i]["method"]
163 | password = servers[i]["password"]
164 | email = servers[i]["email"]
165 | level = servers[i]["level"]
166 | ota = servers[i]["ota"]
167 | if method == "chacha20-ietf-poly1305":
168 | method = "chacha20-poly1305"
169 | self.tableWidgetNewRowItem(i, address, int(port), method, password, email, int(level), ota)
170 | except KeyError as e:
171 | logbook.writeLog("OutboundShadowsocks", "KeyError", e)
172 |
173 | def createOutboundShadowsocksJSONFile(self):
174 | serversNumber = self.tableWidgetOutShadowsocks.rowCount()
175 | outboundShadowsocksJSONFile = {}
176 | outboundShadowsocksJSONFile["servers"] = [] # clean default setting
177 | for i in range(serversNumber):
178 | servers = {}
179 | address = self.tableWidgetOutShadowsocks.item(i, 0)
180 | password = self.tableWidgetOutShadowsocks.item(i, 3)
181 | if not address.text() and not password.text():
182 | continue
183 | port = self.tableWidgetOutShadowsocks.cellWidget(i, 1)
184 | method = self.tableWidgetOutShadowsocks.cellWidget(i, 2)
185 |
186 | email = self.tableWidgetOutShadowsocks.item(i, 4)
187 | level = self.tableWidgetOutShadowsocks.cellWidget(i, 5)
188 | ota = self.tableWidgetOutShadowsocks.cellWidget(i, 6)
189 | servers["email"] = email.text()
190 | servers["address"] = address.text()
191 | servers["port"] = int(port.value())
192 | servers["method"] = method.currentText()
193 | servers["password"] = password.text()
194 | servers["level"] = int(level.value())
195 | servers["ota"] = ota.isChecked()
196 |
197 | try:self.treasureChest.addLevel(level.value())
198 | except Exception:pass
199 | try:self.treasureChest.addEmail(email.text())
200 | except Exception:pass
201 | outboundShadowsocksJSONFile["servers"].append(copy.deepcopy(servers))
202 |
203 | return outboundShadowsocksJSONFile
204 |
205 | def clearShadowsocksPanel(self):
206 | self.tableWidgetOutShadowsocks.setRowCount(0)
207 |
208 | def __DebugTest(self):
209 | import json
210 | print(json.dumps(self.createOutboundShadowsocksJSONFile(), indent=4, sort_keys=False))
211 |
212 |
213 | if __name__ == "__main__":
214 | from PyQt5.QtWidgets import QApplication
215 | app = QApplication(sys.argv)
216 | ex = OutboundShadowsocksPanel()
217 | ex.createShadowsocksSettingPanel()
218 | ex.setGeometry(300, 300, 680, 500)
219 | ex.show()
220 | sys.exit(app.exec_())
221 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/outbound/socksPanel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QLabel, QLineEdit, QSpinBox,
4 | QWidget, QGroupBox, QPushButton,
5 | QHBoxLayout, QVBoxLayout, QAbstractItemView,
6 | QTreeView)
7 | from PyQt5.QtGui import QStandardItemModel, QStandardItem
8 | from PyQt5.QtCore import QFileInfo, QCoreApplication
9 |
10 | import sys, copy
11 |
12 |
13 | v2rayshellDebug = False
14 |
15 | if __name__ == "__main__":
16 | v2rayshellDebug = True
17 | # this for debug test
18 | path = QFileInfo(sys.argv[0])
19 | srcPath = path.absoluteFilePath().split("/")
20 | sys.path.append("/".join(srcPath[:-4]))
21 |
22 | from bridgehouse.editMap.inbound import logbook
23 |
24 |
25 | class OutboundSocksPanel(QWidget):
26 |
27 | def __init__(self):
28 | super().__init__()
29 | self.outboundSocksJSONFile = {
30 | "servers": [{
31 | "address": "127.0.0.1",
32 | "port": 1080,
33 | "users": [{
34 | "user": "test user",
35 | "pass": "test pass",
36 | "level": 0
37 | }]
38 | }]
39 | }
40 | self.translate = QCoreApplication.translate
41 |
42 | self.labeloutSocks = (self.translate("OutboundSocksPanel", "Address"),
43 | self.translate("OutboundSocksPanel", "Port"),
44 | self.translate("OutboundSocksPanel", "Level"))
45 |
46 | def createOutboundSocksSettingPanel(self):
47 | self.btnOutboundSocksNewUser= QPushButton(
48 | self.translate("OutboundSocksPanel", "New User"))
49 | self.btnOutboundSocksNewServer= QPushButton(
50 | self.translate("OutboundSocksPanel", "New Server"))
51 | self.btnOutboundSocksDelete = QPushButton(
52 | self.translate("OutboundSocksPanel", "Delete"))
53 |
54 | vboxBtnUser = QVBoxLayout()
55 | vboxBtnUser.addWidget(QLabel())
56 | vboxBtnUser.addWidget(QLabel())
57 | vboxBtnUser.addWidget(QLabel())
58 | vboxBtnUser.addWidget(QLabel())
59 | vboxBtnUser.addWidget(self.btnOutboundSocksNewUser)
60 | vboxBtnUser.addWidget(self.btnOutboundSocksNewServer)
61 | vboxBtnUser.addWidget(self.btnOutboundSocksDelete)
62 |
63 | self.treeViewoutSocksAddress = treeViewoutSocksAddress = QTreeView()
64 | treeViewoutSocksAddress.setSelectionMode(QAbstractItemView.SingleSelection)
65 | treeViewoutSocksAddress.setSelectionBehavior(QAbstractItemView.SelectRows)
66 | treeViewoutSocksAddress.setUniformRowHeights(True)
67 |
68 | self.treeViewoutSocksAddressMode = QStandardItemModel()
69 | self.treeViewoutSocksAddressMode.setHorizontalHeaderLabels(self.labeloutSocks)
70 | self.treeViewoutSocksAddress.setModel(self.treeViewoutSocksAddressMode)
71 |
72 | hboxtreeView = QHBoxLayout()
73 | hboxtreeView.addWidget(self.treeViewoutSocksAddress)
74 | hboxtreeView.addLayout(vboxBtnUser)
75 |
76 | vboxOutboundSocks = QVBoxLayout()
77 | vboxOutboundSocks.addLayout(hboxtreeView)
78 |
79 | groupBoxOutboundSocksPanel = QGroupBox(
80 | self.translate("OutboundSocksPanel", "Socks"), self)
81 | groupBoxOutboundSocksPanel.setLayout(vboxOutboundSocks)
82 |
83 | if (v2rayshellDebug):
84 | self.__btnDebug = QPushButton("__DebugTest", self)
85 | vboxOutboundSocks.addWidget(self.__btnDebug)
86 | self.__btnDebug.clicked.connect(self.__DebugTest)
87 | self.settingOutboundSocksPanelFromJSONFile(self.outboundSocksJSONFile, True)
88 |
89 | self.createOutboundSocksPanelSignals()
90 |
91 | return groupBoxOutboundSocksPanel
92 |
93 | def createOutboundSocksPanelSignals(self):
94 | self.btnOutboundSocksDelete.clicked.connect(self.onbtnOutboundSocksDelete)
95 | self.btnOutboundSocksNewUser.clicked.connect(self.onbtnOutboundSocksNewUser)
96 | self.btnOutboundSocksNewServer.clicked.connect(self.onbtnOutboundSocksNewServer)
97 |
98 | def onbtnOutboundSocksNewUser(self):
99 | rowCount = self.treeViewoutSocksAddressMode.rowCount()
100 | if not rowCount:
101 | self.newRowOutSocks(rowCount)
102 | self.treeViewoutSocksAddress.setCurrentIndex(self.treeViewoutSocksAddressMode.index(rowCount, 0))
103 | return
104 |
105 | itemSelection = self.treeViewoutSocksAddress.selectionModel()
106 | rowCurrent = itemSelection.selectedIndexes()[0]
107 | root = rowCurrent.parent().row()
108 | row = rowCurrent.row()
109 | if root == -1:
110 | self.treeViewoutSocksAddressMode.item(row).appendRow((
111 | QStandardItem("user_name"),
112 | QStandardItem("********"),
113 | QStandardItem("0")))
114 | self.treeViewoutSocksAddress.expand(self.treeViewoutSocksAddressMode.index(row, 0))
115 | else:
116 | self.treeViewoutSocksAddressMode.item(root).appendRow((
117 | QStandardItem("user_name"),
118 | QStandardItem("********"),
119 | QStandardItem("0")))
120 |
121 | def onbtnOutboundSocksNewServer(self):
122 | row = self.treeViewoutSocksAddressMode.rowCount()
123 | if not row:
124 | self.newRowOutSocks(row)
125 | self.treeViewoutSocksAddress.setCurrentIndex(self.treeViewoutSocksAddressMode.index(row, 0))
126 | else:
127 | r = self.treeViewoutSocksAddressMode.item(row-1)
128 | if r.hasChildren():
129 | self.newRowOutSocks(row)
130 |
131 | def newRowOutSocks(self, row):
132 | self.treeViewoutSocksAddressMode.setRowCount(row+1)
133 | address = self.treeViewoutSocksAddressMode.index(row, 0)
134 | port = self.treeViewoutSocksAddressMode.index(row, 1)
135 | self.treeViewoutSocksAddressMode.setData(address, "127.0.0.1")
136 | self.treeViewoutSocksAddressMode.setData(port, "1080")
137 |
138 | def onbtnOutboundSocksDelete(self):
139 | if (not self.treeViewoutSocksAddressMode.rowCount()): return
140 |
141 | itemSelection = self.treeViewoutSocksAddress.selectionModel()
142 | rowCurrent = itemSelection.selectedIndexes()[0]
143 | root = rowCurrent.parent().row()
144 | row = rowCurrent.row()
145 | if root == -1:
146 | self.treeViewoutSocksAddressMode.removeRow(row)
147 | else:
148 | self.treeViewoutSocksAddressMode.item(root).removeRow(row)
149 |
150 | def settingOutboundSocksPanelFromJSONFile(self, outboundSocksJSONFile={}, openFromJSONFile=True):
151 | logbook.setisOpenJSONFile(openFromJSONFile)
152 | self.treeViewoutSocksAddressMode.setRowCount(0)
153 |
154 | if (not outboundSocksJSONFile): outboundSocksJSONFile = {}
155 |
156 | try:
157 | outboundSocksJSONFile["servers"]
158 | except KeyError as e:
159 | logbook.writeLog("OutboundSocks", "KeyError", e)
160 | outboundSocksJSONFile["servers"] = []
161 |
162 | servers = outboundSocksJSONFile["servers"]
163 | serversNumber = len(servers)
164 |
165 | # just show the first server detail in TabelWidget
166 | if (serversNumber):
167 |
168 | for i in range(serversNumber):
169 | try:
170 | usersNumber = len(servers[i]["users"])
171 | except KeyError as e:
172 | logbook.writeLog("OutboundSocks", "KeyError", e)
173 | usersNumber = 0
174 | try:
175 | users = servers[i]["users"]
176 | except KeyError as e:
177 | logbook.writeLog("OutboundSocks", "KeyError", e)
178 | try:
179 | serverAddress = QStandardItem(str(servers[i]["address"]))
180 | except KeyError as e:
181 | logbook.writeLog("OutboundSocks", "KeyError", e)
182 |
183 | try:
184 | serverPort = QStandardItem(str(servers[i]["port"]))
185 | except KeyError as e:
186 | logbook.writeLog("OutboundSocks", "KeyError", e)
187 |
188 | for j in range(usersNumber):
189 | try:
190 | user = QStandardItem(str(users[j]["user"]))
191 | password = QStandardItem(str(users[j]["pass"]))
192 | try:
193 | level = QStandardItem(str(users[j]["level"]))
194 | except Exception:
195 | level = QStandardItem("0")
196 |
197 | try:
198 | self.treasureChest.addLevel(users[j]["level"])
199 | except Exception:
200 | pass
201 | serverAddress.appendRow((user, password, level))
202 | except KeyError as e:
203 | logbook.writeLog("OutboundSocks set user", "KeyError", e)
204 | except TypeError as e:
205 | logbook.writeLog("OutboundSocks set user", "TypeError", e)
206 | except ValueError as e:
207 | logbook.writeLog("OutboundSocks set user", "ValueError", e)
208 | except:
209 | logbook.writeLog("OutboundSocks set user", "unkonw")
210 | self.treeViewoutSocksAddressMode.appendRow((serverAddress, serverPort))
211 | # make a sure add items success
212 | if (self.treeViewoutSocksAddressMode.rowCount()):
213 | # if there no any selectItem, "Add, Modify, Delete" button's slot will crash
214 | self.treeViewoutSocksAddress.setCurrentIndex(self.treeViewoutSocksAddressMode.index(0, 0))
215 |
216 | def createOutboundSocksJSONFile(self):
217 | outboundSocksJSONFile = {}
218 | outboundSocksJSONFile["servers"] = []
219 | serversNumber = self.treeViewoutSocksAddressMode.rowCount()
220 | if (not serversNumber): return
221 | print(serversNumber)
222 | for i in range(serversNumber):
223 | server = {}
224 | user = {}
225 | server["address"] = self.treeViewoutSocksAddressMode.item(i, 0).text()
226 | server["port"] = int(self.treeViewoutSocksAddressMode.item(i, 1).text())
227 | server["users"] = []
228 | if (self.treeViewoutSocksAddressMode.hasChildren()):
229 | usersNumber = self.treeViewoutSocksAddressMode.item(i).rowCount()
230 | for j in range(usersNumber):
231 | user["user"] = self.treeViewoutSocksAddressMode.item(i).child(j, 0).text()
232 | user["pass"] = self.treeViewoutSocksAddressMode.item(i).child(j, 1).text()
233 | user["level"] = int(self.treeViewoutSocksAddressMode.item(i).child(j, 2).text())
234 | try:
235 | self.treasureChest.addLevel(user["level"])
236 | except Exception:
237 | pass
238 | server["users"].append(copy.deepcopy(user))
239 | else:
240 | server["users"] = []
241 | outboundSocksJSONFile["servers"].append(copy.deepcopy(server))
242 |
243 | return outboundSocksJSONFile
244 |
245 | def clearSocksPanel(self):
246 | self.treeViewoutSocksAddressMode.setRowCount(0)
247 |
248 | def __DebugTest(self):
249 | import json
250 | print(json.dumps(self.createOutboundSocksJSONFile(), indent=4, sort_keys=False))
251 |
252 |
253 | if __name__ == "__main__":
254 | from PyQt5.QtWidgets import QApplication
255 | app = QApplication(sys.argv)
256 | ex = OutboundSocksPanel()
257 | ex.createOutboundSocksSettingPanel()
258 | ex.setGeometry(300, 300, 800, 350)
259 | ex.show()
260 | sys.exit(app.exec_())
261 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/outbound/vmessPanel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QLabel, QLineEdit, QSpinBox, QComboBox,
4 | QWidget, QGroupBox, QPushButton,
5 | QHBoxLayout, QVBoxLayout, QAbstractItemView, QTreeView)
6 | from PyQt5.QtGui import QStandardItemModel, QStandardItem
7 | from PyQt5.QtCore import QFileInfo, QCoreApplication
8 |
9 | import sys, uuid, copy
10 |
11 | v2rayshellDebug = False
12 |
13 | if __name__ == "__main__":
14 | v2rayshellDebug = True
15 | # this for debug test
16 | path = QFileInfo(sys.argv[0])
17 | srcPath = path.absoluteFilePath().split("/")
18 | sys.path.append("/".join(srcPath[:-4]))
19 |
20 | from bridgehouse.editMap.inbound import logbook
21 | from bridgehouse.editMap.toolbox import toolbox
22 |
23 | class OutboundVmessSettingPanel(QWidget):
24 |
25 | def __init__(self):
26 | super().__init__()
27 | self.outboundVmessJSONFile = {
28 | "vnext": [
29 | {
30 | "address": "127.0.0.1",
31 | "port": 443,
32 | "users": [
33 | {
34 | "id": "27848739-7e62-4138-9fd3-098a63964b6b",
35 | "alterId": 10,
36 | "security": "aes-128-cfb",
37 | "level": 0
38 | }
39 | ]
40 | }
41 | ]
42 | }
43 | self.translate = QCoreApplication.translate
44 | self.labeloutVmess = (self.translate("OutboundVmessSettingPanel", "Address/AlterID"),
45 | self.translate("OutboundVmessSettingPanel", "Port/Method"),
46 | self.translate("OutboundVmessSettingPanel", "UUID"),
47 | self.translate("OutboundVmessSettingPanel", "Level"))
48 |
49 | self.listMethodoutVmess = "auto", "aes-128-cfb", "aes-128-gcm", "chacha20-poly1305", "none"
50 |
51 | def createOutboundVmessPanel(self):
52 | self.treeViewOutboundVmessAddress = treeViewOutboundVmessAddress = QTreeView()
53 | treeViewOutboundVmessAddress.setSelectionMode(QAbstractItemView.SingleSelection)
54 | treeViewOutboundVmessAddress.setSelectionBehavior(QAbstractItemView.SelectRows)
55 | treeViewOutboundVmessAddress.setUniformRowHeights(True)
56 |
57 | self.treeViewOutboundVmessAddressMode = QStandardItemModel()
58 | self.treeViewOutboundVmessAddressMode.setHorizontalHeaderLabels(self.labeloutVmess)
59 | treeViewOutboundVmessAddress.setModel(self.treeViewOutboundVmessAddressMode)
60 |
61 | treeViewOutboundVmessAddress.setItemDelegateForColumn(1, toolbox.ComboBoxSpinBoxDelegate(self.listMethodoutVmess))
62 |
63 | self.btnoutVmessNewUser = QPushButton(
64 | self.translate("OutboundVmessSettingPanel", "New User"))
65 | self.btnoutVmessNewServer= QPushButton(
66 | self.translate("OutboundVmessSettingPanel", "New Sever"))
67 | self.btnoutVmessDelete = QPushButton(
68 | self.translate("OutboundVmessSettingPanel", "Delete"))
69 |
70 | vboxBtn = QVBoxLayout()
71 | vboxBtn.addWidget(QLabel())
72 | vboxBtn.addWidget(QLabel())
73 | vboxBtn.addWidget(QLabel())
74 | vboxBtn.addWidget(QLabel())
75 | vboxBtn.addWidget(self.btnoutVmessNewUser)
76 | vboxBtn.addWidget(self.btnoutVmessNewServer)
77 | vboxBtn.addWidget(self.btnoutVmessDelete)
78 |
79 | hboxTreeView = QHBoxLayout()
80 | hboxTreeView.addWidget(treeViewOutboundVmessAddress)
81 | hboxTreeView.addLayout(vboxBtn)
82 |
83 | vboxOutBoundVmessUser = QVBoxLayout()
84 | vboxOutBoundVmessUser.addLayout(hboxTreeView)
85 |
86 | groupBoxOutboundVmessUser = QGroupBox("", self)
87 | groupBoxOutboundVmessUser.setLayout(vboxOutBoundVmessUser)
88 |
89 | self.createOutboundVmessPanelSignals()
90 |
91 | if(v2rayshellDebug):
92 | self.__btnDebug = QPushButton("__DebugTest", self)
93 | self.__btnDebug.clicked.connect(self.__DebugTest)
94 | vboxOutBoundVmessUser.addWidget(self.__btnDebug)
95 | self.setLayout(vboxOutBoundVmessUser)
96 | self.settingOutboundVmessPanelFromJSONFile(self.outboundVmessJSONFile, True)
97 | return
98 |
99 | return groupBoxOutboundVmessUser
100 |
101 | def createOutboundVmessPanelSignals(self):
102 | self.btnoutVmessDelete.clicked.connect(self.onbtnoutVmessDelete)
103 | self.btnoutVmessNewServer.clicked.connect(self.onbtnoutVmessNewServer)
104 | self.btnoutVmessNewUser.clicked.connect(self.onbtnoutVmessNewUser)
105 |
106 | def onbtnoutVmessDelete(self):
107 | if (not self.treeViewOutboundVmessAddressMode.rowCount()): return
108 |
109 | itemSelection = self.treeViewOutboundVmessAddress.selectionModel()
110 | rowCurrent = itemSelection.selectedIndexes()[0]
111 | root = rowCurrent.parent().row()
112 | row = rowCurrent.row()
113 |
114 | if (root == -1):
115 | self.treeViewOutboundVmessAddressMode.removeRow(row)
116 | else:
117 | self.treeViewOutboundVmessAddressMode.item(root).removeRow(row)
118 |
119 | def onbtnoutVmessNewUser(self):
120 | rowCount = self.treeViewOutboundVmessAddressMode.rowCount()
121 | if not rowCount:
122 | self.newRowOutVmess(rowCount)
123 | self.treeViewOutboundVmessAddress.setCurrentIndex(
124 | self.treeViewOutboundVmessAddressMode.index(rowCount, 0))
125 | return
126 |
127 | itemSelection = self.treeViewOutboundVmessAddress.selectionModel()
128 | rowCurrent = itemSelection.selectedIndexes()[0]
129 | root = rowCurrent.parent().row()
130 | row = rowCurrent.row()
131 | if root == -1:
132 | self.treeViewOutboundVmessAddressMode.item(row).appendRow((
133 | QStandardItem("10"),
134 | QStandardItem("aes-128-cfb"),
135 | QStandardItem(self.createUUID()),
136 | QStandardItem("0")))
137 | self.treeViewOutboundVmessAddress.expand(self.treeViewOutboundVmessAddressMode.index(row, 0))
138 | else:
139 | self.treeViewOutboundVmessAddressMode.item(root).appendRow((
140 | QStandardItem("10"),
141 | QStandardItem("aes-128-cfb"),
142 | QStandardItem(self.createUUID()),
143 | QStandardItem("0")))
144 |
145 | def onbtnoutVmessNewServer(self):
146 | row = self.treeViewOutboundVmessAddressMode.rowCount()
147 | if not row:
148 | self.newRowOutVmess(row)
149 | self.treeViewOutboundVmessAddress.setCurrentIndex(
150 | self.treeViewOutboundVmessAddressMode.index(row, 0))
151 | else:
152 | r = self.treeViewOutboundVmessAddressMode.item(row-1)
153 | if r.hasChildren():
154 | self.newRowOutVmess(row)
155 |
156 | def newRowOutVmess(self, row):
157 | self.treeViewOutboundVmessAddressMode.setRowCount(row+1)
158 | address = self.treeViewOutboundVmessAddressMode.index(row, 0)
159 | port = self.treeViewOutboundVmessAddressMode.index(row, 1)
160 | self.treeViewOutboundVmessAddressMode.setData(address, "127.0.0.1")
161 | self.treeViewOutboundVmessAddressMode.setData(port, "443")
162 |
163 | def settingOutboundVmessPanelFromJSONFile(self, outboundVmessJSONFile=None, openFromJSONFile=False):
164 | logbook.setisOpenJSONFile(openFromJSONFile)
165 | self.treeViewOutboundVmessAddressMode.setRowCount(0)
166 |
167 | if (not outboundVmessJSONFile):
168 | outboundVmessJSONFile = {}
169 |
170 | try:
171 | outboundVmessJSONFile["vnext"]
172 | except KeyError as e:
173 | logbook.writeLog("OutboundVmess", "KeyError", e)
174 | outboundVmessJSONFile["vnext"] = []
175 |
176 | addressNumber = len(outboundVmessJSONFile["vnext"])
177 |
178 | if (addressNumber):
179 | addresses = outboundVmessJSONFile["vnext"]
180 |
181 | for i in range(addressNumber):
182 | try:
183 | users = addresses[i]["users"]
184 | usersNumber = len(users)
185 | serverAddress = QStandardItem(addresses[i]["address"])
186 | serverPort = QStandardItem(str(addresses[i]["port"]))
187 | if (usersNumber):
188 | for j in range(usersNumber):
189 | try:
190 | uuidString = QStandardItem(str(users[j]["id"]))
191 | except Exception: uuidString = QStandardItem("")
192 | try:
193 | alterId = QStandardItem(str(users[j]["alterId"]))
194 | except Exception: alterId = QStandardItem("")
195 | try:
196 | security = QStandardItem(str(users[j]["security"]))
197 | except Exception: security = QStandardItem("")
198 | try:
199 | level = QStandardItem(str(users[j]["level"]))
200 | except Exception: level = QStandardItem("0")
201 | try:
202 | self.treasureChest.addLevel(users[j]["level"])
203 | except Exception:pass
204 | serverAddress.appendRow((alterId, security, uuidString, level))
205 | self.treeViewOutboundVmessAddressMode.appendRow((serverAddress, serverPort))
206 | except KeyError as e:
207 | logbook.writeLog("OutboundVmess", "KeyError", e)
208 | except:
209 | logbook.writeLog("OutboundVmess", "unkonw")
210 |
211 | if (self.treeViewOutboundVmessAddressMode.rowCount() > 0):
212 | self.treeViewOutboundVmessAddress.setCurrentIndex(self.treeViewOutboundVmessAddressMode.index(0, 0))
213 |
214 | def createOutboundVmessJSONFile(self):
215 | outboundVmessJSONFile = {}
216 | outboundVmessJSONFile["vnext"] = []
217 | serversNumber = self.treeViewOutboundVmessAddressMode.rowCount()
218 | if (not serversNumber): return
219 |
220 | for i in range(serversNumber):
221 | server = {}
222 | user = {}
223 | server["address"] = self.treeViewOutboundVmessAddressMode.item(i, 0).text()
224 | server["port"] = int(self.treeViewOutboundVmessAddressMode.item(i, 1).text())
225 | server["users"] = []
226 | if (self.treeViewOutboundVmessAddressMode.hasChildren()):
227 | usersNumber = self.treeViewOutboundVmessAddressMode.item(i).rowCount()
228 | for j in range(usersNumber):
229 | user["id"] = self.treeViewOutboundVmessAddressMode.item(i).child(j, 2).text()
230 | user["alterId"] = int(self.treeViewOutboundVmessAddressMode.item(i).child(j, 0).text())
231 | user["security"] = self.treeViewOutboundVmessAddressMode.item(i).child(j, 1).text()
232 | user["level"] = int(self.treeViewOutboundVmessAddressMode.item(i).child(j, 3).text())
233 | try:
234 | self.treasureChest.addLevel(user["level"])
235 | except Exception:
236 | pass
237 | server["users"].append(copy.deepcopy(user))
238 | else:
239 | server["users"] = []
240 | outboundVmessJSONFile["vnext"].append(copy.deepcopy(server))
241 |
242 | return outboundVmessJSONFile
243 |
244 | def createUUID(self):
245 | return str(uuid.uuid4())
246 |
247 | def validateUUID4(self, uuidString):
248 | try:
249 | uuid.UUID(uuidString, version=4)
250 | except ValueError:
251 | return False
252 | return True
253 |
254 | def clearOutVmessPanel(self):
255 | self.treeViewOutboundVmessAddressMode.setRowCount(0)
256 |
257 | def __DebugTest(self):
258 | import json
259 | print(json.dumps(self.createOutboundVmessJSONFile(), indent=4, sort_keys=False))
260 |
261 |
262 | if __name__ == "__main__":
263 | from PyQt5.QtWidgets import QApplication
264 | app = QApplication(sys.argv)
265 | ex = OutboundVmessSettingPanel()
266 | ex.createOutboundVmessPanel()
267 | ex.setGeometry(300, 300, 580, 580)
268 | ex.show()
269 | sys.exit(app.exec_())
270 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/policyTAB.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QWidget, QGroupBox,
4 | QVBoxLayout, QApplication, QLabel, QComboBox,
5 | QHBoxLayout, QSpinBox, QGridLayout, QPushButton,
6 | QCheckBox)
7 | from PyQt5.QtCore import QFileInfo, Qt, QCoreApplication
8 | import sys, copy
9 |
10 | v2rayshellDebug = False
11 |
12 | if __name__ == "__main__":
13 | v2rayshellDebug = True
14 | # this for debug test
15 | path = QFileInfo(sys.argv[0])
16 | srcPath = path.absoluteFilePath().split("/")
17 | sys.path.append("/".join(srcPath[:-3]))
18 |
19 | from bridgehouse.editMap.port import treasureChest
20 |
21 |
22 | class policyTab(QWidget):
23 |
24 | def __init__(self, CaptainstreasureChest=False):
25 | super().__init__()
26 | self.policyJSONFile = {
27 | "levels": {
28 | "0": {
29 | "handshake": 4,
30 | "connIdle": 300,
31 | "uplinkOnly": 5,
32 | "downlinkOnly": 30,
33 | "statsUserUplink": False,
34 | "statsUserDownlink": False
35 | }
36 | }
37 | }
38 |
39 | self.template = {
40 | "handshake": 4,
41 | "connIdle": 300,
42 | "uplinkOnly": 5,
43 | "downlinkOnly": 30,
44 | "statsUserUplink": False,
45 | "statsUserDownlink": False
46 | }
47 | self.translate = QCoreApplication.translate
48 | if (CaptainstreasureChest):
49 | self.treasureChest = CaptainstreasureChest
50 | else:
51 | self.treasureChest = treasureChest.treasureChest() # a empty treasure chest
52 | self.__groupPolicyTitle = self.translate("policyTab", "Policy Setting")
53 | self.levels = {}
54 |
55 | def createPolicyTab(self):
56 | labelLevels = QLabel(self.translate("policyTab", "Levels: "))
57 | self.comboBoxLevels = QComboBox()
58 |
59 | hboxLevels = QHBoxLayout()
60 | hboxLevels.addWidget(labelLevels)
61 | hboxLevels.addWidget(self.comboBoxLevels)
62 | hboxLevels.addStretch()
63 |
64 | labelhandshake = QLabel(
65 | self.translate("policyTab", "Handshake: "))
66 | labelconnIdle = QLabel(
67 | self.translate("policyTab", "ConnIdle: "))
68 | labeluplinkOnly = QLabel(
69 | self.translate("policyTab", "UplinkOnly: "))
70 | labeldownlinkOnly = QLabel(
71 | self.translate("policyTab", "DownlinkOnly: "))
72 | self.spinboxhandshake = QSpinBox()
73 | self.spinboxuplinkOnly = QSpinBox()
74 | self.spinboxconnIdle = QSpinBox()
75 | self.spinboxdownlinkOnly = QSpinBox()
76 | self.spinboxhandshake.setRange(0, 20)
77 | self.spinboxhandshake.setValue(4)
78 | self.spinboxconnIdle.setRange(0, 1500)
79 | self.spinboxconnIdle.setValue(300)
80 | self.spinboxuplinkOnly.setRange(0, 25)
81 | self.spinboxuplinkOnly.setValue(5)
82 | self.spinboxdownlinkOnly.setRange(0, 150)
83 | self.spinboxdownlinkOnly.setValue(30)
84 |
85 | self.checkboxStatsUserUplink = QCheckBox(
86 | self.translate("policyTab", "Stats User Uplink"))
87 | self.checkboxStatsUserDownlink = QCheckBox(
88 | self.translate("policyTab", "Stats User Downlink"))
89 |
90 | hboxhandshake = QHBoxLayout()
91 | hboxhandshake.addWidget(self.spinboxhandshake)
92 | hboxhandshake.addStretch()
93 |
94 | self.buttonPolicyApply = QPushButton(
95 | self.translate("policyTab", "Apply"), self)
96 | self.buttonPolicyDefault = QPushButton(
97 | self.translate("policyTab", "Default"), self)
98 | hboxButton = QHBoxLayout()
99 | hboxButton.addStretch()
100 | hboxButton.addWidget(self.buttonPolicyApply)
101 | hboxButton.addWidget(self.buttonPolicyDefault)
102 |
103 | gridBoxLevel = QGridLayout()
104 | gridBoxLevel.addWidget(labelhandshake, 0, 0, 1, 1, Qt.AlignLeft)
105 | gridBoxLevel.addLayout(hboxhandshake, 0, 1, 1, 1, Qt.AlignLeft)
106 | gridBoxLevel.addWidget(labelconnIdle, 1, 0, 1, 1, Qt.AlignLeft)
107 | gridBoxLevel.addWidget(self.spinboxconnIdle, 1, 1, 1, 1, Qt.AlignLeft)
108 | gridBoxLevel.addWidget(labeluplinkOnly, 2, 0, 1, 1, Qt.AlignLeft)
109 | gridBoxLevel.addWidget(self.spinboxuplinkOnly, 2, 1, 1, 1, Qt.AlignLeft)
110 | gridBoxLevel.addWidget(labeldownlinkOnly, 3, 0, 1, 1, Qt.AlignLeft)
111 | gridBoxLevel.addWidget(self.spinboxdownlinkOnly, 3, 1, 1, 1, Qt.AlignLeft)
112 | gridBoxLevel.addWidget(self.checkboxStatsUserUplink, 4, 0, 1, 1, Qt.AlignLeft)
113 | gridBoxLevel.addWidget(self.checkboxStatsUserDownlink, 5, 0, 1, 1, Qt.AlignLeft)
114 | gridBoxLevel.addLayout(hboxButton, 6, 2, 1, 2, Qt.AlignLeft)
115 |
116 | vboxLevels = QVBoxLayout()
117 | vboxLevels.addLayout(hboxLevels)
118 | vboxLevels.addLayout(gridBoxLevel)
119 | vboxLevels.addStretch()
120 |
121 | self.groupBoxPolicy = QGroupBox(self.__groupPolicyTitle, self)
122 | self.groupBoxPolicy.setLayout(vboxLevels)
123 |
124 | self.createPolcyTabSignals()
125 |
126 | if v2rayshellDebug:
127 | levels = ("0", "1", "2", "3", "4", "5", "6")
128 | self.comboBoxLevels.addItems(levels)
129 | self.__debugBtn = QPushButton("__debugTest", self)
130 | self.__debugBtn.clicked.connect(self.__debugTest)
131 | vboxLevels.addWidget(self.__debugBtn)
132 | return self.groupBoxPolicy
133 |
134 | return self.groupBoxPolicy
135 |
136 | def createPolcyTabSignals(self):
137 | self.treasureChest.updateList.updateLevelandEmail.connect(self.onupdatecomboBoxLevels)
138 | self.comboBoxLevels.activated[str].connect(self.settingLevelsSpinbox)
139 | self.buttonPolicyApply.clicked.connect(self.onbuttonPolicyApply)
140 | self.buttonPolicyDefault.clicked.connect(self.settingLevelsSpinboxDefault)
141 | self.spinboxconnIdle.valueChanged.connect(self.changegroupBoxPolicyTitle)
142 | self.spinboxdownlinkOnly.valueChanged.connect(self.changegroupBoxPolicyTitle)
143 | self.spinboxhandshake.valueChanged.connect(self.changegroupBoxPolicyTitle)
144 | self.spinboxuplinkOnly.valueChanged.connect(self.changegroupBoxPolicyTitle)
145 |
146 | def settingLevelsSpinbox(self, level):
147 | if level in self.levels.keys():
148 | self.spinboxhandshake.setValue(self.levels[level]["handshake"])
149 | self.spinboxconnIdle.setValue(self.levels[level]["connIdle"])
150 | self.spinboxdownlinkOnly.setValue(self.levels[level]["downlinkOnly"])
151 | self.spinboxuplinkOnly.setValue(self.levels[level]["uplinkOnly"])
152 | self.checkboxStatsUserUplink.setChecked(True if self.levels[level]["statsUserUplink"] else False)
153 | self.checkboxStatsUserDownlink.setChecked(True if self.levels[level]["statsUserDownlink"] else False)
154 | self.groupBoxPolicy.setTitle("{}".format(self.__groupPolicyTitle))
155 | else:
156 | self.settingLevelsSpinboxDefault()
157 |
158 | def onbuttonPolicyApply(self):
159 | currentLevel = self.comboBoxLevels.currentText()
160 | if currentLevel not in self.levels: self.levels[currentLevel] = {}
161 | self.levels[currentLevel]["handshake"] = self.spinboxhandshake.value()
162 | self.levels[currentLevel]["connIdle"] = self.spinboxconnIdle.value()
163 | self.levels[currentLevel]["downlinkOnly"] = self.spinboxdownlinkOnly.value()
164 | self.levels[currentLevel]["uplinkOnly"] = self.spinboxuplinkOnly.value()
165 | self.levels[currentLevel]["statsUserUplink"] = True if self.checkboxStatsUserUplink.isChecked() else False
166 | self.levels[currentLevel]["statsUserDownlink"] = True if self.checkboxStatsUserDownlink.isChecked() else False
167 | self.groupBoxPolicy.setTitle("{}".format(self.__groupPolicyTitle))
168 |
169 | def settingLevelsSpinboxDefault(self):
170 | self.spinboxhandshake.setValue(self.template["handshake"])
171 | self.spinboxconnIdle.setValue(self.template["connIdle"])
172 | self.spinboxdownlinkOnly.setValue(self.template["downlinkOnly"])
173 | self.spinboxuplinkOnly.setValue(self.template["uplinkOnly"])
174 | self.checkboxStatsUserUplink.setChecked(False)
175 | self.checkboxStatsUserDownlink.setChecked(False)
176 | self.onbuttonPolicyApply()
177 |
178 | def changegroupBoxPolicyTitle(self):
179 | self.groupBoxPolicy.setTitle("{}{}".format(self.__groupPolicyTitle, "*"))
180 |
181 | def onupdatecomboBoxLevels(self):
182 | self.comboBoxLevels.clear()
183 | allLevels = copy.deepcopy(self.treasureChest.getLevels())
184 |
185 | if allLevels:
186 | # add new Levels
187 | for i in allLevels:
188 | if i not in self.levels.keys():
189 | self.levels[i] = copy.deepcopy(self.template)
190 |
191 | # delete obsolete Levels
192 | for i in self.levels.keys():
193 | if i not in allLevels:
194 | del self.levels[i]
195 | continue
196 | self.comboBoxLevels.addItem(i)
197 |
198 | def settingPolicyTabFromJSONFile(self, policyJSONFile):
199 | self.levels.clear()
200 | self.comboBoxLevels.clear()
201 |
202 | if (not policyJSONFile): policyJSONFile = {}
203 |
204 | for i, v in policyJSONFile.items():
205 | try:
206 | int(i)
207 | except Exception:
208 | continue
209 |
210 | try:
211 | v["handshake"]
212 | except Exception:
213 | v["handshake"] = 4
214 |
215 | try:
216 | v["connIdle"]
217 | except Exception:
218 | v["connIdle"] = 300
219 |
220 | try:
221 | v["uplinkOnly"]
222 | except Exception:
223 | v["uplinkOnly"] = 5
224 |
225 | try:
226 | v["downlinkOnly"]
227 | except Exception:
228 | v["downlinkOnly"] = 30
229 |
230 | try:
231 | v["statsUserUplink"]
232 | except Exception:
233 | v["statsUserUplink"] = False
234 |
235 | try:
236 | v["statsUserDownlink"]
237 | except Exception:
238 | v["statsUserDownlink"] = False
239 |
240 | try:
241 | self.levels[str(i)] = copy.deepcopy(v)
242 | except Exception:
243 | pass
244 | self.comboBoxLevels.addItem(str(i))
245 |
246 | if self.levels:
247 | for i in self.levels.items():
248 | try:
249 | self.settingLevelsSpinbox(i[0])
250 | except Exception:
251 | pass
252 | break
253 |
254 | def createPolicyJSONFile(self):
255 | return self.levels
256 |
257 | def __debugTest(self):
258 | import json
259 | print(json.dumps(self.createPolicyJSONFile(), indent=4, sort_keys=False))
260 |
261 |
262 | if __name__ == "__main__":
263 | app = QApplication(sys.argv)
264 | ex = policyTab()
265 | vbox = QVBoxLayout()
266 | vbox.addWidget(ex.createPolicyTab())
267 | ex.setLayout(vbox)
268 | ex.setGeometry(200, 100, 250, 200)
269 | ex.show()
270 | sys.exit(app.exec_())
271 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/port/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from bridgehouse.editMap import logTAB
4 |
5 | logbook = logTAB.logBook()
6 |
7 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/port/updateListSignal.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtCore import pyqtSignal, QObject
4 |
5 |
6 | class updateListSignal(QObject):
7 | """
8 | when the outbound tag had added or changed.
9 | will emit a signal to outbound->(Proxy Setting) and inbound->vmess->(Detour To outboundDetuour) update the outbound tags
10 |
11 | when have new level or email will emit to they panel. fresh the list.
12 | """
13 | setInboundTag = pyqtSignal()
14 | updateLevelandEmail = pyqtSignal()
15 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/router/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/router/codegen.py:
--------------------------------------------------------------------------------
1 | import os
2 | import grpc_tools.protoc as proto # python -m pip install grpcio-tools
3 |
4 | protoFiles = [x for x in os.listdir() if x.endswith(".proto") and os.path.isfile(x)]
5 |
6 | for p in protoFiles:
7 | proto.main("--proto_path=./ --python_out=./ --grpc_python_out=./ {}".format(p).split())
8 |
9 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/router/geoSite.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | enum Network {
4 | Unknown = 0;
5 |
6 | RawTCP = 1 [deprecated=true];
7 | TCP = 2;
8 | UDP = 3;
9 | }
10 |
11 | // NetworkList is a list of Networks.
12 | message NetworkList {
13 | repeated Network network = 1;
14 | }
15 |
16 | // PortRange represents a range of ports.
17 | message PortRange {
18 | // The port that this range starts from.
19 | uint32 From = 1;
20 | // The port that this range ends with (inclusive).
21 | uint32 To = 2;
22 | }
23 |
24 |
25 | // Domain for routing decision.
26 | message Domain {
27 | // Type of domain value.
28 | enum Type {
29 | // The value is used as is.
30 | Plain = 0;
31 | // The value is used as a regular expression.
32 | Regex = 1;
33 | // The value is a domain.
34 | Domain = 2;
35 | }
36 |
37 | // Domain matching type.
38 | Type type = 1;
39 |
40 | // Domain value.
41 | string value = 2;
42 | }
43 |
44 | // IP for routing decision, in CIDR form.
45 | message CIDR {
46 | // IP address, should be either 4 or 16 bytes.
47 | bytes ip = 1;
48 |
49 | // Number of leading ones in the network mask.
50 | uint32 prefix = 2;
51 | }
52 |
53 | message GeoIP {
54 | string country_code = 1;
55 | repeated CIDR cidr = 2;
56 | }
57 |
58 | message GeoIPList {
59 | repeated GeoIP entry = 1;
60 | }
61 |
62 | message GeoSite {
63 | string country_code = 1;
64 | repeated Domain domain = 2;
65 | }
66 |
67 | message GeoSiteList{
68 | repeated GeoSite entry = 1;
69 | }
70 |
71 | message RoutingRule {
72 | string tag = 1;
73 | repeated Domain domain = 2;
74 | repeated CIDR cidr = 3;
75 | PortRange port_range = 4;
76 | NetworkList network_list = 5;
77 | repeated CIDR source_cidr = 6;
78 | repeated string user_email = 7;
79 | repeated string inbound_tag = 8;
80 | }
81 |
82 | message Config {
83 | enum DomainStrategy {
84 | // Use domain as is.
85 | AsIs = 0;
86 |
87 | // Always resolve IP for domains.
88 | UseIp = 1;
89 |
90 | // Resolve to IP if the domain doesn't match any rules.
91 | IpIfNonMatch = 2;
92 |
93 | // Resolve to IP if any rule requires IP matching.
94 | IpOnDemand = 3;
95 | }
96 | DomainStrategy domain_strategy = 1;
97 | repeated RoutingRule rule = 2;
98 | }
99 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/router/geoSite_pb2_grpc.py:
--------------------------------------------------------------------------------
1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2 | import grpc
3 |
4 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/router/readgfwlist.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from base64 import b64decode
4 |
5 | def openGWFLIST(path):
6 | gwfList = []
7 | with open(path, "r") as f:
8 | gwflistBase64 = f.read()
9 |
10 | if gwflistBase64:
11 | for i in b64decode(gwflistBase64).decode("utf-8").split("\n"):
12 | # https://adblockplus.org/zh_CN/filters
13 | if i.startswith("!#"):
14 | continue
15 | if i.startswith("!"): # remove Comments
16 | continue
17 | if not i: # remove empty
18 | continue
19 | if i.startswith("[AutoProxy"):
20 | continue
21 | if i.startswith("@@"): # remove Exception rules
22 | continue
23 | if i.startswith("!##############General List End#################"):
24 | break
25 | else:
26 | gwfList.append(i)
27 | del gwflistBase64
28 | return gwfList
29 |
30 |
31 | if __name__ == "__main__":
32 | openGWFLIST("gfwlist.txt")
33 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/routingTAB.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QWidget, QTextEdit,
4 | QVBoxLayout, QApplication)
5 | from PyQt5.QtCore import QFileInfo, QCoreApplication
6 | import sys, json, copy
7 |
8 | v2rayshellDebug = False
9 |
10 | if __name__ == "__main__":
11 | v2rayshellDebug = True
12 | # this for debug test
13 | path = QFileInfo(sys.argv[0])
14 | srcPath = path.absoluteFilePath().split("/")
15 | sys.path.append("/".join(srcPath[:-3]))
16 |
17 | from bridgehouse.editMap.router import geoSiteEditorPanel
18 |
19 |
20 | class routingTab(QWidget):
21 |
22 | def __init__(self):
23 | super().__init__()
24 | self.routingJSONFile = {
25 | "strategy": "rules",
26 | "settings": {
27 | "domainStrategy": "IPIfNonMatch",
28 | "rules": [
29 | {
30 | "type": "field",
31 | "port": "1-52",
32 | "outboundTag": "direct"
33 | },
34 | {
35 | "type": "field",
36 | "port": "54-79",
37 | "outboundTag": "direct"
38 | },
39 | {
40 | "type": "field",
41 | "port": "81-442",
42 | "outboundTag": "direct"
43 | },
44 | {
45 | "type": "field",
46 | "port": "444-65535",
47 | "outboundTag": "direct"
48 | },
49 | {
50 | "type": "chinasites",
51 | "outboundTag": "direct"
52 | },
53 | {
54 | "type": "field",
55 | "ip": [
56 | "0.0.0.0/8",
57 | "10.0.0.0/8",
58 | "100.64.0.0/10",
59 | "127.0.0.0/8",
60 | "169.254.0.0/16",
61 | "172.16.0.0/12",
62 | "192.0.0.0/24",
63 | "192.0.2.0/24",
64 | "192.168.0.0/16",
65 | "198.18.0.0/15",
66 | "198.51.100.0/24",
67 | "203.0.113.0/24",
68 | "::1/128",
69 | "fc00::/7",
70 | "fe80::/10"
71 | ],
72 | "outboundTag": "direct"
73 | },
74 | {
75 | "type": "chinaip",
76 | "outboundTag": "direct"
77 | }
78 | ]
79 | }
80 | }
81 | self.translate = QCoreApplication.translate
82 |
83 | def createRoutingTab(self):
84 | self.textEditRoutingJSONFile = QTextEdit()
85 | self.textEditRoutingJSONFile.setReadOnly(True)
86 | self.textEditRoutingJSONFile.setVisible(False)
87 |
88 | self.textEditRoutingJSONFile.setPlainText(
89 | json.dumps(self.routingJSONFile, indent=4, sort_keys=False))
90 |
91 | self.geoSiteEditorPanel = geoSiteEditorPanel.GeoSiteEditorPanel()
92 | self.panel = self.geoSiteEditorPanel.createGeoSiteEditorPanel()
93 |
94 | return self.panel
95 |
96 | def settingRoutingTABFromJSONFile(self, routingJSONFile=None, openFromJSONFile=False):
97 |
98 | if (not routingJSONFile): routingJSONFile = self.routingJSONFile
99 |
100 | if (openFromJSONFile and routingJSONFile):
101 | self.textEditRoutingJSONFile.clear()
102 | try:
103 | self.textEditRoutingJSONFile.setText(
104 | json.dumps(routingJSONFile, indent=4, sort_keys=False))
105 | except Exception:
106 | pass
107 | elif (not openFromJSONFile):
108 | # use default settings
109 | self.textEditRoutingJSONFile.setText(
110 | json.dumps(self.routingJSONFile, indent=4, sort_keys=False))
111 |
112 | def createRoutingJSONFile(self):
113 | try:
114 | routingJSONFile = copy.deepcopy(
115 | json.loads(self.textEditRoutingJSONFile.toPlainText()))
116 | except Exception:
117 | routingJSONFile = {}
118 |
119 | return routingJSONFile
120 |
121 |
122 | if __name__ == "__main__":
123 | app = QApplication(sys.argv)
124 | ex = routingTab()
125 | v = QVBoxLayout()
126 | v.addWidget(ex.createRoutingTab())
127 | ex.setLayout(v)
128 | ex.setGeometry(200, 100, 800, 768)
129 | ex.show()
130 | sys.exit(app.exec_())
131 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/statsTAB.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # this feature has not support, it's good for servers, not client side
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/toolbox/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/v2ray/V2Ray-shell_alpha/df72d9cc8c4dfb0fa7215580bdd16f76edcf7fbe/src/bridgehouse/editMap/toolbox/__init__.py
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/toolbox/toolbox.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtCore import QModelIndex, Qt, pyqtSignal, QObject, QTimer
2 | from PyQt5.QtGui import QStandardItemModel
3 | from PyQt5.QtWidgets import (QApplication, QStyledItemDelegate,
4 | QTableView, QWidget, QPushButton, QLineEdit, QStyle, QSpinBox,
5 | QComboBox)
6 | import uuid
7 |
8 | class UUIDLineEdit(QLineEdit):
9 | def __init__(self, parent=None, btnName=None):
10 | QLineEdit.__init__(self, parent)
11 |
12 | self.btn = QPushButton(btnName, self)
13 |
14 | frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth)
15 | self.setStyleSheet('QLineEdit {{ padding-left: {}px; }} '.format(
16 | self.btn.sizeHint().width() + frameWidth + 1))
17 | msz = self.minimumSizeHint()
18 | self.setMinimumSize(max(msz.width(), self.btn.sizeHint().height() + frameWidth * 2 + 2),
19 | max(msz.height(), self.btn.sizeHint().height() + frameWidth * 2 + 2))
20 | self.setInputMask("HHHHHHHH-HHHH-HHHH-HHHH-HHHHHHHHHHHH; ")
21 | self.btn.clicked.connect(lambda: self.setText(str(uuid.uuid4())))
22 |
23 |
24 | class UUIDLineEditDelegate(QStyledItemDelegate):
25 | def __init__(self, btnName=None):
26 | super(UUIDLineEditDelegate, self).__init__()
27 | self.btnName = btnName
28 |
29 | def createEditor(self, parent, option, index):
30 | editor = UUIDLineEdit(parent, self.btnName)
31 | return editor
32 |
33 | def setEditorData(self, lineEdit, index):
34 | value = index.model().data(index, Qt.EditRole)
35 | lineEdit.setText(str(value))
36 |
37 | def setModelData(self, lineEdit, model, index):
38 | value = lineEdit.text()
39 | model.setData(index, value, Qt.EditRole)
40 |
41 | def updateEditorGeometry(self, lineEdit, option, index):
42 | lineEdit.setGeometry(option.rect)
43 |
44 |
45 | class SpinBoxDelegate(QStyledItemDelegate):
46 | def __init__(self, min=False, max=False):
47 | super(SpinBoxDelegate, self).__init__()
48 | self.min, self.max = min, max
49 |
50 | def createEditor(self, parent, option, index):
51 | editor = QSpinBox(parent)
52 | editor.setFrame(False)
53 | editor.setMinimum(int(self.min))
54 | editor.setMaximum(int(self.max))
55 | editor.setValue(0)
56 |
57 | return editor
58 |
59 | def setEditorData(self, spinBox, index):
60 | value = index.model().data(index, Qt.EditRole)
61 |
62 | spinBox.setValue(0 if not value else value)
63 |
64 | def setModelData(self, spinBox, model, index):
65 | spinBox.interpretText()
66 | value = spinBox.value()
67 |
68 | model.setData(index, value, Qt.EditRole)
69 |
70 | def updateEditorGeometry(self, editor, option, index):
71 | editor.setGeometry(option.rect)
72 |
73 |
74 | class ComboBoxSpinBoxDelegate(QStyledItemDelegate):
75 | def __init__(self, comboList=None):
76 | super(ComboBoxSpinBoxDelegate, self).__init__()
77 | self.comboList = comboList
78 |
79 | def createEditor(self, parent, option, index):
80 | if index.parent().row() != -1:
81 | editor = QComboBox(parent)
82 | if self.comboList:
83 | editor.addItems(self.comboList)
84 |
85 | return editor
86 | else:
87 | editor = QSpinBox(parent)
88 | editor.setMaximum(65535)
89 | editor.setMinimum(0)
90 | editor.setValue(443)
91 | return editor
92 |
93 | def setEditorData(self, comboBox, index):
94 | value = index.model().data(index, Qt.EditRole)
95 | if index.parent().row() != -1 and value in self.comboList:
96 | comboBox.setCurrentText(value)
97 | else:
98 | try:
99 | comboBox.setValue(int(value))
100 | except:
101 | pass
102 |
103 | def setModelData(self, comboBox, model, index):
104 | if index.parent().row() != -1:
105 | value = comboBox.currentText()
106 | else:
107 | value = comboBox.value()
108 | model.setData(index, value, Qt.EditRole)
109 |
110 | def updateEditorGeometry(self, editor, option, index):
111 | editor.setGeometry(option.rect)
112 |
113 | class ComboBoxDelegate(QStyledItemDelegate):
114 | def __init__(self, comboList=None):
115 | super(ComboBoxDelegate, self).__init__()
116 | self.comboList = comboList
117 |
118 | def createEditor(self, parent, option, index):
119 | editor = QComboBox(parent)
120 | if self.comboList:
121 | editor.addItems(self.comboList)
122 |
123 | return editor
124 |
125 | def setEditorData(self, comboBox, index):
126 | value = index.model().data(index, Qt.EditRole)
127 | if value in self.comboList:
128 | comboBox.setCurrentText(value)
129 |
130 | def setModelData(self, comboBox, model, index):
131 | value = comboBox.currentText()
132 |
133 | model.setData(index, value, Qt.EditRole)
134 |
135 | def updateEditorGeometry(self, editor, option, index):
136 | editor.setGeometry(option.rect)
137 |
138 |
139 | class MyComboBox(QComboBox, QObject):
140 | previousTextChanged = pyqtSignal(str, str, name="previousTextChanged")
141 |
142 | def __init__(self, parent=None):
143 | super(MyComboBox, self).__init__()
144 | self.currentTextChanged.connect(self.previousTextChangedSlot)
145 | self.oldText = None
146 |
147 | def previousTextChangedSlot(self, newText):
148 | oldText, self.oldText = self.oldText, newText
149 | self.previousTextChanged.emit(oldText, newText)
150 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/transport/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from bridgehouse.editMap import logTAB
4 |
5 | logbook = logTAB.logBook()
6 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/transport/certificatesPanel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/transport/dsPanel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QLabel, QWidget, QGroupBox,
4 | QLineEdit, QHBoxLayout, QVBoxLayout,
5 | QPushButton)
6 | from PyQt5.QtCore import QFileInfo, QCoreApplication
7 | import sys
8 |
9 | v2rayshellDebug = False
10 |
11 | if __name__ == "__main__":
12 | v2rayshellDebug = True
13 | # this for debug test
14 | path = QFileInfo(sys.argv[0])
15 | srcPath = path.absoluteFilePath().split("/")
16 | sys.path.append("/".join(srcPath[:-4]))
17 |
18 | class domainSocketPanel(QWidget):
19 |
20 | def __init__(self):
21 | super().__init__()
22 | self.domainSocketJSONFile = {
23 | "path": "/path/to/ds/file"
24 | }
25 | self.translate = QCoreApplication.translate
26 |
27 | def createdsSettingPanel(self):
28 | labelPath = QLabel(self.translate("domainSocketPanel", 'Path:'), self)
29 | self.lineEditPath = QLineEdit(self)
30 |
31 | vbox = QVBoxLayout()
32 | vbox.addWidget(labelPath)
33 | vbox.addWidget(self.lineEditPath)
34 |
35 | self.groupBoxdsSetting = groupBoxdsSetting = QGroupBox(
36 | self.translate("domainSocketPanel", "Domain Socket Setting"), self)
37 | groupBoxdsSetting.setCheckable(True)
38 | groupBoxdsSetting.setChecked(False)
39 | groupBoxdsSetting.setLayout(vbox)
40 |
41 | if (v2rayshellDebug):
42 | self.__debugBtn = QPushButton("__debugTest", self)
43 | self.__debugBtn.clicked.connect(self.__debugTest)
44 | vbox.addWidget(self.__debugBtn)
45 |
46 | return groupBoxdsSetting
47 |
48 | def settingdsPanelFromJSONFile(self, dsJSONFile, openFromJSONFile=False):
49 |
50 | if not dsJSONFile:
51 | dsJSONFile = {}
52 | self.cleardsPanel()
53 |
54 | try:
55 | dsJSONFile['path']
56 | except KeyError:
57 | dsJSONFile['path'] = ''
58 |
59 | self.lineEditPath.setText(str(dsJSONFile['path']))
60 |
61 | def createdsSettingJSONFile(self):
62 | dsJSONFile = {}
63 | dsJSONFile['path'] = self.lineEditPath.text()
64 |
65 | return dsJSONFile
66 |
67 | def cleardsPanel(self):
68 | self.groupBoxdsSetting.setChecked(False)
69 | self.lineEditPath.clear()
70 |
71 | def __debugTest(self):
72 | import json
73 | print(json.dumps(self.createdsSettingJSONFile(), indent=4, sort_keys=False))
74 |
75 |
76 | if __name__ == "__main__":
77 | from PyQt5.QtWidgets import QApplication
78 | app = QApplication(sys.argv)
79 | ex = domainSocketPanel()
80 | ex.createdsSettingPanel()
81 | ex.setGeometry(300, 300, 680, 230)
82 | ex.show()
83 | sys.exit(app.exec_())
84 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/transport/http2Panel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QLabel, QWidget, QGroupBox,
4 | QLineEdit, QGridLayout, QPushButton)
5 | from PyQt5.QtCore import QFileInfo, QCoreApplication
6 | import sys, re
7 |
8 | v2rayshellDebug = False
9 |
10 | if __name__ == "__main__":
11 | v2rayshellDebug = True
12 | # this for debug test
13 | path = QFileInfo(sys.argv[0])
14 | srcPath = path.absoluteFilePath().split("/")
15 | sys.path.append("/".join(srcPath[:-4]))
16 |
17 | from bridgehouse.editMap.transport import logbook
18 |
19 |
20 | class http2Panel(QWidget):
21 | def __init__(self):
22 | super(http2Panel, self).__init__()
23 | self.httpJSONFile = {
24 | "host": ["v2ray.com"],
25 | "path": "/random/path"
26 | }
27 | self.translate = QCoreApplication.translate
28 |
29 | def createHttpSettingPanel(self):
30 | labelHost = QLabel(self.translate("http2Panel", "Host: "), self)
31 | self.lineEditHost = QLineEdit()
32 |
33 | labelPath = QLabel(self.translate("http2Panel", "Path: "), self)
34 | self.lineEditPath = QLineEdit()
35 |
36 | grid = QGridLayout(self)
37 | grid.addWidget(labelHost,0, 0)
38 | grid.addWidget(self.lineEditHost, 0, 1)
39 | grid.addWidget(labelPath, 1, 0)
40 | grid.addWidget(self.lineEditPath, 1, 1)
41 |
42 | self.groupBoxhttp = box = QGroupBox(self.translate("http2Panel", "http Settings "), self)
43 | box.setCheckable(True)
44 | box.setChecked(False)
45 | box.setLayout(grid)
46 |
47 | if (v2rayshellDebug):
48 | self.__debugBtn = QPushButton("__debugTest", self)
49 | self.__debugBtn.clicked.connect(self.__debugTest)
50 | grid.addWidget(self.__debugBtn, 2, 0)
51 | self.settingHttpPanelFromJSONFile(self.httpJSONFile, True)
52 |
53 | return box
54 |
55 | def settingHttpPanelFromJSONFile(self, httpJSONFile, openFromJSONFile=False):
56 | logbook.setisOpenJSONFile(openFromJSONFile)
57 |
58 | if (not httpJSONFile):
59 | self.lineEditHost.clear()
60 | self.lineEditPath.clear()
61 | self.groupBoxhttp.setChecked(False)
62 | del httpJSONFile
63 | return False
64 |
65 | try:
66 | httpJSONFile["host"]
67 | except Exception:
68 | httpJSONFile["host"] = []
69 |
70 | try:
71 | httpJSONFile["path"]
72 | except Exception:
73 | httpJSONFile["path"] = ""
74 |
75 |
76 | if (httpJSONFile["host"]):
77 | self.lineEditHost.setText(", ".join([str(x) for x in httpJSONFile["host"]]))
78 |
79 | if (httpJSONFile["path"]):
80 | self.lineEditPath.setText(httpJSONFile["path"])
81 |
82 | def createHttpSettingJSONFile(self):
83 | httpJSONFile = {}
84 | httpJSONFile["host"] = [x.strip() for x in re.split(r"[,;]", self.lineEditHost.text())]
85 | httpJSONFile["path"] = self.lineEditPath.text()
86 |
87 | return httpJSONFile
88 |
89 | def clearHttpPanel(self):
90 | self.lineEditHost.clear()
91 | self.lineEditPath.clear()
92 | self.groupBoxhttp.setChecked(False)
93 |
94 | def __debugTest(self):
95 | import json
96 | print(json.dumps(self.createHttpSettingJSONFile(), indent=4, sort_keys=False))
97 |
98 | if __name__ == "__main__":
99 | from PyQt5.QtWidgets import QApplication
100 | app = QApplication(sys.argv)
101 | ex = http2Panel()
102 | ex.createHttpSettingPanel()
103 | ex.setGeometry(300, 300, 680, 230)
104 | ex.show()
105 | sys.exit(app.exec_())
106 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/transport/mkcpPanel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QLabel, QSpinBox, QComboBox, QCheckBox, QWidget,
4 | QGridLayout, QGroupBox, QPushButton)
5 | from PyQt5.QtCore import QFileInfo, QCoreApplication
6 |
7 | v2rayshellDebug = False
8 | import sys
9 |
10 | if __name__ == "__main__":
11 | v2rayshellDebug = True
12 | # this for debug test
13 | path = QFileInfo(sys.argv[0])
14 | srcPath = path.absoluteFilePath().split("/")
15 | sys.path.append("/".join(srcPath[:-4]))
16 |
17 | from bridgehouse.editMap.transport import logbook
18 |
19 |
20 | class mKcpPanel(QWidget):
21 |
22 | def __init__(self):
23 | super().__init__()
24 | self.mKcpJSONFile = {
25 | "mtu": 1355,
26 | "tti": 50,
27 | "uplinkCapacity": 5,
28 | "downlinkCapacity": 20,
29 | "congestion": False,
30 | "readBufferSize": 2,
31 | "writeBufferSize": 2,
32 | "header": {
33 | "type": "none"
34 | }
35 | }
36 | self.translate = QCoreApplication.translate
37 | self.headerTypes = ("none", "srtp", "uTP", "wechat-video")
38 |
39 | def createmKcpSettingPanel(self):
40 | labelMTU = QLabel(
41 | self.translate("mKcpPanel", "MTU: "), self)
42 | self.spinBoxmKcpMTU = QSpinBox()
43 | labelTTI = QLabel(
44 | self.translate("mKcpPanel", "TTI: "), self)
45 | self.spinBoxmKcpTTI = QSpinBox()
46 | labelUplinkCapacity = QLabel(
47 | self.translate("mKcpPanel", "Uplink Capacity: "), self)
48 | self.spinBoxUpCapacity = QSpinBox()
49 | labelDownlinckCapacity = QLabel(
50 | self.translate("mKcpPanel", "Downlink Capacity: "), self)
51 | self.spinBoxDownCapacity = QSpinBox()
52 | labelReadBufferSize = QLabel(
53 | self.translate("mKcpPanel", "Read Buffer Size: "), self)
54 | self.spinBoxRdBufferSize = QSpinBox()
55 | labelWriteBufferSize = QLabel(
56 | self.translate("mKcpPanel", "Write Buffer Size: "), self)
57 | self.spinBoxWrBufferSize = QSpinBox()
58 | self.checkBoxCongestion = QCheckBox(
59 | self.translate("mKcpPanel", "Congestion"), self)
60 | labelHeaderType = QLabel(
61 | self.translate("mKcpPanel", "Header Type: "), self)
62 | self.comboBoxHeader = QComboBox()
63 |
64 | self.spinBoxmKcpMTU.setRange(576, 1460)
65 | self.spinBoxmKcpMTU.setValue(1335)
66 | self.spinBoxmKcpTTI.setRange(10, 100)
67 | self.spinBoxmKcpTTI.setValue(50)
68 | self.spinBoxUpCapacity.setRange(0, 9212500) # Francesco Poletti 73.7 Tb/s
69 | self.spinBoxUpCapacity.setValue(5)
70 | self.spinBoxDownCapacity.setRange(0, 9212500)
71 | self.spinBoxDownCapacity.setValue(20)
72 | self.spinBoxRdBufferSize.setRange(0, 230584301) # 2.30584301 * 10^12 (2^64 bit)
73 | self.spinBoxRdBufferSize.setValue(2)
74 | self.spinBoxWrBufferSize.setRange(0, 230584301)
75 | self.spinBoxWrBufferSize.setValue(2)
76 | self.comboBoxHeader.addItems(self.headerTypes)
77 |
78 | gridBoxmKCP = QGridLayout(self)
79 | gridBoxmKCP.addWidget(labelMTU, 0, 0)
80 | gridBoxmKCP.addWidget(self.spinBoxmKcpMTU, 0, 1)
81 | gridBoxmKCP.addWidget(labelTTI, 0, 2)
82 | gridBoxmKCP.addWidget(self.spinBoxmKcpTTI, 0, 3)
83 |
84 | gridBoxmKCP.addWidget(labelUplinkCapacity, 1, 0)
85 | gridBoxmKCP.addWidget(self.spinBoxUpCapacity, 1, 1)
86 | gridBoxmKCP.addWidget(labelDownlinckCapacity, 1, 2)
87 | gridBoxmKCP.addWidget(self.spinBoxDownCapacity, 1, 3)
88 |
89 | gridBoxmKCP.addWidget(labelReadBufferSize, 2, 0)
90 | gridBoxmKCP.addWidget(self.spinBoxRdBufferSize, 2, 1)
91 | gridBoxmKCP.addWidget(labelWriteBufferSize, 2, 2)
92 | gridBoxmKCP.addWidget(self.spinBoxWrBufferSize, 2, 3)
93 | gridBoxmKCP.addWidget(self.checkBoxCongestion, 3, 0)
94 | gridBoxmKCP.addWidget(labelHeaderType, 4, 0)
95 | gridBoxmKCP.addWidget(self.comboBoxHeader, 4, 1)
96 |
97 | self.groupBoxmKCPSetting = groupBoxmKCPSetting = QGroupBox(
98 | self.translate("mKcpPanel", "mKcp Setting"), self)
99 | groupBoxmKCPSetting.setCheckable(True)
100 | groupBoxmKCPSetting.setChecked(False)
101 | groupBoxmKCPSetting.adjustSize()
102 | groupBoxmKCPSetting.setLayout(gridBoxmKCP)
103 |
104 | if (v2rayshellDebug):
105 | self.__debugBtn = QPushButton("__debugTest", self)
106 | gridBoxmKCP.addWidget(self.__debugBtn, 5, 0)
107 | self.__debugBtn.clicked.connect(self.__debugTest)
108 | self.settingmKcpPanelFromJSONFile(self.mKcpJSONFile, True)
109 |
110 | return groupBoxmKCPSetting
111 |
112 | def settingmKcpPanelFromJSONFile(self, mKcpJSONFile, openFromJSONFile=False):
113 | logbook.setisOpenJSONFile(openFromJSONFile)
114 |
115 | if (not mKcpJSONFile):
116 | mKcpJSONFile = {}
117 | self.groupBoxmKCPSetting.setChecked(False)
118 | return False
119 |
120 | try:
121 | mKcpJSONFile["mtu"]
122 | except KeyError as e:
123 | logbook.writeLog("mKcp", "KeyError", e)
124 | mKcpJSONFile["mtu"] = 1355
125 |
126 | try:
127 | mKcpJSONFile["tti"]
128 | except KeyError as e:
129 | logbook.writeLog("mKcp", "KeyError", e)
130 | mKcpJSONFile["tti"] = 50
131 |
132 | try:
133 | mKcpJSONFile["uplinkCapacity"]
134 | except KeyError as e:
135 | logbook.writeLog("mKcp", "KeyError", e)
136 | mKcpJSONFile["uplinkCapacity"] = 5
137 |
138 | try:
139 | mKcpJSONFile["downlinkCapacity"]
140 | except KeyError as e:
141 | logbook.writeLog("mKcp", "KeyError", e)
142 | mKcpJSONFile["downlinkCapacity"] = 20
143 |
144 | try:
145 | mKcpJSONFile["congestion"]
146 | except KeyError as e:
147 | logbook.writeLog("mKcp", "KeyError", e)
148 | mKcpJSONFile["congestion"] = False
149 |
150 | try:
151 | mKcpJSONFile["readBufferSize"]
152 | except KeyError as e:
153 | logbook.writeLog("mKcp", "KeyError", e)
154 | mKcpJSONFile["readBufferSize"] = 2
155 |
156 | try:
157 | mKcpJSONFile["writeBufferSize"]
158 | except KeyError as e:
159 | logbook.writeLog("mKcp", "KeyError", e)
160 | mKcpJSONFile["writeBufferSize"] = 2
161 |
162 | try:
163 | mKcpJSONFile["header"]
164 | except KeyError as e:
165 | logbook.writeLog("mKcp", "KeyError", e)
166 | mKcpJSONFile["header"] = {}
167 |
168 | try:
169 | mKcpJSONFile["header"]["type"]
170 | except KeyError as e:
171 | logbook.writeLog("mKcp", "KeyError", e)
172 | mKcpJSONFile["header"]["type"] = "none"
173 |
174 | try:
175 | self.spinBoxmKcpMTU.setValue(int(mKcpJSONFile["mtu"]))
176 | except ValueError as e:
177 | logbook.writeLog("mKcp", "ValueError", e)
178 | mKcpJSONFile["mtu"] = 1355
179 |
180 | try:
181 | self.spinBoxmKcpTTI.setValue(int(mKcpJSONFile["tti"]))
182 | except ValueError as e:
183 | logbook.writeLog("mKcp", "ValueError", e)
184 | mKcpJSONFile["tti"] = 50
185 |
186 | try:
187 | self.spinBoxUpCapacity.setValue(int(mKcpJSONFile["uplinkCapacity"]))
188 | except ValueError as e:
189 | logbook.writeLog("mKcp", "ValueError", e)
190 | mKcpJSONFile["uplinkCapacity"] = 5
191 |
192 | try:
193 | self.spinBoxDownCapacity.setValue(int(mKcpJSONFile["downlinkCapacity"]))
194 | except ValueError as e:
195 | logbook.writeLog("mKcp", "ValueError", e)
196 | mKcpJSONFile["downlinkCapacity"] = 20
197 |
198 | try:
199 | self.checkBoxCongestion.setChecked(mKcpJSONFile["congestion"])
200 | except ValueError as e:
201 | logbook.writeLog("mKcp", "ValueError", e)
202 | mKcpJSONFile["congestion"] = False
203 |
204 | try:
205 | self.spinBoxRdBufferSize.setValue(int(mKcpJSONFile["readBufferSize"]))
206 | except ValueError as e:
207 | logbook.writeLog("mKcp", "ValueError", e)
208 | mKcpJSONFile["readBufferSize"] = 2
209 |
210 | try:
211 | self.spinBoxWrBufferSize.setValue(int(mKcpJSONFile["writeBufferSize"]))
212 | except ValueError as e:
213 | logbook.writeLog("mKcp", "ValueError", e)
214 | mKcpJSONFile["writeBufferSize"] = 2
215 |
216 | try:
217 | self.comboBoxHeader.setCurrentText(mKcpJSONFile["header"]["type"])
218 | except ValueError as e:
219 | logbook.writeLog("mKcp", "ValueError", e)
220 | except TypeError as e:
221 | logbook.writeLog("mKcp", "TypeError", e)
222 | except:
223 | logbook.writeLog("mKcp", "unkonw Error")
224 |
225 | def createmKcpSettingJSONFile(self):
226 | mKcpJSONFile = {}
227 |
228 | mKcpJSONFile["mtu"] = self.spinBoxmKcpMTU.value()
229 | mKcpJSONFile["tti"] = self.spinBoxmKcpTTI.value()
230 | mKcpJSONFile["uplinkCapacity"] = self.spinBoxUpCapacity.value()
231 | mKcpJSONFile["downlinkCapacity"] = self.spinBoxDownCapacity.value()
232 | mKcpJSONFile["congestion"] = self.checkBoxCongestion.isChecked()
233 | mKcpJSONFile["readBufferSize"] = self.spinBoxRdBufferSize.value()
234 | mKcpJSONFile["writeBufferSize"] = self.spinBoxWrBufferSize.value()
235 | mKcpJSONFile["header"] = {}
236 | mKcpJSONFile["header"]["type"] = self.comboBoxHeader.currentText()
237 |
238 | return mKcpJSONFile
239 |
240 | def clearmkcpPanel(self):
241 | self.groupBoxmKCPSetting.setChecked(False)
242 | self.spinBoxmKcpMTU.setValue(1355)
243 | self.spinBoxmKcpTTI.setValue(50)
244 | self.spinBoxUpCapacity.setValue(5)
245 | self.spinBoxDownCapacity.setValue(20)
246 | self.checkBoxCongestion.setChecked(False)
247 | self.spinBoxRdBufferSize.setValue(2)
248 | self.spinBoxWrBufferSize.setValue(2)
249 | self.comboBoxHeader.setCurrentIndex(0)
250 |
251 | def __debugTest(self):
252 | import json
253 | print(json.dumps(self.createmKcpSettingJSONFile(), indent=4, sort_keys=False))
254 |
255 |
256 | if __name__ == "__main__":
257 | from PyQt5.QtWidgets import QApplication
258 | app = QApplication(sys.argv)
259 | ex = mKcpPanel()
260 | ex.createmKcpSettingPanel()
261 | ex.setGeometry(300, 300, 680, 230)
262 | ex.show()
263 | sys.exit(app.exec_())
264 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/transport/muxPanel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QLabel, QWidget, QGroupBox, QHBoxLayout, QSpinBox, QPushButton)
4 | from PyQt5.QtCore import QFileInfo, QCoreApplication
5 | import sys
6 |
7 | v2rayshellDebug = False
8 |
9 | if __name__ == "__main__":
10 | v2rayshellDebug = True
11 | # this for debug test
12 | path = QFileInfo(sys.argv[0])
13 | srcPath = path.absoluteFilePath().split("/")
14 | sys.path.append("/".join(srcPath[:-4]))
15 |
16 | from bridgehouse.editMap.transport import logbook
17 |
18 |
19 | class muxPanel(QWidget):
20 |
21 | def __init__(self):
22 | super().__init__()
23 | self.muxJSONFile = {
24 | "enabled": False,
25 | "concurrency": 8
26 | }
27 | self.translate = QCoreApplication.translate
28 |
29 | self.groupBoxmuxSetting = QGroupBox(
30 | self.translate("muxPanel", "Mux Setting"), self)
31 | self.hboxConcurrency = QHBoxLayout()
32 |
33 | def createmuxSettingPanel(self):
34 | labelConcurrency = QLabel(
35 | self.translate("muxPanel", "Concurrency: "), self)
36 | self.spinBoxConcurrency = QSpinBox()
37 | self.spinBoxConcurrency.setRange(1, 1024)
38 | self.spinBoxConcurrency.setValue(8)
39 |
40 | hboxConcurrency = self.hboxConcurrency
41 | hboxConcurrency.addWidget(labelConcurrency)
42 | hboxConcurrency.addWidget(self.spinBoxConcurrency)
43 | hboxConcurrency.addStretch()
44 |
45 | self.groupBoxmuxSetting.setCheckable(True)
46 | self.groupBoxmuxSetting.setLayout(hboxConcurrency)
47 |
48 | if (v2rayshellDebug):
49 | from PyQt5.QtWidgets import QVBoxLayout
50 | self.__debugBtn = QPushButton("__debugTest", self)
51 | v = QVBoxLayout()
52 | v.addWidget(self.groupBoxmuxSetting)
53 | v.addWidget(self.__debugBtn)
54 | self.__debugBtn.clicked.connect(self.__debugTest)
55 | self.settingmuxPanelFromJSONFile(self.muxJSONFile, True)
56 | self.setLayout(v)
57 | return
58 |
59 | return self.groupBoxmuxSetting
60 |
61 | def settingmuxPanelFromJSONFile(self, muxJSONFile, openFromJSONFile=False):
62 | logbook.setisOpenJSONFile(openFromJSONFile)
63 |
64 | if (not muxJSONFile):
65 | muxJSONFile = {}
66 | self.groupBoxmuxSetting.setChecked(False)
67 | return
68 |
69 | try:
70 | muxJSONFile["enabled"]
71 | except KeyError as e:
72 | logbook.writeLog("mux", "KeyError", e)
73 | muxJSONFile["enabled"] = False
74 |
75 | try:
76 | muxJSONFile["concurrency"]
77 | except KeyError as e:
78 | logbook.writeLog("mux", "KeyError", e)
79 | muxJSONFile["concurrency"] = 8
80 |
81 | try:
82 | self.spinBoxConcurrency.setValue(int(muxJSONFile["concurrency"]))
83 | except ValueError as e:
84 | logbook.writeLog("mux", "ValueError", e)
85 | muxJSONFile["concurrency"] = 8
86 |
87 | self.groupBoxmuxSetting.setChecked(bool(muxJSONFile["enabled"]))
88 |
89 | def createmuxSettingJSONFile(self):
90 | muxJSONFile = {}
91 | muxJSONFile["enabled"] = self.groupBoxmuxSetting.isChecked()
92 | muxJSONFile["concurrency"] = self.spinBoxConcurrency.value()
93 |
94 | return muxJSONFile
95 |
96 | def clearmuxPanel(self):
97 | self.groupBoxmuxSetting.setChecked(False)
98 | self.spinBoxConcurrency.setValue(8)
99 |
100 | def __debugTest(self):
101 | import json
102 | print(json.dumps(self.createmuxSettingJSONFile(), indent=4, sort_keys=False))
103 |
104 |
105 | if __name__ == "__main__":
106 | from PyQt5.QtWidgets import QApplication
107 | app = QApplication(sys.argv)
108 | ex = muxPanel()
109 | ex.createmuxSettingPanel()
110 | ex.setGeometry(300, 300, 680, 230)
111 | ex.show()
112 | sys.exit(app.exec_())
113 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/transport/tcpPanel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QWidget, QGroupBox, QApplication,
4 | QHBoxLayout, QVBoxLayout, QTextEdit,
5 | QLabel, QComboBox, QPushButton)
6 | from PyQt5.QtCore import QFileInfo, QCoreApplication
7 | import sys, json
8 |
9 | v2rayshellDebug = False
10 |
11 | if __name__ == "__main__":
12 | v2rayshellDebug = True
13 | # this for debug test
14 | path = QFileInfo(sys.argv[0])
15 | srcPath = path.absoluteFilePath().split("/")
16 | sys.path.append("/".join(srcPath[:-4]))
17 |
18 | from bridgehouse.editMap.transport import logbook
19 |
20 |
21 | class TcpPanel(QWidget):
22 |
23 | def __init__(self):
24 | super().__init__()
25 | self.tcpJSONFile = {
26 | "header": {
27 | "type": "none"
28 | }
29 | }
30 | self.translate = QCoreApplication.translate
31 | self.httpHeader = "none", "http"
32 |
33 | def createTCPSettingPanel(self):
34 | labelHttpHeaderType = QLabel(
35 | self.translate("TcpPanel", "Http type: "), self)
36 | self.comboxHttpHeaderType = QComboBox(self)
37 | self.btnHttpHeaderTypeClear = QPushButton(
38 | self.translate("TcpPanel", "Clear"), self)
39 | self.textHttpHeaderType = QTextEdit()
40 |
41 | self.comboxHttpHeaderType.addItems(self.httpHeader)
42 | self.btnHttpHeaderTypeClear.hide()
43 | self.textHttpHeaderType.hide()
44 | self.textHttpHeaderType.adjustSize()
45 |
46 | hboxhttpHeader = QHBoxLayout()
47 | hboxhttpHeader.addWidget(labelHttpHeaderType)
48 | hboxhttpHeader.addWidget(self.comboxHttpHeaderType)
49 | hboxhttpHeader.addWidget(self.btnHttpHeaderTypeClear)
50 | hboxhttpHeader.addStretch()
51 |
52 | vboxTCPSetting = QVBoxLayout()
53 | vboxTCPSetting.addLayout(hboxhttpHeader)
54 | vboxTCPSetting.addWidget(self.textHttpHeaderType)
55 |
56 | self.groupBoxTCPSetting = groupBoxTCPSetting = QGroupBox(
57 | self.translate("TcpPanel", "TCP Settings"), self)
58 | groupBoxTCPSetting.setCheckable(True)
59 | groupBoxTCPSetting.setChecked(False)
60 | groupBoxTCPSetting.adjustSize()
61 | groupBoxTCPSetting.setLayout(vboxTCPSetting)
62 |
63 | self.createTCPSettingPanelSignles()
64 |
65 | if(v2rayshellDebug):
66 | self.__debugBtn = QPushButton("__debugTest", self)
67 | v = QVBoxLayout()
68 | v.addWidget(groupBoxTCPSetting)
69 | v.addWidget(self.__debugBtn)
70 | v.addStretch()
71 | self.setLayout(v)
72 | self.__debugBtn.clicked.connect(self.__debugTest)
73 | self.settingtcpPanelFromJSONFile(self.tcpJSONFile, True)
74 | return
75 |
76 | return groupBoxTCPSetting
77 |
78 | def createTCPSettingPanelSignles(self):
79 | self.comboxHttpHeaderType.currentTextChanged.connect(self.oncomboxHttpHeaderType)
80 | self.btnHttpHeaderTypeClear.clicked.connect(self.onbtnHttpHeaderTypeClear)
81 |
82 | def onbtnHttpHeaderTypeClear(self):
83 | self.textHttpHeaderType.clear()
84 |
85 | def oncomboxHttpHeaderType(self, e):
86 | if (e == "none"):
87 | self.textHttpHeaderType.hide()
88 | self.btnHttpHeaderTypeClear.hide()
89 |
90 | if (e == "http"):
91 | self.btnHttpHeaderTypeClear.show()
92 | self.textHttpHeaderType.show()
93 |
94 | def jsonDataValitor(self, jsonData):
95 | try:
96 | data = json.loads(str(jsonData))
97 | except ValueError as e:
98 | return -1, e
99 | return 0, data
100 |
101 | def settingtcpPanelFromJSONFile(self, tcpJSONFile, openFromJSONFile=False):
102 | logbook.setisOpenJSONFile(openFromJSONFile)
103 |
104 | if (not tcpJSONFile):
105 | tcpJSONFile = {}
106 | self.groupBoxTCPSetting.setChecked(False)
107 | self.textHttpHeaderType.clear()
108 | self.comboxHttpHeaderType.setCurrentText("none")
109 | return
110 |
111 | try:
112 | tcpJSONFile["header"]
113 | except KeyError as e:
114 | logbook.writeLog("transport TCP", "KeyError", e)
115 | tcpJSONFile["header"] = {}
116 |
117 | try:
118 | tcpJSONFile["header"]["type"]
119 | except KeyError as e:
120 | logbook.writeLog("transport TCP", "KeyError", e)
121 | tcpJSONFile["header"]["type"] = "none"
122 |
123 | if (tcpJSONFile["header"]["type"] == "http"):
124 | self.textHttpHeaderType.setText(
125 | json.dumps(tcpJSONFile["header"], indent=4, sort_keys=False))
126 | self.comboxHttpHeaderType.setCurrentText("http")
127 | elif (tcpJSONFile["header"]["type"] == "none"):
128 | self.textHttpHeaderType.clear()
129 | else:
130 | # TODO pop a error message
131 | pass
132 |
133 | def createtcpSettingJSONFile(self):
134 | tcpJSONFile = {}
135 | tcpJSONFile["header"] = {}
136 |
137 | if (self.comboxHttpHeaderType.currentText() == "http"):
138 | header = self.textHttpHeaderType.toPlainText()
139 | checkjsonfile = self.jsonDataValitor(header)
140 | if (checkjsonfile[0] == -1):
141 | tcpJSONFile["header"]["type"] = "none"
142 | return tcpJSONFile
143 |
144 | if (not checkjsonfile[0]):
145 | header = checkjsonfile[1]
146 | http = False
147 | try:
148 | # use input text maybe no value type
149 | http = (header["type"] == "http")
150 | except KeyError:
151 | # TODO pop a error message
152 | pass
153 | except:
154 | # TODO pop a error message
155 | pass
156 |
157 | if(http):
158 | tcpJSONFile["header"] = header
159 | else:
160 | tcpJSONFile["header"]["type"] = "none"
161 | else:
162 | tcpJSONFile["header"]["type"] = "none"
163 |
164 | return tcpJSONFile
165 |
166 | def cleartcpPanel(self):
167 | self.groupBoxTCPSetting.setChecked(False)
168 | self.comboxHttpHeaderType.setCurrentIndex(0)
169 | self.textHttpHeaderType.clear()
170 |
171 | def __debugTest(self):
172 | print(json.dumps(self.createtcpSettingJSONFile(), indent=4, sort_keys=False))
173 |
174 |
175 | if __name__ == "__main__":
176 | app = QApplication(sys.argv)
177 | ex = TcpPanel()
178 | ex.createTCPSettingPanel()
179 | ex.setGeometry(300, 300, 680, 620)
180 | ex.show()
181 | sys.exit(app.exec_())
182 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/transport/wsPanel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QLabel, QWidget, QGroupBox,
4 | QLineEdit, QHBoxLayout, QVBoxLayout,
5 | QPushButton)
6 | from PyQt5.QtCore import QFileInfo, QCoreApplication
7 | import sys
8 |
9 | v2rayshellDebug = False
10 |
11 | if __name__ == "__main__":
12 | v2rayshellDebug = True
13 | # this for debug test
14 | path = QFileInfo(sys.argv[0])
15 | srcPath = path.absoluteFilePath().split("/")
16 | sys.path.append("/".join(srcPath[:-4]))
17 |
18 | from bridgehouse.editMap.transport import logbook
19 |
20 |
21 | class wsPanel(QWidget):
22 |
23 | def __init__(self):
24 | super().__init__()
25 | self.wsJSONFile = {
26 | "path": "",
27 | "headers": {
28 | "Host": "v2ray.com"
29 | }
30 | }
31 | self.translate = QCoreApplication.translate
32 |
33 | def createwsSettingPanel(self):
34 | labelPath = QLabel(self.translate("wsPanel", "Path: "), self)
35 | self.lineEditwebsocksPath = QLineEdit()
36 | labelHost = QLabel(self.translate("wsPanel", "Host: "), self)
37 | self.lineEditwebsocksHost = QLineEdit()
38 |
39 | hboxPath = QHBoxLayout()
40 | hboxPath.addWidget(labelPath)
41 | hboxPath.addWidget(self.lineEditwebsocksPath)
42 |
43 | hboxHost = QHBoxLayout()
44 | hboxHost.addWidget(labelHost)
45 | hboxHost.addWidget(self.lineEditwebsocksHost)
46 |
47 | vboxwsSetting = QVBoxLayout()
48 | vboxwsSetting.addLayout(hboxPath)
49 | vboxwsSetting.addLayout(hboxHost)
50 |
51 | self.groupBoxwsSetting = groupBoxwsSetting = QGroupBox(
52 | self.translate("wsPanel", "WebSocket Setting"), self)
53 | groupBoxwsSetting.setCheckable(True)
54 | groupBoxwsSetting.setChecked(False)
55 | groupBoxwsSetting.adjustSize()
56 | groupBoxwsSetting.setLayout(vboxwsSetting)
57 |
58 | if (v2rayshellDebug):
59 | self.__debugBtn = QPushButton("__debugTest", self)
60 | self.__debugBtn.clicked.connect(self.__debugTest)
61 | vboxwsSetting.addWidget(self.__debugBtn)
62 | self.settingwsPanelFromJSONFile(self.wsJSONFile, True)
63 |
64 | return groupBoxwsSetting
65 |
66 | def settingwsPanelFromJSONFile(self, wsJSONFile, openFromJSONFile=False):
67 | logbook.setisOpenJSONFile(openFromJSONFile)
68 |
69 | if (not wsJSONFile):
70 | wsJSONFile = {}
71 | self.groupBoxwsSetting.setChecked(False)
72 | self.lineEditwebsocksHost.clear()
73 | self.lineEditwebsocksPath.clear()
74 | return False
75 | try:
76 | wsJSONFile["path"]
77 | except KeyError as e:
78 | logbook.writeLog("transport ws", "KeyError", e)
79 | wsJSONFile["path"] = ""
80 |
81 | try:
82 | wsJSONFile["headers"]
83 | except KeyError as e:
84 | logbook.writeLog("transport ws", "KeyError", e)
85 | wsJSONFile["headers"] = {}
86 |
87 | try:
88 | wsJSONFile["headers"]["Host"]
89 | except KeyError as e:
90 | logbook.writeLog("transport ws", "KeyError", e)
91 | wsJSONFile["headers"]["Host"] = ""
92 |
93 | self.lineEditwebsocksPath.setText(str(wsJSONFile["path"]))
94 | self.lineEditwebsocksHost.setText(str(wsJSONFile["headers"]["Host"]))
95 |
96 | def createwsSettingJSONFile(self):
97 | wsJSONFile = {}
98 | wsJSONFile["headers"] = {}
99 | wsJSONFile["headers"]["Host"] = self.lineEditwebsocksHost.text()
100 | wsJSONFile["path"] = self.lineEditwebsocksPath.text()
101 |
102 | return wsJSONFile
103 |
104 | def clearwsPanel(self):
105 | self.lineEditwebsocksHost.clear()
106 | self.lineEditwebsocksPath.clear()
107 | self.groupBoxwsSetting.setChecked(False)
108 |
109 | def __debugTest(self):
110 | import json
111 | print(json.dumps(self.createwsSettingJSONFile(), indent=4, sort_keys=False))
112 |
113 |
114 | if __name__ == "__main__":
115 | from PyQt5.QtWidgets import QApplication
116 | app = QApplication(sys.argv)
117 | ex = wsPanel()
118 | ex.createwsSettingPanel()
119 | ex.setGeometry(300, 300, 680, 230)
120 | ex.show()
121 | sys.exit(app.exec_())
122 |
--------------------------------------------------------------------------------
/src/bridgehouse/editMap/transportTAB.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QApplication, QPushButton, QVBoxLayout)
4 | from PyQt5.QtCore import QFileInfo, QCoreApplication
5 | import sys, json
6 |
7 | v2rayshellDebug = False
8 |
9 | if __name__ == "__main__":
10 | v2rayshellDebug = True
11 | # this for debug test
12 | path = QFileInfo(sys.argv[0])
13 | srcPath = path.absoluteFilePath().split("/")
14 | sys.path.append("/".join(srcPath[:-3]))
15 |
16 | from bridgehouse.editMap.transport import transportPanel
17 |
18 |
19 | class transportTab(transportPanel.TransportPanel):
20 |
21 | def __init__(self):
22 | super().__init__()
23 | self.translate = QCoreApplication.translate
24 |
25 | def createTransportPanel(self):
26 | super(transportTab, self).createTransportPanel()
27 |
28 | if v2rayshellDebug:
29 | self.setLayout(self.vboxcheckBoxStreamSetting)
30 | self.__debugBtn = QPushButton("__debugTest", self)
31 | self.vboxTransportPanel.addWidget(self.__debugBtn)
32 | self.__debugBtn.clicked.connect(self.__debugTest)
33 | self.settingtransportPanelFromJSONFile(self.transportJSONFile, True)
34 |
35 | self.groupTransportPanel.setTitle(self.translate("transportTab", "Transport Setting (Global)"))
36 | self.groupTransportPanel.setCheckable(True)
37 | self.groupTransportPanel.setChecked(False)
38 |
39 | return self.groupTransportPanel
40 |
41 | def __debugTest(self):
42 | print(json.dumps(self.createtransportSettingJSONFile(), indent=4, sort_keys=False))
43 |
44 |
45 | if __name__ == "__main__":
46 | app = QApplication(sys.argv)
47 | ex = transportTab()
48 | v = QVBoxLayout()
49 | v.addWidget(ex.createTransportPanel())
50 | ex.setLayout(v)
51 | ex.setGeometry(200, 100, 800, 768)
52 | ex.show()
53 | sys.exit(app.exec_())
54 |
--------------------------------------------------------------------------------
/src/bridgehouse/extension/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/v2ray/V2Ray-shell_alpha/df72d9cc8c4dfb0fa7215580bdd16f76edcf7fbe/src/bridgehouse/extension/__init__.py
--------------------------------------------------------------------------------
/src/bridgehouse/extension/bugReport.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from PyQt5.QtWidgets import (QApplication, QLabel, QPushButton,
4 | QVBoxLayout, QHBoxLayout, QTextEdit, QLineEdit,
5 | QGridLayout, QRadioButton, QGroupBox, QButtonGroup,
6 | QDialog, QSpacerItem)
7 | from PyQt5.QtCore import (QFile, QFileInfo, QUrl, QIODevice, QTimer,
8 | QCoreApplication, QSysInfo)
9 | from PyQt5.QtGui import QDesktopServices
10 | from PyQt5.Qt import QTextCursor, PYQT_VERSION_STR, QT_VERSION_STR
11 | import sys, copy, codecs
12 |
13 |
14 | class bugReport(QDialog):
15 |
16 | def __init__(self):
17 | super(bugReport, self).__init__()
18 | self.translate = QCoreApplication.translate
19 | self.readedHowReportBug = False
20 | self.timerAutoSave = QTimer()
21 | self.timerAutoSave.timeout.connect(self.onautoSave)
22 | self.timerAutoSave.start(1000 * 60 * 3)
23 |
24 | def createPanel(self):
25 | labelReportTitle = QLabel(self.translate("bugReport", "Bug Report Title: "))
26 | self.lineEditReportTitle = QLineEdit()
27 |
28 | labelTestedEnvironment = QLabel(self.translate("bugReport", "Tested Environment: "))
29 | self.lineEditTestedEnvironment = QLineEdit(
30 | self.translate("bugReport",
31 | """System Platform:{}_{} Python Version:{}.{}.{}-{} PyQt Version:{} QT Version:{}""").format(
32 | QSysInfo.prettyProductName() if QSysInfo.prettyProductName() == "unknown" else "{}-{}".format(QSysInfo.kernelType(), QSysInfo.kernelVersion()),
33 | QSysInfo.currentCpuArchitecture(),
34 | sys.version_info.major,
35 | sys.version_info.minor,
36 | sys.version_info.micro,
37 | sys.version_info.releaselevel,
38 | PYQT_VERSION_STR,
39 | QT_VERSION_STR))
40 |
41 | radioBtnQuickReport = QRadioButton(self.translate("bugReport", "Quick Report"))
42 | radioBtnKnowHowFix = QRadioButton(self.translate("bugReport", "Know How Fix"))
43 | radioBtnKnowHowFix.setChecked(True)
44 | radioBtnFeatureRequest = QRadioButton(self.translate("bugReport", "Feature Request"))
45 | buttonOpenHowReportBugURL = QPushButton(
46 | self.translate("bugReport", """Click Me! Read "HOW REPORT A BUG" before report a bug."""))
47 |
48 | self.buttonGroupBugReport = QButtonGroup()
49 | self.buttonGroupBugReport.addButton(radioBtnQuickReport)
50 | self.buttonGroupBugReport.addButton(radioBtnKnowHowFix)
51 | self.buttonGroupBugReport.addButton(radioBtnFeatureRequest)
52 | self.buttonGroupBugReport.addButton(buttonOpenHowReportBugURL)
53 |
54 | hboxRadiobutton = QHBoxLayout()
55 | hboxRadiobutton.addWidget(radioBtnKnowHowFix)
56 | hboxRadiobutton.addWidget(radioBtnQuickReport)
57 | hboxRadiobutton.addWidget(radioBtnFeatureRequest)
58 | hboxRadiobutton.addWidget(buttonOpenHowReportBugURL)
59 | hboxRadiobutton.addStretch()
60 |
61 | labelStepsToReproduce = QLabel(self.translate("bugReport", "Steps To Reproduce: "))
62 | self.textEditStepsToReproduce = QTextEdit()
63 |
64 | labelActualresults = QLabel(self.translate("bugReport", "Actual results: "))
65 | self.textEditActualresults = QTextEdit()
66 | self.textEditActualresults.insertPlainText(
67 | self.translate("bugReport", "if have Python's Traceback, Please Paste.\nif is V2Ray-core JSON Editor issue, please Paste the JSON File without server information."))
68 | self.textEditActualresults.setAcceptDrops(True)
69 |
70 | labelExpectedresults = QLabel(self.translate("bugReport", "Expected results: "))
71 | self.textEditExpectedresults = QTextEdit()
72 |
73 | labelFeatureRequest = QLabel(self.translate("bugReport", "Feature Request: "))
74 | self.textEditFeatureRequest = QTextEdit()
75 |
76 | labelQuickReport = QLabel(self.translate("bugReport", "Quick Report: "))
77 | self.textEditQuickReport = QTextEdit()
78 |
79 | labelHowFix = QLabel(self.translate("bugReport", "How Fix: "))
80 | self.textEditHowFix = QTextEdit()
81 |
82 | gridBoxReport = QGridLayout()
83 | gridBoxReport.addWidget(labelReportTitle, 0, 0)
84 | gridBoxReport.addWidget(self.lineEditReportTitle, 0, 1)
85 | gridBoxReport.addWidget(labelTestedEnvironment, 1, 0)
86 | gridBoxReport.addWidget(self.lineEditTestedEnvironment, 1, 1)
87 | gridBoxReport.addLayout(hboxRadiobutton, 2, 0, 1, 2)
88 |
89 | gridBoxQuickReport = QGridLayout()
90 | gridBoxQuickReport.addWidget(labelQuickReport, 0, 0)
91 | gridBoxQuickReport.addWidget(self.textEditQuickReport, 0, 1)
92 |
93 | self.groupBoxQuickReport = QGroupBox("", self)
94 | self.groupBoxQuickReport.setLayout(gridBoxQuickReport)
95 | self.groupBoxQuickReport.hide()
96 |
97 | gridBoxKnowHowFix = QGridLayout()
98 | gridBoxKnowHowFix.addWidget(labelStepsToReproduce, 0, 0)
99 | gridBoxKnowHowFix.addWidget(self.textEditStepsToReproduce, 0, 1)
100 | gridBoxKnowHowFix.addWidget(labelActualresults, 1, 0)
101 | gridBoxKnowHowFix.addWidget(self.textEditActualresults, 1, 1)
102 | self.buttonInsertPiture = QPushButton(self.translate("bugReport", "Insert Picture From URL:"))
103 | self.lineEditInserPiture = QLineEdit()
104 | gridBoxKnowHowFix.addWidget(self.lineEditInserPiture, 2, 1)
105 | gridBoxKnowHowFix.addWidget(self.buttonInsertPiture, 2, 0)
106 | gridBoxKnowHowFix.addItem(QSpacerItem(50, 50), 3, 0, 1, 4)
107 | gridBoxKnowHowFix.addWidget(labelExpectedresults, 4, 0)
108 | gridBoxKnowHowFix.addWidget(self.textEditExpectedresults, 4, 1)
109 | gridBoxKnowHowFix.addWidget(labelHowFix, 5, 0)
110 | gridBoxKnowHowFix.addWidget(self.textEditHowFix, 5, 1)
111 |
112 | self.groupBoxKnowHowFix = QGroupBox()
113 | self.groupBoxKnowHowFix.setLayout(gridBoxKnowHowFix)
114 |
115 | gridBoxFeatureRequest = QGridLayout()
116 | gridBoxFeatureRequest.addWidget(labelFeatureRequest, 0, 0)
117 | gridBoxFeatureRequest.addWidget(self.textEditFeatureRequest, 0, 1)
118 |
119 | self.groupBoxFeatureRequest = QGroupBox("", self)
120 | self.groupBoxFeatureRequest.setLayout(gridBoxFeatureRequest)
121 | self.groupBoxFeatureRequest.hide()
122 |
123 | hboxButton = QHBoxLayout()
124 | self.buttonExportBugReportText = QPushButton(self.translate("bugReport", "Export Bug Report Text"))
125 | self.buttonExitButReport = QPushButton(self.translate("bugReport", "Exit"))
126 | hboxButton.addStretch()
127 | hboxButton.addWidget(self.buttonExportBugReportText)
128 | hboxButton.addWidget(self.buttonExitButReport)
129 |
130 | vboxBugReport = QVBoxLayout(self)
131 | vboxBugReport.addLayout(gridBoxReport)
132 | vboxBugReport.addWidget(self.groupBoxQuickReport)
133 | vboxBugReport.addWidget(self.groupBoxKnowHowFix)
134 | vboxBugReport.addWidget(self.groupBoxFeatureRequest)
135 | vboxBugReport.addLayout(hboxButton)
136 | vboxBugReport.addStretch()
137 |
138 | self.settextEidtReadonly(result=True)
139 | self.createSignals()
140 |
141 | def createSignals(self):
142 | self.buttonGroupBugReport.buttonClicked.connect(self.onbuttonGroupBugReport)
143 | self.buttonExitButReport.clicked.connect(self.close)
144 | self.buttonExportBugReportText.clicked.connect(self.onautoSave)
145 | self.buttonInsertPiture.clicked.connect(self.onbuttonInsertPiture)
146 |
147 | def onbuttonInsertPiture(self):
148 | url = self.lineEditInserPiture.text()
149 | if url != "":
150 | url = QUrl(url)
151 | self.textEditActualresults.moveCursor(QTextCursor.End)
152 | self.textEditActualresults.insertPlainText("""\n
""".format(url.path()))
153 | self.textEditActualresults.moveCursor(QTextCursor.End)
154 | self.lineEditInserPiture.clear()
155 |
156 | def settextEidtReadonly(self, result=True):
157 | self.lineEditInserPiture.setReadOnly(result)
158 | self.textEditActualresults.setReadOnly(result)
159 | self.textEditExpectedresults.setReadOnly(result)
160 | self.textEditFeatureRequest.setReadOnly(result)
161 | self.textEditHowFix.setReadOnly(result)
162 | self.textEditQuickReport.setReadOnly(result)
163 | self.textEditStepsToReproduce.setReadOnly(result)
164 |
165 | def onautoSave(self):
166 | currentButton = self.buttonGroupBugReport.buttons()
167 | for i in currentButton:
168 | if i.isChecked():
169 | button = i.text()
170 | if button == self.translate("bugReport", "Quick Report"):
171 | self.savebugReportText(save=copy.deepcopy(self.saveQuickReport()))
172 | if button == self.translate("bugReport", "Know How Fix"):
173 | self.savebugReportText(save=copy.deepcopy(self.saveKnowHowFix()))
174 | if button == self.translate("bugReport", "Feature Request"):
175 | self.savebugReportText(save=copy.deepcopy(self.saveFeatureRequest()))
176 |
177 | def savebugReportText(self, save=False):
178 | if save:
179 | outFile = QFileInfo(self.translate("bugReport", "bugReport.txt"))
180 | fileName = outFile.fileName()
181 | if QFile.exists(fileName):
182 | QFile.remove(fileName)
183 |
184 | outFile = QFile(fileName)
185 | outFile.open(QIODevice.WriteOnly | QIODevice.Text)
186 | outFile.write(codecs.encode(save, "utf-8"))
187 |
188 | def saveQuickReport(self):
189 | bugReportText = self.translate("bugReport", "Bug Report Title: \n{}\nTested Environment: \n{}\n\nQuick Report:\n{}\n").format(
190 | self.lineEditReportTitle.text(),
191 | self.lineEditTestedEnvironment.text(),
192 | self.textEditQuickReport.toPlainText())
193 |
194 | return bugReportText
195 |
196 | def saveKnowHowFix(self):
197 | bugReportText = self.translate("bugReport", """Bug Report Title: {}
198 | \nTested Environment: \n{}
199 | \nSteps To Reproduce: \n{}
200 | \nActual Results: \n{}
201 | \nExpected Results: \n{}
202 | \nHow Fix: \n{}\n""").format(
203 | self.lineEditReportTitle.text(),
204 | self.lineEditTestedEnvironment.text(),
205 | self.textEditStepsToReproduce.toPlainText(),
206 | self.textEditActualresults.toPlainText(),
207 | self.textEditExpectedresults.toPlainText(),
208 | self.textEditHowFix.toPlainText())
209 |
210 | return bugReportText
211 |
212 | def saveFeatureRequest(self):
213 | bugReportText = self.translate("bugReport", """Feature Request Title: \n{}
214 | Tested Environment: \n{}
215 | Feature Request Details:\n{}\n""").format(
216 | self.lineEditReportTitle.text(),
217 | self.lineEditTestedEnvironment.text(),
218 | self.textEditFeatureRequest.toPlainText())
219 |
220 | return bugReportText
221 |
222 | def onbuttonGroupBugReport(self, button):
223 |
224 | def hideAllWidget():
225 | self.groupBoxFeatureRequest.hide()
226 | self.groupBoxKnowHowFix.hide()
227 | self.groupBoxQuickReport.hide()
228 |
229 | buttonText = button.text()
230 | if buttonText == self.translate("bugReport", "Quick Report"):
231 | hideAllWidget()
232 | self.groupBoxQuickReport.show()
233 | elif buttonText == self.translate("bugReport", "Know How Fix"):
234 | hideAllWidget()
235 | self.groupBoxKnowHowFix.show()
236 | elif buttonText == self.translate("bugReport", "Feature Request"):
237 | hideAllWidget()
238 | self.groupBoxFeatureRequest.show()
239 | elif buttonText == self.translate("bugReport", """Click Me! Read "HOW REPORT A BUG" before report a bug."""):
240 | QDesktopServices.openUrl(QUrl("https://www.chiark.greenend.org.uk/~sgtatham/bugs.html"))
241 | self.settextEidtReadonly(result=False)
242 |
243 |
244 | if __name__ == '__main__':
245 | app = QApplication(sys.argv)
246 | ex = bugReport()
247 | ex.createPanel()
248 | ex.setGeometry(250, 150, 1024, 768)
249 | ex.show()
250 | sys.exit(app.exec_())
251 |
--------------------------------------------------------------------------------
/src/bridgehouse/extension/runV2raycore.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | from PyQt5.QtWidgets import (QWidget, QVBoxLayout,
3 | QPushButton, QTextEdit, QLabel,
4 | QLineEdit, QGridLayout, QFileDialog, QButtonGroup)
5 | from PyQt5.QtCore import (QProcess, QSize, QIODevice, QProcessEnvironment,
6 | QObject, pyqtSignal, QCoreApplication, QFileInfo,
7 | QFile, qDebug)
8 | from PyQt5.Qt import QTextCursor
9 |
10 | import re
11 | import sys
12 | import codecs
13 | import os
14 | import signal
15 |
16 | v2rayshellDebug = False
17 |
18 | if __name__ == "__main__":
19 | v2rayshellDebug = True
20 | # this for debug test
21 | path = QFileInfo(sys.argv[0])
22 | srcPath = path.absoluteFilePath().split("/")
23 | sys.path.append("/".join(srcPath[:-3]))
24 |
25 |
26 | class runV2raycore(QObject):
27 | """
28 | you should emit a signal to start or stop a program.
29 | """
30 | start = pyqtSignal()
31 | stop = pyqtSignal()
32 |
33 | def __init__(self,
34 | outputTextEdit,
35 | v2rayPath="v2ray",
36 | v2rayOption="",
37 | bridgetreasureChest=False):
38 | super().__init__()
39 | self.outputTextEdit = outputTextEdit
40 | self.v2rayPath = v2rayPath
41 | self.v2rayOption = v2rayOption
42 | self.bridgetreasureChest = bridgetreasureChest
43 | if not self.bridgetreasureChest:
44 | from bridgehouse.extension import bridgetreasureChest
45 | self.bridgetreasureChest = bridgetreasureChest.bridgetreasureChest()
46 |
47 | self.v2rayProcess = QProcess()
48 | self.v2rayProcess.setProcessChannelMode(QProcess.MergedChannels)
49 | self.v2rayProcess.setProcessEnvironment(
50 | QProcessEnvironment.systemEnvironment())
51 |
52 | self.v2rayProcess.readyRead.connect(self.setoutputTextEdit)
53 | self.v2rayProcess.started.connect(self.oncreatePIDFile)
54 | self.start.connect(self.onstart)
55 | self.stop.connect(self.onstop)
56 | self.translate = QCoreApplication.translate
57 | self.pidFile = ".v2rayPID"
58 |
59 | def onstart(self):
60 | if (self.v2rayProcess.state() == QProcess.NotRunning):
61 | self.outputTextEdit.clear()
62 | command = self.translate(
63 | "runV2raycore", "v2ray file path had no seted.")
64 | if (self.v2rayPath):
65 | checkSpaces = re.search(" ", self.v2rayPath)
66 | if checkSpaces:
67 | # in fact, you can just keep this line.
68 | # do not need check spaces
69 | command = '"' + self.v2rayPath + '" ' + self.v2rayOption
70 | else:
71 | command = "{} {}".format(self.v2rayPath, self.v2rayOption)
72 | self.killOrphanProcess()
73 | self.v2rayProcess.start(command, QIODevice.ReadWrite)
74 | self.outputTextEdit.insertPlainText("{}\n\n".format(command))
75 |
76 | if (self.v2rayProcess.state() == QProcess.NotRunning):
77 | self.outputTextEdit.moveCursor(QTextCursor.End)
78 | self.outputTextEdit.append("\n")
79 | self.outputTextEdit.insertPlainText(
80 | str("{}\n".format(command)))
81 | self.outputTextEdit.insertPlainText(
82 | str(self.translate(
83 | "runV2raycore", "{} Error Code:{}").format(
84 | self.v2rayProcess.errorString(),
85 | self.v2rayProcess.error())))
86 | self.outputTextEdit.moveCursor(QTextCursor.End)
87 |
88 | self.outputTextEdit.textChanged.connect(self.getV2raycoreVersion)
89 |
90 | def killOrphanProcess(self):
91 | openFile = QFileInfo(self.pidFile)
92 |
93 | fileName = openFile.fileName()
94 | if QFile.exists(fileName):
95 | openFile = QFile(fileName)
96 | else:
97 | return
98 | v2rayPID = None
99 |
100 | try:
101 | openFile.open(QIODevice.ReadOnly | QIODevice.Text)
102 | v2rayPID = str(openFile.readAll(), "utf-8")
103 | except Exception:
104 | pass
105 |
106 | try:
107 | os.kill(int(v2rayPID), signal.SIGTERM)
108 | except Exception:
109 | pass
110 |
111 | def oncreatePIDFile(self):
112 | if self.v2rayProcess.state() == QProcess.NotRunning:
113 | return
114 |
115 | outFile = QFileInfo(self.pidFile)
116 | fileName = outFile.fileName()
117 | if QFile.exists(fileName):
118 | QFile.remove(fileName)
119 | outFile = QFile(fileName)
120 |
121 | v2rayPID = str(self.v2rayProcess.processId())
122 | qDebug("process ID is: {}".format(v2rayPID))
123 | try:
124 | outFile.open(QIODevice.WriteOnly | QIODevice.Text)
125 | outFile.write(codecs.encode(v2rayPID, "utf-8"))
126 | except Exception:
127 | pass
128 | outFile.close()
129 |
130 | def getV2raycoreVersion(self):
131 | text = self.outputTextEdit.toPlainText()
132 | version = re.findall("V2Ray v\d\.\d{1,2}", text)
133 | failtostart = re.findall("Failed to start App", text)
134 | if (version):
135 | version = version[0].split(" ")[1]
136 | self.bridgetreasureChest.setV2raycoreVersion(version)
137 | if (failtostart):
138 | self.outputTextEdit.textChanged.disconnect(
139 | self.getV2raycoreVersion)
140 | self.onstop()
141 |
142 | def onstop(self):
143 | if (self.v2rayProcess.state() == QProcess.Running):
144 | self.v2rayProcess.close()
145 | self.v2rayProcess.kill()
146 | self.outputTextEdit.moveCursor(QTextCursor.End)
147 | self.outputTextEdit.append("\n\n")
148 | self.outputTextEdit.insertPlainText(
149 | str(self.translate(
150 | "runV2raycore",
151 | "{} is stop now...").format(self.v2rayPath)))
152 | self.outputTextEdit.insertPlainText(
153 | str(self.translate(
154 | "runV2raycore",
155 | "\n{} is ready to run...").format(self.v2rayPath)))
156 | self.outputTextEdit.moveCursor(QTextCursor.End)
157 |
158 | def setoutputTextEdit(self):
159 | self.outputTextEdit.moveCursor(QTextCursor.End)
160 | self.outputTextEdit.insertPlainText(
161 | str(self.v2rayProcess.readAllStandardOutput(), "utf-8"))
162 | self.outputTextEdit.insertPlainText(
163 | str(self.v2rayProcess.readAllStandardError(), "utf-8"))
164 | self.outputTextEdit.moveCursor(QTextCursor.End)
165 |
166 |
167 | class executeProgramPanel(QWidget):
168 |
169 | def __init__(self):
170 | super().__init__()
171 |
172 | self.start = QPushButton("Start")
173 | self.stop = QPushButton("Stop")
174 | self.outputTextEdit = QTextEdit()
175 | self.outputTextEdit.isReadOnly()
176 |
177 | self.labelComand = QLabel("Comand: ")
178 | self.lineEditComand = QLineEdit()
179 | self.lineEditComand.setText("ping")
180 | self.buttonOpenComand = QPushButton("Open")
181 |
182 | self.labelOption = QLabel("Option: ")
183 | self.lineEditOption = QLineEdit()
184 | self.lineEditOption.setText("127.0.0.1 -t")
185 |
186 | self.buttonGroup = buttonGroup = QButtonGroup()
187 | buttonGroup.addButton(self.start)
188 | buttonGroup.addButton(self.stop)
189 | buttonGroup.addButton(self.buttonOpenComand)
190 |
191 | gridBox = QGridLayout()
192 | gridBox.addWidget(self.labelComand, 0, 0)
193 | gridBox.addWidget(self.lineEditComand, 0, 1, 1, 4)
194 | gridBox.addWidget(self.buttonOpenComand, 0, 5, 1, 1)
195 | gridBox.addWidget(self.labelOption, 1, 0, 1, 1)
196 | gridBox.addWidget(self.lineEditOption, 1, 1, 1, 4)
197 | gridBox.addWidget(self.start, 2, 4)
198 | gridBox.addWidget(self.stop, 2, 5)
199 |
200 | vbox = QVBoxLayout()
201 | vbox.addWidget(self.outputTextEdit)
202 | vbox.addLayout(gridBox)
203 | self.setFixedSize(QSize(600, 460))
204 |
205 | self.setLayout(vbox)
206 |
207 | self.buttonGroup.buttonClicked.connect(self.onbuttonGroupClicked)
208 |
209 | def onbuttonGroupClicked(self, e):
210 | if e.text() == "Start":
211 | exeFile = None
212 | option = None
213 | if (self.lineEditComand.text() != ""):
214 | exeFile = self.lineEditComand.text()
215 | if (self.lineEditOption.text() != ""):
216 | option = self.lineEditOption.text()
217 |
218 | self.runV2ray = runV2raycore(outputTextEdit=self.outputTextEdit,
219 | v2rayPath=exeFile,
220 | v2rayOption=option)
221 | self.runV2ray.start.emit()
222 |
223 | elif e.text() == "Open":
224 | options = QFileDialog.Options()
225 | filePath, _ = QFileDialog.getOpenFileName(
226 | self,
227 | "Open V2ray execute File",
228 | "",
229 | "All File (*)",
230 | options=options)
231 | if (filePath):
232 | self.lineEditOption.clear()
233 | self.lineEditComand.clear()
234 | self.lineEditComand.setText(filePath)
235 |
236 | elif e.text() == "Stop":
237 | self.runV2ray.stop.emit()
238 |
239 |
240 | if __name__ == "__main__":
241 | from PyQt5.QtWidgets import QApplication
242 | app = QApplication(sys.argv)
243 | ex = executeProgramPanel()
244 | ex.show()
245 | sys.exit(app.exec_())
246 |
--------------------------------------------------------------------------------
/src/bridgehouse/icons/rocket.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/v2ray/V2Ray-shell_alpha/df72d9cc8c4dfb0fa7215580bdd16f76edcf7fbe/src/bridgehouse/icons/rocket.psd
--------------------------------------------------------------------------------
/src/bridgehouse/icons/start.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/v2ray/V2Ray-shell_alpha/df72d9cc8c4dfb0fa7215580bdd16f76edcf7fbe/src/bridgehouse/icons/start.ico
--------------------------------------------------------------------------------
/src/bridgehouse/icons/start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/v2ray/V2Ray-shell_alpha/df72d9cc8c4dfb0fa7215580bdd16f76edcf7fbe/src/bridgehouse/icons/start.png
--------------------------------------------------------------------------------
/src/bridgehouse/icons/stop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/v2ray/V2Ray-shell_alpha/df72d9cc8c4dfb0fa7215580bdd16f76edcf7fbe/src/bridgehouse/icons/stop.png
--------------------------------------------------------------------------------
/src/bridgehouse/v2ray-shell.spec:
--------------------------------------------------------------------------------
1 | # -*- mode: python -*-
2 |
3 | block_cipher = None
4 |
5 |
6 | a = Analysis(['bridge.py'],
7 | pathex=['./bridgehouse'],
8 | binaries=[],
9 | datas=[],
10 | hiddenimports=[],
11 | hookspath=[],
12 | runtime_hooks=[],
13 | excludes=[],
14 | win_no_prefer_redirects=False,
15 | win_private_assemblies=False,
16 | cipher=block_cipher)
17 | icons = Tree('icons', 'icons')
18 | pyz = PYZ(a.pure, a.zipped_data,
19 | cipher=block_cipher)
20 | exe = EXE(pyz,
21 | a.scripts,
22 | a.binaries,
23 | a.zipfiles,
24 | a.datas,
25 | icons,
26 | name='v2ray-shell',
27 | debug=False,
28 | strip=False,
29 | upx=True,
30 | runtime_tmpdir=None,
31 | console=False,
32 | icon="./icons/start.ico")
33 |
--------------------------------------------------------------------------------
/translations/en_US.qm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/v2ray/V2Ray-shell_alpha/df72d9cc8c4dfb0fa7215580bdd16f76edcf7fbe/translations/en_US.qm
--------------------------------------------------------------------------------
/translations/tr.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | from PyQt5 import pylupdate_main as pylupdate
3 | import sys
4 |
5 | profile = "../v2rayshell.pro"
6 | sys.argv.append(profile)
7 | pylupdate.main()
--------------------------------------------------------------------------------
/translations/zh_CN.qm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/v2ray/V2Ray-shell_alpha/df72d9cc8c4dfb0fa7215580bdd16f76edcf7fbe/translations/zh_CN.qm
--------------------------------------------------------------------------------
/v2ray-shell.pyw:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from tkinter import Tk, BOTH, Text, END
4 | from tkinter.ttk import Frame, Button, Label
5 | from pathlib import Path
6 | import sys, subprocess
7 |
8 | class runV2Rayshell(Frame):
9 | def __init__(self, root):
10 | super(runV2Rayshell, self).__init__()
11 | self.root = root
12 | self.pyqt5 = False
13 | self.check_PyQt5_installed()
14 | self.pip_source = u"""[global]
15 | index-url = https://pypi.douban.com/simple/
16 | trusted-host = pypi.douban.com
17 | """
18 | if (not self.pyqt5):
19 | self.ui()
20 | else:
21 | self.ui()
22 | self.root.withdraw()
23 | self.run_current_v2rayshell()
24 |
25 | def run_current_v2rayshell(self):
26 | dir = "/src/bridgehouse/"
27 | path = Path().cwd()
28 | src_path ="{}{}".format(path, dir)
29 | if Path(src_path).is_dir():
30 | bridgehouse_path = src_path.split("/")
31 | sys.path.append("/".join(bridgehouse_path[:-2]))
32 | try:
33 | from bridgehouse import bridge
34 | except Exception as e:
35 | self.root.deiconify()
36 | self.text.delete(1.0, END)
37 | self.text.insert(2.0, e)
38 | else:
39 | #os.system('"{}{}"'.format(src_path, "bridge.py"))
40 | if sys.platform == 'win32':
41 | subprocess.call('pythonw "{}{}"'.format(src_path, "bridge.py"), shell=True)
42 | else:
43 | subprocess.call('"{}{}"'.format(src_path, "bridge.py"), shell = True)
44 | self.root.destroy()
45 |
46 | def check_PyQt5_installed(self):
47 | try: import PyQt5
48 | except Exception: self.pyqt5 = False
49 | else: self.pyqt5 = True
50 |
51 | def set_pip_source(self):
52 | name = "pip.ini"
53 | home_path = "{}/pip".format(str(Path.home()))
54 | file_path = "{}/{}".format(home_path, name)
55 | if not Path(home_path).is_dir():
56 | Path(home_path).mkdir()
57 |
58 | if Path(home_path).is_dir():
59 | try:
60 | with open(file_path, "w", encoding="utf8") as f:
61 | f.write(self.pip_source)
62 | except Exception:
63 | self.text.delete(1.0, END)
64 | self.text.insert(
65 | 2.0,"install {} failed. you can do by manual...\n{}".format(
66 | filePath, self.pip_source))
67 | else:
68 | self.text.delete(1.0, END)
69 | self.text.insert(
70 | 2.0,"{} installed successfully...\n{}".format(
71 | file_path, self.pip_source))
72 |
73 | def install_PyQt5(self):
74 | test = subprocess.Popen(
75 | ["pip3","install","PyQt5"],
76 | stdout=subprocess.PIPE)
77 | output = test.communicate()[0]
78 | self.text.delete(1.0, END)
79 | self.text.insert(END, output.decode("utf-8"))
80 |
81 | def ui(self):
82 | label_no_pyqt5 = Label(self, text = "There is no PyQt5 install.")
83 | label_pip_source = Label(
84 | self,
85 | text = "You can click on the button below\nto speed up the installation of pypi source")
86 | label_install_pyqt5 = Label(
87 | self, text = "Then as a ROOT (OR ADMINISTRATOR) install PyQt5, \nlast restart this script.")
88 | butonn_install_source = Button(
89 | self, text = "install pypi source",
90 | command = self.set_pip_source)
91 |
92 | buton_install_PyQt5 = Button(
93 | self,
94 | text = "install PyQt5",
95 | command = self.install_PyQt5)
96 |
97 | self.text = Text(self)
98 |
99 | label_empty = Label(self)
100 | label_empty2 = Label(self)
101 | label_empty3 = Label(self)
102 |
103 | label_no_pyqt5.pack()
104 | label_pip_source.pack()
105 | label_install_pyqt5.pack()
106 | label_empty.pack()
107 | butonn_install_source.pack()
108 | label_empty2.pack()
109 | buton_install_PyQt5.pack()
110 | self.text.pack()
111 | label_empty3.pack()
112 | self.master.title("start run v2ray-shell")
113 | self.pack(fill = BOTH, expand = 1)
114 | self.center_window()
115 |
116 | def center_window(self):
117 | w = 620; h = 460
118 | sw = self.master.winfo_screenwidth()
119 | sh = self.master.winfo_screenheight()
120 |
121 | x = (sw -w)/2
122 | y = (sh -h)/2
123 | self.master.geometry("{}x{}+{}+{}".format(w, h, int(x), int(y)))
124 |
125 | if __name__ == "__main__":
126 | root = Tk()
127 | runV2Rayshell(root)
128 | root.mainloop()
--------------------------------------------------------------------------------
/v2rayshell.pro:
--------------------------------------------------------------------------------
1 | SOURCES += ./src/bridgehouse/bridge.py \
2 | ./src/bridgehouse/extension/bridgePreference.py \
3 | ./src/bridgehouse/extension/bridgetreasureChest.py \
4 | ./src/bridgehouse/extension/proxyTest.py \
5 | ./src/bridgehouse/extension/runV2raycore.py \
6 | ./src/bridgehouse/extension/updatePanel.py \
7 | ./src/bridgehouse/extension/bugReport.py \
8 | ./src/bridgehouse/editMap/apiTAB.py \
9 | ./src/bridgehouse/editMap/cafeteriaTAB.py \
10 | ./src/bridgehouse/editMap/dnsTAB.py \
11 | ./src/bridgehouse/editMap/logTAB.py \
12 | ./src/bridgehouse/editMap/nauticalChartPanel.py \
13 | ./src/bridgehouse/editMap/policyTAB.py \
14 | ./src/bridgehouse/editMap/routingTAB.py \
15 | ./src/bridgehouse/editMap/statsTAB.py \
16 | ./src/bridgehouse/editMap/transportTAB.py \
17 | ./src/bridgehouse/editMap/inbound/dokodemodoorPanel.py \
18 | ./src/bridgehouse/editMap/inbound/httpPanel.py \
19 | ./src/bridgehouse/editMap/inbound/shadowsocksPanel.py \
20 | ./src/bridgehouse/editMap/inbound/socksPanel.py \
21 | ./src/bridgehouse/editMap/inbound/vmessPanel.py \
22 | ./src/bridgehouse/editMap/inbound/mtPanel.py \
23 | ./src/bridgehouse/editMap/outbound/blackholePanel.py \
24 | ./src/bridgehouse/editMap/outbound/freedomPanel.py \
25 | ./src/bridgehouse/editMap/outbound/shadowsocksPanel.py \
26 | ./src/bridgehouse/editMap/outbound/socksPanel.py \
27 | ./src/bridgehouse/editMap/outbound/vmessPanel.py \
28 | ./src/bridgehouse/editMap/port/inboundPanel.py \
29 | ./src/bridgehouse/editMap/port/openV2rayJSONFile.py \
30 | ./src/bridgehouse/editMap/port/outboundPanel.py \
31 | ./src/bridgehouse/editMap/port/treasureChest.py \
32 | ./src/bridgehouse/editMap/port/updateListSignal.py \
33 | ./src/bridgehouse/editMap/router/geoSiteEditorPanel.py \
34 | ./src/bridgehouse/editMap/transport/certificatesPanel.py \
35 | ./src/bridgehouse/editMap/transport/http2Panel.py \
36 | ./src/bridgehouse/editMap/transport/mkcpPanel.py \
37 | ./src/bridgehouse/editMap/transport/muxPanel.py \
38 | ./src/bridgehouse/editMap/transport/tcpPanel.py \
39 | ./src/bridgehouse/editMap/transport/dsPanel.py \
40 | ./src/bridgehouse/editMap/transport/transportPanel.py \
41 | ./src/bridgehouse/editMap/transport/wsPanel.py
42 |
43 | TRANSLATIONS += ./translations/zh_CN.ts \
44 | ./translations/en_US.ts
45 |
46 | CODECFORSRC = UTF-8
47 |
--------------------------------------------------------------------------------