From 48c2567c5fc9da3631cf5f2fca3451e48ea4f2d2 Mon Sep 17 00:00:00 2001
From: "bt.cn" <31841517+aaPanel@users.noreply.github.com>
Date: Mon, 17 Jun 2019 19:02:40 +0800
Subject: [PATCH 01/79] Create README.md
---
README.md | 1 +
1 file changed, 1 insertion(+)
create mode 100644 README.md
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..2aec86dd
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+# 宝塔Linux面板
From 998b67f553b4ea28e3af2a9b4ed019229f69532c Mon Sep 17 00:00:00 2001
From: "bt.cn" <31841517+aaPanel@users.noreply.github.com>
Date: Mon, 17 Jun 2019 19:07:17 +0800
Subject: [PATCH 02/79] Update README.md
---
README.md | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 2aec86dd..dad65f9c 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,4 @@
-# 宝塔Linux面板
+# 使用手册:http://docs.bt.cn
+# 论坛地址:https://www.bt.cn/bbs
+# 反馈建议: https://www.bt.cn/bbs/forum-43-1.html
+# Bug提交:https://www.bt.cn/bbs/forum-39-1.html
From 41419416dc24aea8b76600ce7cbfae1798d39922 Mon Sep 17 00:00:00 2001
From: "bt.cn" <31841517+aaPanel@users.noreply.github.com>
Date: Mon, 17 Jun 2019 19:08:15 +0800
Subject: [PATCH 03/79] Update README.md
---
README.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index dad65f9c..a0779037 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# 使用手册:http://docs.bt.cn
-# 论坛地址:https://www.bt.cn/bbs
-# 反馈建议: https://www.bt.cn/bbs/forum-43-1.html
-# Bug提交:https://www.bt.cn/bbs/forum-39-1.html
+使用手册:http://docs.bt.cn
+论坛地址:https://www.bt.cn/bbs
+反馈建议: https://www.bt.cn/bbs/forum-43-1.html
+Bug提交:https://www.bt.cn/bbs/forum-39-1.html
From 7b0effa97493415d533453a172a983e3b7642a6c Mon Sep 17 00:00:00 2001
From: "bt.cn" <31841517+aaPanel@users.noreply.github.com>
Date: Mon, 17 Jun 2019 19:09:20 +0800
Subject: [PATCH 04/79] Update README.md
---
README.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index a0779037..6f0f9219 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-使用手册:http://docs.bt.cn
-论坛地址:https://www.bt.cn/bbs
-反馈建议: https://www.bt.cn/bbs/forum-43-1.html
-Bug提交:https://www.bt.cn/bbs/forum-39-1.html
+#####使用手册:http://docs.bt.cn
+#####论坛地址:https://www.bt.cn/bbs
+#####反馈建议: https://www.bt.cn/bbs/forum-43-1.html
+#####Bug提交:https://www.bt.cn/bbs/forum-39-1.html
From f56d7f292ed6b2503d1bfa1568dc94f7cc3c4f64 Mon Sep 17 00:00:00 2001
From: "bt.cn" <31841517+aaPanel@users.noreply.github.com>
Date: Mon, 17 Jun 2019 19:09:34 +0800
Subject: [PATCH 05/79] Update README.md
---
README.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 6f0f9219..3008f872 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-#####使用手册:http://docs.bt.cn
-#####论坛地址:https://www.bt.cn/bbs
-#####反馈建议: https://www.bt.cn/bbs/forum-43-1.html
-#####Bug提交:https://www.bt.cn/bbs/forum-39-1.html
+##### 使用手册:http://docs.bt.cn
+##### 论坛地址:https://www.bt.cn/bbs
+##### 反馈建议: https://www.bt.cn/bbs/forum-43-1.html
+##### Bug提交:https://www.bt.cn/bbs/forum-39-1.html
From 5fef838425d919e5fa19b2ada2060087fe47e01e Mon Sep 17 00:00:00 2001
From: "bt.cn" <31841517+aaPanel@users.noreply.github.com>
Date: Mon, 17 Jun 2019 19:11:37 +0800
Subject: [PATCH 06/79] Create license.txt
---
license.txt | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
create mode 100644 license.txt
diff --git a/license.txt b/license.txt
new file mode 100644
index 00000000..3b0951d6
--- /dev/null
+++ b/license.txt
@@ -0,0 +1,54 @@
+宝塔开源许可协议
+
+重要须知:在此特别提醒用户认真阅读、充分理解本协议,用户应认真阅读、充分理解本协议中各条款,包括免除或限制的免责条款以及对用户的权利限制条款。用户需审慎阅读并选择接受或不接受本协议,除非用户接受本协议所有条款,否则用户无权安装或使用本软件及相关服务。用户的安装、使用、登录等行为将视为对本协议的接受,并同意接受本协议各项条款的约束。
+
+名词定义:
+用户:通过宝塔授权获得宝塔面板及使用宝塔相关服务的自然人、法人及其他组织
+宝塔:宝塔面板(主体: 东莞市百塔网络科技有限公司)
+用户许可定义:用户在基于明显的用途说明后主动安装、使用、注册、管理软件,以及同意宝塔提供相关服务所订立的协议
+
+一、宝塔需尊守的约定
+1.1 除付费插件外,确保所有代码用户皆可阅读。
+1.2 确保用户在完成所有环境部署后,在不依赖宝塔云端支持下也可永久运行。
+1.3 除付费插件外,禁止对源代码进行加密和混淆。
+1.4 禁止不经用户许可的情况下以任何方式自动安装加密代码。
+1.5 禁止不经用户许可的情况下以任何方式收集用户数据。
+1.6 禁止不经用户许可的情况下以任何方式远程控制用户面板。
+1.7 禁止在用户面板上插入与宝塔无关的广告。
+1.8 即日起,禁止将宝塔官方提供的免费功能改为付费功能。
+
+二、用户需遵守的约定
+2.1 以自用为目的,可将宝塔用于盈利或非盈利项目上,且不受任何限制。
+2.2 以自用为目的,在保留版权标识的前提下可任意修改程序源码,但不得公开发行。
+2.3 禁止以任何方式破坏宝塔的商业授权机制(包括但不限于收集宝塔源码后经营与宝塔同类型、同性质服务等)。
+2.4 用户禁止利用宝塔发表、传送、传播、储存违反国家法律、危害国家安全、社会稳定、公序良俗的内容,或任何不当的、侮辱诽谤的、淫秽的、暴力的及任何违反国家法律法规政策的内容。
+2.5 用户禁止利用宝塔制作、发布、传播用户窃取相关或其他软件及他人专属信息、财产的软件。
+
+三、API使用约定
+3.1 宝塔欢迎并感谢您为该软件开发基于API的各种应用,且可自行免费或收费发布。
+3.2 用户基于宝塔API机制开发的应用,不得包含有破坏或修改宝塔代码。
+
+四、无改动发布或集成宝塔
+4.1 宝塔欢迎并感谢您将宝塔发布在您的个人网站、企业官网或者其他的第三方网站。
+4.2 宝塔欢迎并感谢您将宝塔集成在其他系统中一起发布,包括云服务镜像、操作系统发行版等。
+4.3 用户在发布或者集成宝塔的时候,不得对宝塔源码做任何改动。
+
+五、知识产权声明
+宝塔是由东莞市百塔网络科技有限公司开发,宝塔的知识产权以及与宝塔相关的所有信息内容,包括但不限于:文字、图形、界面设计、版面框架、有关数据均受中华人民共和国相关知识产权法律法规的保护,除涉及第三方授权的内容外,宝塔公司享有上述知识产权。
+
+六、免责声明
+6.1 用户出于自愿而使用宝塔,您必须了解使用本软件的风险,宝塔不作任何类型的担保,不论是明示的、默示的,包括但不限于用户在任何情况下因使用或不能使用宝塔所产生的直接、间接、偶然、特殊及后续的损害及风险,百塔公司不承担任何责任。
+6.2 用户清楚互联网软件的特殊性,宝塔与大多数互联网软件一样,受包括但不限于用户原因、网络服务质量、社会环境等因素的影响,可能收到各种安全问题的侵扰,如用户下载安装的其他软件或访问的其他网站中含有“木马”等病毒,威胁到用户的计算机信息和数据的安全,继而影响宝塔的正常使用等,用户应加强信息安全及使用资料的保护,以免遭受损失
+6.3 宝塔界面中“第三方应用”是宝塔获得了第三方合法授权的,如因用户使用第三方软件或技术引发的任何纠纷,由第三方负责解决,宝塔不对第三方软件或技术提供服务,若用户需要获得支持,请与该第三方联系。
+6.4 用户因使用宝塔违反国家法律法规的,
+
+七、授权例外
+7.1 如果上述条款无法满足您使用该软件的要求,可联系宝塔签署额外的合同以获得更灵活的授权许可。
+
+八、合同终止
+8.1 如果用户违反了本协议的任一条款,本授权协议将自动终止,用户行为损害宝塔或其他任意第三方权利的,宝塔保留通过法律手段追究责任的权利。
+
+九、其他条款
+9.1 本协议约定的任何条款部分或完全无效的,不影响其他条款的效力。
+9.2 协议的解释、效力及纠纷的解决使用中华人民共和国法律,若用户和宝塔发生任何纠纷或争议,首先应当友好协商解决,协商不成的,用户完全同意将该纠纷或争议提交至宝塔所在地即东莞市有管辖权的法院管辖。
+9.3 本协议宝塔保留一切解释权利
From 7f036c4969f66ff621819ee454bea667181aa508 Mon Sep 17 00:00:00 2001
From: "bt.cn" <31841517+aaPanel@users.noreply.github.com>
Date: Mon, 17 Jun 2019 19:33:36 +0800
Subject: [PATCH 07/79] Update README.md
---
README.md | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/README.md b/README.md
index 3008f872..3fadde64 100644
--- a/README.md
+++ b/README.md
@@ -2,3 +2,13 @@
##### 论坛地址:https://www.bt.cn/bbs
##### 反馈建议: https://www.bt.cn/bbs/forum-43-1.html
##### Bug提交:https://www.bt.cn/bbs/forum-39-1.html
+
+##### Centos安装命令:
+'''bash
+yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh
+'''
+
+##### Ubuntu/Debian安装命令:
+'''bash
+wget -O install.sh http://download.bt.cn/install/install-ubuntu_6.0.sh && sudo bash install.sh
+'''
From 6d2414ba1930a7537d7f3ea14a03aa403e951f01 Mon Sep 17 00:00:00 2001
From: "bt.cn" <31841517+aaPanel@users.noreply.github.com>
Date: Mon, 17 Jun 2019 19:34:08 +0800
Subject: [PATCH 08/79] Update README.md
---
README.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 3fadde64..25cf3603 100644
--- a/README.md
+++ b/README.md
@@ -4,11 +4,11 @@
##### Bug提交:https://www.bt.cn/bbs/forum-39-1.html
##### Centos安装命令:
-'''bash
+```bash
yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh
-'''
+```
##### Ubuntu/Debian安装命令:
-'''bash
+```bash
wget -O install.sh http://download.bt.cn/install/install-ubuntu_6.0.sh && sudo bash install.sh
-'''
+```
From 5c2e0d65f4a776ad6ff3b498837adfa63a96b5ef Mon Sep 17 00:00:00 2001
From: "bt.cn" <31841517+aaPanel@users.noreply.github.com>
Date: Mon, 17 Jun 2019 19:34:47 +0800
Subject: [PATCH 09/79] Update README.md
---
README.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 25cf3603..d18323b4 100644
--- a/README.md
+++ b/README.md
@@ -3,12 +3,12 @@
##### 反馈建议: https://www.bt.cn/bbs/forum-43-1.html
##### Bug提交:https://www.bt.cn/bbs/forum-39-1.html
-##### Centos安装命令:
+#### 安装命令:
+##### Centos
```bash
yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh
```
-
-##### Ubuntu/Debian安装命令:
+##### Ubuntu/Debian
```bash
wget -O install.sh http://download.bt.cn/install/install-ubuntu_6.0.sh && sudo bash install.sh
```
From 4beb22721c4ff2585c797490d5b6a0e6e6e8d144 Mon Sep 17 00:00:00 2001
From: "bt.cn" <287962566@qq.com>
Date: Tue, 18 Jun 2019 10:41:37 +0800
Subject: [PATCH 10/79] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=96=87=E4=BB=B6?=
=?UTF-8?q?=E6=90=9C=E7=B4=A2=E6=97=B6=E7=9A=84=E8=B7=AF=E5=BE=84=E6=9E=84?=
=?UTF-8?q?=E9=80=A0=E9=97=AE=E9=A2=98=EF=BC=8C=E5=A2=9E=E5=8A=A0=E5=90=AF?=
=?UTF-8?q?=E5=8A=A8=E9=9D=A2=E6=9D=BF=E6=97=B6=E5=81=9A=E9=9D=A2=E6=9D=BF?=
=?UTF-8?q?=E5=85=B3=E9=94=AE=E7=9B=AE=E5=BD=95=E7=9A=84=E6=9D=83=E9=99=90?=
=?UTF-8?q?=E5=A4=84=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
license.txt | 54 -----------------------------------------------------
1 file changed, 54 deletions(-)
diff --git a/license.txt b/license.txt
index 3b0951d6..e69de29b 100644
--- a/license.txt
+++ b/license.txt
@@ -1,54 +0,0 @@
-宝塔开源许可协议
-
-重要须知:在此特别提醒用户认真阅读、充分理解本协议,用户应认真阅读、充分理解本协议中各条款,包括免除或限制的免责条款以及对用户的权利限制条款。用户需审慎阅读并选择接受或不接受本协议,除非用户接受本协议所有条款,否则用户无权安装或使用本软件及相关服务。用户的安装、使用、登录等行为将视为对本协议的接受,并同意接受本协议各项条款的约束。
-
-名词定义:
-用户:通过宝塔授权获得宝塔面板及使用宝塔相关服务的自然人、法人及其他组织
-宝塔:宝塔面板(主体: 东莞市百塔网络科技有限公司)
-用户许可定义:用户在基于明显的用途说明后主动安装、使用、注册、管理软件,以及同意宝塔提供相关服务所订立的协议
-
-一、宝塔需尊守的约定
-1.1 除付费插件外,确保所有代码用户皆可阅读。
-1.2 确保用户在完成所有环境部署后,在不依赖宝塔云端支持下也可永久运行。
-1.3 除付费插件外,禁止对源代码进行加密和混淆。
-1.4 禁止不经用户许可的情况下以任何方式自动安装加密代码。
-1.5 禁止不经用户许可的情况下以任何方式收集用户数据。
-1.6 禁止不经用户许可的情况下以任何方式远程控制用户面板。
-1.7 禁止在用户面板上插入与宝塔无关的广告。
-1.8 即日起,禁止将宝塔官方提供的免费功能改为付费功能。
-
-二、用户需遵守的约定
-2.1 以自用为目的,可将宝塔用于盈利或非盈利项目上,且不受任何限制。
-2.2 以自用为目的,在保留版权标识的前提下可任意修改程序源码,但不得公开发行。
-2.3 禁止以任何方式破坏宝塔的商业授权机制(包括但不限于收集宝塔源码后经营与宝塔同类型、同性质服务等)。
-2.4 用户禁止利用宝塔发表、传送、传播、储存违反国家法律、危害国家安全、社会稳定、公序良俗的内容,或任何不当的、侮辱诽谤的、淫秽的、暴力的及任何违反国家法律法规政策的内容。
-2.5 用户禁止利用宝塔制作、发布、传播用户窃取相关或其他软件及他人专属信息、财产的软件。
-
-三、API使用约定
-3.1 宝塔欢迎并感谢您为该软件开发基于API的各种应用,且可自行免费或收费发布。
-3.2 用户基于宝塔API机制开发的应用,不得包含有破坏或修改宝塔代码。
-
-四、无改动发布或集成宝塔
-4.1 宝塔欢迎并感谢您将宝塔发布在您的个人网站、企业官网或者其他的第三方网站。
-4.2 宝塔欢迎并感谢您将宝塔集成在其他系统中一起发布,包括云服务镜像、操作系统发行版等。
-4.3 用户在发布或者集成宝塔的时候,不得对宝塔源码做任何改动。
-
-五、知识产权声明
-宝塔是由东莞市百塔网络科技有限公司开发,宝塔的知识产权以及与宝塔相关的所有信息内容,包括但不限于:文字、图形、界面设计、版面框架、有关数据均受中华人民共和国相关知识产权法律法规的保护,除涉及第三方授权的内容外,宝塔公司享有上述知识产权。
-
-六、免责声明
-6.1 用户出于自愿而使用宝塔,您必须了解使用本软件的风险,宝塔不作任何类型的担保,不论是明示的、默示的,包括但不限于用户在任何情况下因使用或不能使用宝塔所产生的直接、间接、偶然、特殊及后续的损害及风险,百塔公司不承担任何责任。
-6.2 用户清楚互联网软件的特殊性,宝塔与大多数互联网软件一样,受包括但不限于用户原因、网络服务质量、社会环境等因素的影响,可能收到各种安全问题的侵扰,如用户下载安装的其他软件或访问的其他网站中含有“木马”等病毒,威胁到用户的计算机信息和数据的安全,继而影响宝塔的正常使用等,用户应加强信息安全及使用资料的保护,以免遭受损失
-6.3 宝塔界面中“第三方应用”是宝塔获得了第三方合法授权的,如因用户使用第三方软件或技术引发的任何纠纷,由第三方负责解决,宝塔不对第三方软件或技术提供服务,若用户需要获得支持,请与该第三方联系。
-6.4 用户因使用宝塔违反国家法律法规的,
-
-七、授权例外
-7.1 如果上述条款无法满足您使用该软件的要求,可联系宝塔签署额外的合同以获得更灵活的授权许可。
-
-八、合同终止
-8.1 如果用户违反了本协议的任一条款,本授权协议将自动终止,用户行为损害宝塔或其他任意第三方权利的,宝塔保留通过法律手段追究责任的权利。
-
-九、其他条款
-9.1 本协议约定的任何条款部分或完全无效的,不影响其他条款的效力。
-9.2 协议的解释、效力及纠纷的解决使用中华人民共和国法律,若用户和宝塔发生任何纠纷或争议,首先应当友好协商解决,协商不成的,用户完全同意将该纠纷或争议提交至宝塔所在地即东莞市有管辖权的法院管辖。
-9.3 本协议宝塔保留一切解释权利
From 1409d0822bbdb41cdc28f3ec357f62dad65e77ce Mon Sep 17 00:00:00 2001
From: "bt.cn" <287962566@qq.com>
Date: Tue, 18 Jun 2019 10:50:21 +0800
Subject: [PATCH 11/79] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=96=87=E4=BB=B6?=
=?UTF-8?q?=E6=90=9C=E7=B4=A2=E6=97=B6=E6=B2=A1=E6=9C=89=E8=BF=87=E5=BA=A6?=
=?UTF-8?q?=E6=8F=90=E7=A4=BA=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C=E4=BC=98?=
=?UTF-8?q?=E5=8C=96=E6=96=87=E4=BB=B6=E5=88=97=E8=A1=A8=E8=B7=AF=E5=BE=84?=
=?UTF-8?q?=E6=9E=84=E9=80=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 4 ++-
BTPanel/static/js/files.js | 4 +--
class/common.py | 2 +-
class/files.py | 5 ++--
class/jobs.py | 7 +++++
license.txt | 54 ++++++++++++++++++++++++++++++++++++++
6 files changed, 70 insertions(+), 6 deletions(-)
diff --git a/.gitignore b/.gitignore
index 76f86cc2..913054b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -266,4 +266,6 @@ code_v.py
demo.py
tocc.sh
*.user
-*.pubxml
\ No newline at end of file
+*.pubxml
+*.pyproj
+*.sln
\ No newline at end of file
diff --git a/BTPanel/static/js/files.js b/BTPanel/static/js/files.js
index 1271069d..0abb23f6 100644
--- a/BTPanel/static/js/files.js
+++ b/BTPanel/static/js/files.js
@@ -361,12 +361,12 @@ function GetFiles(Path,sort) {
data['path'] = Path;
- if (search) {
+ if (searchV) {
var loadT = layer.msg('正在搜索,请稍候...', { icon: 16, time: 0, shade: [0.3, '#000']});
}
var totalSize = 0;
$.post('/files?action=GetDir&tojs=GetFiles&p=' + p + '&showRow=' + showRow + search, data, function(rdata) {
- if (search) layer.close(loadT);
+ if (searchV) layer.close(loadT);
if (rdata.status === false) {
layer.msg(rdata.msg, { icon: 2 });
return;
diff --git a/class/common.py b/class/common.py
index 42fb6f19..d38b1a8e 100644
--- a/class/common.py
+++ b/class/common.py
@@ -27,7 +27,7 @@ def init(self):
if ua:
ua = ua.lower();
if ua.find('spider') != -1 or ua.find('bot') != -1: return redirect('https://www.baidu.com');
- g.version = '6.9.21'
+ g.version = '6.9.5'
g.title = public.GetConfigValue('title')
g.uri = request.path
session['version'] = g.version;
diff --git a/class/files.py b/class/files.py
index 40f0c45a..752133d9 100644
--- a/class/files.py
+++ b/class/files.py
@@ -282,7 +282,7 @@ def __format_stat(self,filename,path):
stat = self.__get_stat(filename,path)
if not stat: return None
tmp_stat = stat.split(';')
- file_info = {'name': self.xssencode(tmp_stat[0]),'size':int(tmp_stat[1]),'mtime':int(tmp_stat[2]),'accept':int(tmp_stat[3]),'user':tmp_stat[4],'link':tmp_stat[5]}
+ file_info = {'name': self.xssencode(tmp_stat[0].replace('/','')),'size':int(tmp_stat[1]),'mtime':int(tmp_stat[2]),'accept':int(tmp_stat[3]),'user':tmp_stat[4],'link':tmp_stat[5]}
return file_info
except: return None
@@ -331,7 +331,8 @@ def __get_stat(self,filename,path = None):
size = str(stat.st_size)
link = '';
if os.path.islink(filename): link = ' -> ' + os.readlink(filename)
- if path:filename = filename.replace((path + '/').replace('//','/'),'')
+ tmp_path = (path + '/').replace('//','/')
+ if path and tmp_path != '/':filename = filename.replace(tmp_path,'')
return filename + ';' + size + ';' + mtime+ ';' +accept+ ';' +user+ ';' +link
diff --git a/class/jobs.py b/class/jobs.py
index 19827ab8..37d8ebaa 100644
--- a/class/jobs.py
+++ b/class/jobs.py
@@ -55,6 +55,13 @@ def control_init():
p_file = 'class/plugin2.so'
if os.path.exists(p_file): public.ExecShell("rm -f class/*.so")
+ public.ExecShell("chmod -R 600 /www/server/panel/data")
+ public.ExecShell("chmod -R 600 /www/server/panel/config")
+ public.ExecShell("chmod -R 700 /www/server/cron")
+ public.ExecShell("chmod -R 600 /www/server/cron/*.log")
+ public.ExecShell("chown -R root:root /www/server/panel/data")
+ public.ExecShell("chown -R root:root /www/server/panel/config")
+
clean_session()
diff --git a/license.txt b/license.txt
index e69de29b..3f3f6689 100644
--- a/license.txt
+++ b/license.txt
@@ -0,0 +1,54 @@
+宝塔开源许可协议
+
+重要须知:在此特别提醒用户认真阅读、充分理解本协议,用户应认真阅读、充分理解本协议中各条款,包括免除或限制的免责条款以及对用户的权利限制条款。用户需审慎阅读并选择接受或不接受本协议,除非用户接受本协议所有条款,否则用户无权安装或使用本软件及相关服务。用户的安装、使用、登录等行为将视为对本协议的接受,并同意接受本协议各项条款的约束。
+
+名词定义:
+用户:通过宝塔授权获得宝塔面板及使用宝塔相关服务的自然人、法人及其他组织
+宝塔:宝塔面板(主体: 东莞市百塔网络科技有限公司)
+用户许可定义:用户在基于明显的用途说明后主动安装、使用、注册、管理软件,以及同意宝塔提供相关服务所订立的协议
+
+一、宝塔需尊守的约定
+1.1 除付费插件外,确保所有代码用户皆可阅读。
+1.2 确保用户在完成所有环境部署后,在不依赖宝塔云端支持下也可永久运行。
+1.3 除付费插件外,禁止对源代码进行加密和混淆。
+1.4 禁止不经用户许可的情况下以任何方式自动安装加密代码。
+1.5 禁止不经用户许可的情况下以任何方式收集用户数据。
+1.6 禁止不经用户许可的情况下以任何方式远程控制用户面板。
+1.7 禁止在用户面板上插入与宝塔无关的广告。
+1.8 即日起,禁止将宝塔官方提供的免费功能改为付费功能。
+
+二、用户需遵守的约定
+2.1 以自用为目的,可将宝塔用于盈利或非盈利项目上,且不受任何限制。
+2.2 以自用为目的,在保留版权标识的前提下可任意修改程序源码,但不得公开发行。
+2.3 禁止以任何方式破坏宝塔的商业授权机制(包括但不限于收集宝塔源码后经营与宝塔同类型、同性质服务等)。
+2.4 用户禁止利用宝塔发表、传送、传播、储存违反国家法律、危害国家安全、社会稳定、公序良俗的内容,或任何不当的、侮辱诽谤的、淫秽的、暴力的及任何违反国家法律法规政策的内容。
+2.5 用户禁止利用宝塔制作、发布、传播用户窃取相关或其他软件及他人专属信息、财产的软件。
+
+三、API使用约定
+3.1 宝塔欢迎并感谢您为该软件开发基于API的各种应用,且可自行免费或收费发布。
+3.2 用户基于宝塔API机制开发的应用,不得包含有破坏或修改宝塔代码。
+
+四、无改动发布或集成宝塔
+4.1 宝塔欢迎并感谢您将宝塔发布在您的个人网站、企业官网或者其他的第三方网站。
+4.2 宝塔欢迎并感谢您将宝塔集成在其他系统中一起发布,包括云服务镜像、操作系统发行版等。
+4.3 用户在发布或者集成宝塔的时候,不得对宝塔源码做任何改动。
+
+五、知识产权声明
+宝塔是由东莞市百塔网络科技有限公司开发,宝塔的知识产权以及与宝塔相关的所有信息内容,包括但不限于:文字、图形、界面设计、版面框架、有关数据均受中华人民共和国相关知识产权法律法规的保护,除涉及第三方授权的内容外,宝塔公司享有上述知识产权。
+
+六、免责声明
+6.1 用户出于自愿而使用宝塔,您必须了解使用本软件的风险,宝塔不作任何类型的担保,不论是明示的、默示的,包括但不限于用户在任何情况下因使用或不能使用宝塔所产生的直接、间接、偶然、特殊及后续的损害及风险,百塔公司不承担任何责任。
+6.2 用户清楚互联网软件的特殊性,宝塔与大多数互联网软件一样,受包括但不限于用户原因、网络服务质量、社会环境等因素的影响,可能收到各种安全问题的侵扰,如用户下载安装的其他软件或访问的其他网站中含有“木马”等病毒,威胁到用户的计算机信息和数据的安全,继而影响宝塔的正常使用等,用户应加强信息安全及使用资料的保护,以免遭受损失
+6.3 宝塔界面中“第三方应用”是宝塔获得了第三方合法授权的,如因用户使用第三方软件或技术引发的任何纠纷,由第三方负责解决,宝塔不对第三方软件或技术提供服务,若用户需要获得支持,请与该第三方联系。
+6.4 用户因使用宝塔违反国家法律法规的,
+
+七、授权例外
+7.1 如果上述条款无法满足您使用该软件的要求,可联系宝塔签署额外的合同以获得更灵活的授权许可。
+
+八、合同终止
+8.1 如果用户违反了本协议的任一条款,本授权协议将自动终止,用户行为损害宝塔或其他任意第三方权利的,宝塔保留通过法律手段追究责任的权利。
+
+九、其他条款
+9.1 本协议约定的任何条款部分或完全无效的,不影响其他条款的效力。
+9.2 协议的解释、效力及纠纷的解决使用中华人民共和国法律,若用户和宝塔发生任何纠纷或争议,首先应当友好协商解决,协商不成的,用户完全同意将该纠纷或争议提交至宝塔所在地即东莞市有管辖权的法院管辖。
+9.3 本协议宝塔保留一切解释权利
\ No newline at end of file
From f727c05b9f53d679f5210863a70c32ada80cd448 Mon Sep 17 00:00:00 2001
From: "bt.cn" <31841517+aaPanel@users.noreply.github.com>
Date: Tue, 18 Jun 2019 14:50:55 +0800
Subject: [PATCH 12/79] Update README.md
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index d18323b4..13deb69c 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+##### 宝塔开源许可协议:https://www.bt.cn/kyxy.html
##### 使用手册:http://docs.bt.cn
##### 论坛地址:https://www.bt.cn/bbs
##### 反馈建议: https://www.bt.cn/bbs/forum-43-1.html
From f6151305c8f2de01843360649c4be3b53e694a5b Mon Sep 17 00:00:00 2001
From: "bt.cn" <287962566@qq.com>
Date: Tue, 18 Jun 2019 15:21:50 +0800
Subject: [PATCH 13/79] =?UTF-8?q?SSH=E7=BB=88=E7=AB=AF=E4=BF=AE=E5=A4=8D?=
=?UTF-8?q?=E7=94=A8=E6=88=B7=E5=90=8D=E5=AF=86=E7=A0=81=E5=B8=A6=E7=A9=BA?=
=?UTF-8?q?=E6=A0=BC=E5=AF=BC=E8=87=B4=E7=9A=84=E7=99=BB=E5=BD=95=E5=A4=B1?=
=?UTF-8?q?=E8=B4=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
BTPanel/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/BTPanel/__init__.py b/BTPanel/__init__.py
index 1b5723f2..56af7296 100644
--- a/BTPanel/__init__.py
+++ b/BTPanel/__init__.py
@@ -814,7 +814,7 @@ def webssh(msg):
ssh_success = True
if type(msg) == dict:
if 'ssh_user' in msg:
- connect_ssh(msg['ssh_user'],msg['ssh_passwd'])
+ connect_ssh(msg['ssh_user'].strip(),msg['ssh_passwd'].strip())
if not shell: ssh_success = connect_ssh()
if not shell:
emit('server_response',{'data':public.getMsg('INIT_WEBSSH_CONN_ERR')})
From 675d0d4ccff49a39b43f864e5c501a4a68be6c32 Mon Sep 17 00:00:00 2001
From: "bt.cn" <287962566@qq.com>
Date: Tue, 18 Jun 2019 15:44:48 +0800
Subject: [PATCH 14/79] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=8A=82=E7=82=B9?=
=?UTF-8?q?=E9=85=8D=E7=BD=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
data/node.json | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/data/node.json b/data/node.json
index c5660095..f9c24290 100644
--- a/data/node.json
+++ b/data/node.json
@@ -17,6 +17,18 @@
"port": "3389",
"ping": 500
},
+ {
+ "protocol": "http://",
+ "address": "119.188.210.21",
+ "port": "5880",
+ "ping": 500
+ },
+ {
+ "protocol": "http://",
+ "address": "45.32.116.160",
+ "port": "80",
+ "ping": 500
+ },
{
"protocol": "http://",
"address": "128.1.164.196",
From acc53bd72e1005298457ade608a4a65effd4c746 Mon Sep 17 00:00:00 2001
From: "bt.cn" <287962566@qq.com>
Date: Tue, 18 Jun 2019 16:44:50 +0800
Subject: [PATCH 15/79] =?UTF-8?q?=E4=BF=AE=E6=AD=A3Apache=E5=BC=80?=
=?UTF-8?q?=E5=90=AF=E9=BB=98=E8=AE=A4=E7=AB=99=E7=82=B9=E5=AF=BC=E8=87=B4?=
=?UTF-8?q?=E6=97=A0=E6=B3=95=E8=8E=B7=E5=8F=96=E8=B4=9F=E8=BD=BD=E7=8A=B6?=
=?UTF-8?q?=E6=80=81=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
BTPanel.pyproj | 3 +++
class/panelSite.py | 4 +++-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/BTPanel.pyproj b/BTPanel.pyproj
index c0a30313..fabb0e4c 100644
--- a/BTPanel.pyproj
+++ b/BTPanel.pyproj
@@ -32,10 +32,12 @@
+
+
@@ -780,6 +782,7 @@
+
diff --git a/class/panelSite.py b/class/panelSite.py
index 1ea09e31..e8246cb5 100644
--- a/class/panelSite.py
+++ b/class/panelSite.py
@@ -3493,8 +3493,10 @@ def SetDefaultSite(self,get):
if os.path.exists(path):
conf = '''
RewriteEngine on
+ RewriteCond %{HTTP_HOST} !^127.0.0.1 [NC]
RewriteRule (.*) http://%s/$1 [L]
-''' % (get.name,)
+'''
+ conf = conf.replace("%s",get.name)
if get.name == 'off': conf = '';
public.writeFile(path + '/.htaccess',conf);
From 5f506ffa8cf1bfd8f34e24085724c84143ae7d43 Mon Sep 17 00:00:00 2001
From: "bt.cn" <287962566@qq.com>
Date: Tue, 18 Jun 2019 17:08:05 +0800
Subject: [PATCH 16/79] =?UTF-8?q?=E5=A2=9E=E5=8A=A0phpMyadmin=E7=8A=B6?=
=?UTF-8?q?=E6=80=81=E6=8E=A7=E5=88=B6=E5=92=8C=E4=BF=AE=E6=AD=A3=E5=85=B6?=
=?UTF-8?q?=E9=A6=96=E9=A1=B5=E5=9B=BE=E6=A0=87=E6=98=BE=E7=A4=BA=E9=94=99?=
=?UTF-8?q?=E8=AF=AF=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
BTPanel.pyproj | 3 +++
BTPanel/static/js/index.js | 2 +-
BTPanel/static/js/soft.js | 6 +++++-
class/panelPlugin.py | 12 ++++++++++++
4 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/BTPanel.pyproj b/BTPanel.pyproj
index fabb0e4c..8b8f5fd9 100644
--- a/BTPanel.pyproj
+++ b/BTPanel.pyproj
@@ -774,16 +774,19 @@
+
+
+
diff --git a/BTPanel/static/js/index.js b/BTPanel/static/js/index.js
index 5236063b..0629480a 100644
--- a/BTPanel/static/js/index.js
+++ b/BTPanel/static/js/index.js
@@ -392,7 +392,7 @@ var index = {
clickName = 'onclick="soft.set_soft_config(\'' + rdata[i].name + '\')"';
}
var icon = rdata[i].name;
- if (bt.contains(rdata[i].name, 'php')) {
+ if (bt.contains(rdata[i].name, 'php-')) {
icon = 'php';
rdata[i].version = '';
}
diff --git a/BTPanel/static/js/soft.js b/BTPanel/static/js/soft.js
index c3ec709e..9249b5b5 100644
--- a/BTPanel/static/js/soft.js
+++ b/BTPanel/static/js/soft.js
@@ -532,7 +532,7 @@ var soft = {
});
var menu = $('.bt-soft-menu').data("data", rdata);
setTimeout(function () {
- if (name != 'phpmyadmin') menu.append($('' + lan.soft.service + '
'))
+ menu.append($('' + lan.soft.service + '
'))
if (rdata.version_coexist) {
var ver = name.split('-')[1].replace('.', '');
var opt_list = [
@@ -590,11 +590,15 @@ var soft = {
case 'service':
var tabCon = $(".soft-man-con").empty();
+
var status_list = [
{ opt: data.status ? 'stop' : 'start', title: data.status ? lan.soft.stop : lan.soft.start },
{ opt: 'restart', title: lan.soft.restart },
{ opt: 'reload', title: lan.soft.reload }
]
+ if (data.name == 'phpmyadmin') {
+ status_list = [status_list[0]];
+ }
var btns = $('');
for (var i = 0; i < status_list.length; i++) btns.append('');
tabCon.append('' + lan.soft.status + ':' + (data.status ? lan.soft.on : lan.soft.off) + '
Date: Wed, 19 Jun 2019 16:46:55 +0800
Subject: [PATCH 17/79] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AE=98=E7=BD=91?=
=?UTF-8?q?=E8=BF=9E=E6=8E=A5=E6=9C=BA=E5=88=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
BTPanel.pyproj | 1 +
BTPanel/__init__.py | 6 ++++
class/public.py | 83 ++++++++++++++++++++++++++++++++++++++-------
config/hosts.json | 1 +
4 files changed, 78 insertions(+), 13 deletions(-)
create mode 100644 config/hosts.json
diff --git a/BTPanel.pyproj b/BTPanel.pyproj
index 8b8f5fd9..17519136 100644
--- a/BTPanel.pyproj
+++ b/BTPanel.pyproj
@@ -838,6 +838,7 @@
+
diff --git a/BTPanel/__init__.py b/BTPanel/__init__.py
index 56af7296..abb2aad7 100644
--- a/BTPanel/__init__.py
+++ b/BTPanel/__init__.py
@@ -20,6 +20,11 @@
from werkzeug.wrappers import Response
from flask_socketio import SocketIO,emit,send
+from flask_basicauth import BasicAuth
+app.config['BASIC_AUTH_USERNAME'] = 'admin'
+app.config['BASIC_AUTH_PASSWORD'] = 'amwyygyyv'
+app.config['BASIC_AUTH_FORCE'] = True
+basic_auth = BasicAuth(app)
cache = SimpleCache()
@@ -30,6 +35,7 @@
jobs.control_init()
app.secret_key = uuid.UUID(int=uuid.getnode()).hex[-12:]
+
try:
from flask_sqlalchemy import SQLAlchemy
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////dev/shm/session.db'
diff --git a/class/public.py b/class/public.py
index 28952c50..281f440a 100644
--- a/class/public.py
+++ b/class/public.py
@@ -22,13 +22,20 @@ def M(table):
sql = db.Sql()
return sql.table(table);
-def HttpGet(url,timeout = 10):
+def HttpGet(url,timeout = 3,headers = {}):
"""
发送GET请求
@url 被请求的URL地址(必需)
@timeout 超时时间默认60秒
return string
"""
+ home = 'www.bt.cn'
+ host_home = 'data/home_host.pl'
+ old_url = url
+ if url.find(home) != -1:
+ if os.path.exists(host_home):
+ headers['host'] = home
+ url = url.replace(home,readFile(host_home))
if sys.version_info[0] == 2:
try:
import urllib2,ssl
@@ -38,9 +45,12 @@ def HttpGet(url,timeout = 10):
try:
ssl._create_default_https_context = ssl._create_unverified_context
except:pass;
- response = urllib2.urlopen(url,timeout=timeout)
+ req = urllib2.Request(url, headers = headers)
+ response = urllib2.urlopen(req,timeout = timeout,)
return response.read()
except Exception as ex:
+ if old_url.find(home) != -1: return http_get_home(old_url,timeout,str(ex))
+ if headers: return False
return str(ex);
else:
try:
@@ -48,19 +58,37 @@ def HttpGet(url,timeout = 10):
try:
ssl._create_default_https_context = ssl._create_unverified_context
except:pass;
- response = urllib.request.urlopen(url,timeout=timeout)
+ req = urllib.request.Request(url,headers = headers)
+ response = urllib.request.urlopen(req,timeout = timeout)
result = response.read()
if type(result) == bytes: result = result.decode('utf-8')
return result
except Exception as ex:
+ if old_url.find(home) != -1: return http_get_home(old_url,timeout,str(ex))
+ if headers: return False
return str(ex)
-
-def httpGet(url,timeout=10):
+def http_get_home(url,timeout,ex):
+ try:
+ home = 'www.bt.cn'
+ if url.find(home) == -1: return ex
+ hosts_file = "config/hosts.json"
+ if not os.path.exists(hosts_file): return ex
+ hosts = json.loads(readFile(hosts_file))
+ headers = {"host":home}
+ for host in hosts:
+ new_url = url.replace(home,host)
+ res = HttpGet(new_url,timeout,headers)
+ if res:
+ writeFile("data/home_host.pl",host)
+ return res
+ return ex
+ except: return ex
+
+def httpGet(url,timeout=3):
return HttpGet(url,timeout)
-
-def HttpPost(url,data,timeout = 10):
+def HttpPost(url,data,timeout = 3,headers = {}):
"""
发送POST请求
@url 被请求的URL地址(必需)
@@ -68,17 +96,27 @@ def HttpPost(url,data,timeout = 10):
@timeout 超时时间默认60秒
return string
"""
+ home = 'www.bt.cn'
+ host_home = 'data/home_host.pl'
+ old_url = url
+ if url.find(home) != -1:
+ if os.path.exists(host_home):
+ headers['host'] = home
+ url = url.replace(home,readFile(host_home))
+
if sys.version_info[0] == 2:
try:
import urllib,urllib2,ssl
try:
ssl._create_default_https_context = ssl._create_unverified_context
except:pass
- data = urllib.urlencode(data)
- req = urllib2.Request(url, data)
- response = urllib2.urlopen(req,timeout = timeout)
+ data2 = urllib.urlencode(data)
+ req = urllib2.Request(url, data2,headers = headers)
+ response = urllib2.urlopen(req,timeout=timeout)
return response.read()
except Exception as ex:
+ if old_url.find(home) != -1: return http_post_home(old_url,data,timeout,str(ex))
+ if headers: return False
return str(ex);
else:
try:
@@ -86,16 +124,35 @@ def HttpPost(url,data,timeout = 10):
try:
ssl._create_default_https_context = ssl._create_unverified_context
except:pass;
- data = urllib.parse.urlencode(data).encode('utf-8')
- req = urllib.request.Request(url, data)
+ data2 = urllib.parse.urlencode(data).encode('utf-8')
+ req = urllib.request.Request(url, data2,headers = headers)
response = urllib.request.urlopen(req,timeout = timeout)
result = response.read()
if type(result) == bytes: result = result.decode('utf-8')
return result
except Exception as ex:
+ if old_url.find(home) != -1: return http_post_home(old_url,data,timeout,str(ex))
+ if headers: return False
return str(ex);
-def httpPost(url,data,timeout=10):
+def http_post_home(url,data,timeout,ex):
+ try:
+ home = 'www.bt.cn'
+ if url.find(home) == -1: return ex
+ hosts_file = "config/hosts.json"
+ if not os.path.exists(hosts_file): return ex
+ hosts = json.loads(readFile(hosts_file))
+ headers = {"host":home}
+ for host in hosts:
+ new_url = url.replace(home,host)
+ res = HttpPost(new_url,data,timeout,headers)
+ if res:
+ writeFile("data/home_host.pl",host)
+ return res
+ return ex
+ except: return ex
+
+def httpPost(url,data,timeout=3):
return HttpPost(url,data,timeout)
def check_home():
diff --git a/config/hosts.json b/config/hosts.json
new file mode 100644
index 00000000..8c3f40f2
--- /dev/null
+++ b/config/hosts.json
@@ -0,0 +1 @@
+[ "103.224.251.67", "119.188.210.21", "45.32.116.160", "125.88.182.172"]
\ No newline at end of file
From d43d13034814034087f4f3109a504eac0fc5b414 Mon Sep 17 00:00:00 2001
From: "bt.cn" <287962566@qq.com>
Date: Wed, 19 Jun 2019 16:51:35 +0800
Subject: [PATCH 18/79] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=AE=9D=E5=A1=94?=
=?UTF-8?q?=E5=B8=90=E5=8F=B7=E7=BB=91=E5=AE=9A=E5=A4=B1=E6=95=88=E5=90=8E?=
=?UTF-8?q?=EF=BC=8C=E8=8E=B7=E5=8F=96=E4=BA=91=E7=AB=AFSSL=E5=88=97?=
=?UTF-8?q?=E8=A1=A8=E6=97=B6=E6=B2=A1=E6=9C=89=E6=8F=90=E7=A4=BA=E7=9A=84?=
=?UTF-8?q?=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
BTPanel/__init__.py | 10 +++++-----
BTPanel/static/js/site.js | 4 ++++
2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/BTPanel/__init__.py b/BTPanel/__init__.py
index abb2aad7..3e45d0ea 100644
--- a/BTPanel/__init__.py
+++ b/BTPanel/__init__.py
@@ -20,11 +20,11 @@
from werkzeug.wrappers import Response
from flask_socketio import SocketIO,emit,send
-from flask_basicauth import BasicAuth
-app.config['BASIC_AUTH_USERNAME'] = 'admin'
-app.config['BASIC_AUTH_PASSWORD'] = 'amwyygyyv'
-app.config['BASIC_AUTH_FORCE'] = True
-basic_auth = BasicAuth(app)
+#from flask_basicauth import BasicAuth
+#app.config['BASIC_AUTH_USERNAME'] = 'admin'
+#app.config['BASIC_AUTH_PASSWORD'] = '11111'
+#app.config['BASIC_AUTH_FORCE'] = True
+#basic_auth = BasicAuth(app)
cache = SimpleCache()
diff --git a/BTPanel/static/js/site.js b/BTPanel/static/js/site.js
index 7e09fb63..d524f9a1 100644
--- a/BTPanel/static/js/site.js
+++ b/BTPanel/static/js/site.js
@@ -1122,6 +1122,10 @@ var site = {
var loading = bt.load()
bt.site.get_order_list(web.name, function (odata) {
loading.close();
+ if (odata.status === false) {
+ layer.msg(odata.msg, { icon: 2 });
+ return;
+ }
robj.append("");
bt.render({
table: '#bt_order_list',
From 192c88a00b94e5d8378c019802b92deb3cd4f4c1 Mon Sep 17 00:00:00 2001
From: "bt.cn" <287962566@qq.com>
Date: Wed, 19 Jun 2019 17:40:50 +0800
Subject: [PATCH 19/79] 6.9.23
---
class/public.py | 44 ++++++++++++++------------------------------
config/hosts.json | 2 +-
install/public.sh | 2 +-
3 files changed, 16 insertions(+), 32 deletions(-)
diff --git a/class/public.py b/class/public.py
index 281f440a..211b4cb4 100644
--- a/class/public.py
+++ b/class/public.py
@@ -22,7 +22,7 @@ def M(table):
sql = db.Sql()
return sql.table(table);
-def HttpGet(url,timeout = 3,headers = {}):
+def HttpGet(url,timeout = 6,headers = {}):
"""
发送GET请求
@url 被请求的URL地址(必需)
@@ -81,14 +81,22 @@ def http_get_home(url,timeout,ex):
res = HttpGet(new_url,timeout,headers)
if res:
writeFile("data/home_host.pl",host)
+ set_home_host(host)
return res
return ex
except: return ex
-def httpGet(url,timeout=3):
+
+def set_home_host(host):
+ ExecShell('sed -i "/www.bt.cn/d" /etc/hosts')
+ ExecShell("echo '' >> /etc/hosts")
+ ExecShell("echo '%s www.bt.cn' >> /etc/hosts" % host)
+ ExecShell('sed -i "/^\s*$/d" /etc/hosts')
+
+def httpGet(url,timeout=6):
return HttpGet(url,timeout)
-def HttpPost(url,data,timeout = 3,headers = {}):
+def HttpPost(url,data,timeout = 6,headers = {}):
"""
发送POST请求
@url 被请求的URL地址(必需)
@@ -148,40 +156,16 @@ def http_post_home(url,data,timeout,ex):
res = HttpPost(new_url,data,timeout,headers)
if res:
writeFile("data/home_host.pl",host)
+ set_home_host(host)
return res
return ex
except: return ex
-def httpPost(url,data,timeout=3):
+def httpPost(url,data,timeout=6):
return HttpPost(url,data,timeout)
def check_home():
- try:
- if HttpGet('http://www.bt.cn/test.txt') == 'True': return True
- hosts = '/etc/hosts'
- hosts_body = ReadFile(hosts)
- if hosts_body.find('www.bt.cn') != -1: return True
-
- url = 'http://125.88.182.170/test.txt'
- if sys.version_info[0] == 2:
- import urllib2
- req = urllib2.Request(url)
- req.add_header('host','www.bt.cn')
- result = urllib2.urlopen(req).read()
- else:
- import urllib.request
- req = urllib.request.Request(url)
- req.add_header('host','www.bt.cn')
- result = urllib.request.urlopen(req).read()
- result = result.decode('utf-8')
- if result != 'True': return True
- ExecShell("echo '' >> /etc/hosts")
- ExecShell("echo '125.88.182.170 www.bt.cn' >> /etc/hosts")
- return True
- except:
- return True
-
-
+ return True
def Md5(strings):
"""
diff --git a/config/hosts.json b/config/hosts.json
index 8c3f40f2..d0df5993 100644
--- a/config/hosts.json
+++ b/config/hosts.json
@@ -1 +1 @@
-[ "103.224.251.67", "119.188.210.21", "45.32.116.160", "125.88.182.172"]
\ No newline at end of file
+[ "103.224.251.67", "119.188.210.21", "45.32.116.160", "183.60.107.171" ]
\ No newline at end of file
diff --git a/install/public.sh b/install/public.sh
index 0c4ab3ba..e23633fe 100644
--- a/install/public.sh
+++ b/install/public.sh
@@ -5,7 +5,7 @@ export LANG=en_US.UTF-8
export LANGUAGE=en_US:en
get_node_url(){
- nodes=(http://183.235.223.101:3389 http://125.88.182.172:5880 http://128.1.164.196 http://103.224.251.67 http://download.bt.cn);
+ nodes=(http://183.235.223.101:3389 http://119.188.210.21:5880 http://125.88.182.172:5880 http://103.224.251.67 http://download.bt.cn http://45.32.116.160 http://128.1.164.196);
i=1;
for node in ${nodes[@]};
do
From 9e087cb157b6cd8d176bd63f7e8e666001b2fdaa Mon Sep 17 00:00:00 2001
From: "bt.cn" <287962566@qq.com>
Date: Fri, 21 Jun 2019 14:24:51 +0800
Subject: [PATCH 20/79] =?UTF-8?q?=E5=A2=9E=E5=8A=A0BasicAuth=E8=AE=A4?=
=?UTF-8?q?=E8=AF=81=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BF=AE=E6=AD=A3apache2.2?=
=?UTF-8?q?=E4=B8=8B=E7=9A=84=E4=B8=80=E4=BA=9B=E6=98=BE=E7=A4=BA=E9=97=AE?=
=?UTF-8?q?=E9=A2=98=EF=BC=8C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
BTPanel.pyproj | 172 ++++++++++++++++++++++++++
BTPanel/__init__.py | 52 ++++++--
BTPanel/static/js/config.js | 63 ++++++++++
BTPanel/static/js/idown_index.js | 3 -
BTPanel/static/js/soft.js | 13 +-
BTPanel/templates/default/config.html | 1 +
class/config.py | 31 +++++
class/panelPlugin.py | 3 +-
class/plugin_deployment.py | 3 +-
class/public.py | 14 ++-
tools.py | 12 +-
11 files changed, 342 insertions(+), 25 deletions(-)
delete mode 100644 BTPanel/static/js/idown_index.js
diff --git a/BTPanel.pyproj b/BTPanel.pyproj
index 17519136..d4114035 100644
--- a/BTPanel.pyproj
+++ b/BTPanel.pyproj
@@ -79,6 +79,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -240,6 +250,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -934,6 +965,147 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BTPanel/__init__.py b/BTPanel/__init__.py
index 3e45d0ea..bfee4684 100644
--- a/BTPanel/__init__.py
+++ b/BTPanel/__init__.py
@@ -20,12 +20,16 @@
from werkzeug.wrappers import Response
from flask_socketio import SocketIO,emit,send
-#from flask_basicauth import BasicAuth
-#app.config['BASIC_AUTH_USERNAME'] = 'admin'
-#app.config['BASIC_AUTH_PASSWORD'] = '11111'
-#app.config['BASIC_AUTH_FORCE'] = True
-#basic_auth = BasicAuth(app)
-
+#设置BasicAuth
+basic_auth_conf = 'config/basic_auth.json'
+app.config['BASIC_AUTH_OPEN'] = False
+if os.path.exists(basic_auth_conf):
+ try:
+ ba_conf = json.loads(public.readFile(basic_auth_conf))
+ app.config['BASIC_AUTH_USERNAME'] = ba_conf['basic_user']
+ app.config['BASIC_AUTH_PASSWORD'] = ba_conf['basic_pwd']
+ app.config['BASIC_AUTH_OPEN'] = ba_conf['open']
+ except: pass
cache = SimpleCache()
socketio = SocketIO()
@@ -81,6 +85,22 @@
def service_status():
return 'True'
+
+@app.before_request
+def basic_auth_check():
+ if app.config['BASIC_AUTH_OPEN']:
+ if request.path in ['/public']: return;
+ auth = request.authorization
+ if not comm.get_sk(): return;
+ if not auth: return send_authenticated()
+ tips = '_bt.cn'
+ if public.md5(auth.username.strip() + tips) != app.config['BASIC_AUTH_USERNAME'] or public.md5(auth.password.strip() + tips) != app.config['BASIC_AUTH_PASSWORD']:
+ return send_authenticated()
+
+
+def send_authenticated():
+ return Response('', 401,{'WWW-Authenticate': 'Basic realm="Login Required"'})
+
@app.route('/',methods=method_all)
def home():
comReturn = comm.local()
@@ -186,7 +206,7 @@ def ftp(pdata = None):
data['isSetup'] = True;
if os.path.exists(public.GetConfigValue('setup_path') + '/pure-ftpd') == False: data['isSetup'] = False;
data['lan'] = public.GetLan('ftp')
- return render_template( 'ftp.html',data=data)
+ return render_template('ftp.html',data=data)
import ftp
ftpObject = ftp.ftp()
defs = ('AddUser','DeleteUser','SetUserPassword','SetStatus','setPort')
@@ -337,6 +357,7 @@ def config(pdata = None):
if comReturn: return comReturn
if request.method == method_get[0] and not pdata:
import system,wxapp,config
+ c_obj = config.config()
data = system.system().GetConcifInfo()
data['lan'] = public.GetLan('config')
try:
@@ -351,13 +372,15 @@ def config(pdata = None):
if not os.path.exists(workers_p): public.writeFile(workers_p,'1')
data['workers'] = int(public.readFile(workers_p))
data['session_timeout'] = int(public.readFile(sess_out_path))
- if config.config().get_ipv6_listen(None): data['ipv6'] = 'checked'
- if config.config().get_token(None)['open']: data['api'] = 'checked'
+ if c_obj.get_ipv6_listen(None): data['ipv6'] = 'checked'
+ if c_obj.get_token(None)['open']: data['api'] = 'checked'
+ data['basic_auth'] = c_obj.get_basic_auth_stat(None)
+ data['basic_auth']['value'] = '已关闭'
+ if data['basic_auth']['open']: data['basic_auth']['value'] = '已开启'
return render_template( 'config.html',data=data)
import config
- configObject = config.config()
- defs = ('get_cli_php_version','get_tmp_token','set_cli_php_version','DelOldSession', 'GetSessionCount', 'SetSessionConf', 'GetSessionConf','get_ipv6_listen','set_ipv6_status','GetApacheValue','SetApacheValue','GetNginxValue','SetNginxValue','get_token','set_token','set_admin_path','is_pro','get_php_config','get_config','SavePanelSSL','GetPanelSSL','GetPHPConf','SetPHPConf','GetPanelList','AddPanelInfo','SetPanelInfo','DelPanelInfo','ClickPanelInfo','SetPanelSSL','SetTemplates','Set502','setPassword','setUsername','setPanel','setPathInfo','setPHPMaxSize','getFpmConfig','setFpmConfig','setPHPMaxTime','syncDate','setPHPDisable','SetControl','ClosePanel','AutoUpdatePanel','SetPanelLock')
- return publicObject(configObject,defs,None,pdata);
+ defs = ('get_basic_auth_stat','set_basic_auth','get_cli_php_version','get_tmp_token','set_cli_php_version','DelOldSession', 'GetSessionCount', 'SetSessionConf', 'GetSessionConf','get_ipv6_listen','set_ipv6_status','GetApacheValue','SetApacheValue','GetNginxValue','SetNginxValue','get_token','set_token','set_admin_path','is_pro','get_php_config','get_config','SavePanelSSL','GetPanelSSL','GetPHPConf','SetPHPConf','GetPanelList','AddPanelInfo','SetPanelInfo','DelPanelInfo','ClickPanelInfo','SetPanelSSL','SetTemplates','Set502','setPassword','setUsername','setPanel','setPathInfo','setPHPMaxSize','getFpmConfig','setFpmConfig','setPHPMaxTime','syncDate','setPHPDisable','SetControl','ClosePanel','AutoUpdatePanel','SetPanelLock')
+ return publicObject(config.config(),defs,None,pdata);
@app.route('/ajax',methods=method_all)
def ajax(pdata = None):
@@ -455,7 +478,12 @@ def plugin(pdata = None):
def panel_public():
get = get_input();
get.client_ip = public.GetClientIp();
+
if get.fun in ['scan_login','login_qrcode','set_login','is_scan_ok','blind']:
+ #检查是否验证过安全入口
+ if get.fun in ['login_qrcode','is_scan_ok']:
+ global admin_check_auth,admin_path,route_path,admin_path_file
+ if admin_path != '/bt' and os.path.exists(admin_path_file) and not 'admin_auth' in session: return 'False'
import wxapp
pluwx = wxapp.wxapp()
checks = pluwx._check(get)
diff --git a/BTPanel/static/js/config.js b/BTPanel/static/js/config.js
index c37707c4..a11f3fc0 100644
--- a/BTPanel/static/js/config.js
+++ b/BTPanel/static/js/config.js
@@ -519,4 +519,67 @@ function SetIPv6() {
layer.close(loadT);
bt.msg(rdata);
});
+}
+
+
+function modify_basic_auth_to() {
+ var pdata = {
+ open: $("select[name='open']").val(),
+ basic_user: $("input[name='basic_user']").val(),
+ basic_pwd: $("input[name='basic_pwd']").val()
+ }
+ var loadT = layer.msg('正在配置BasicAuth服务,请稍候...', { icon: 16, time: 0, shade: [0.3, '#000'] });
+ $.post('/config?action=set_basic_auth', pdata, function (rdata) {
+ layer.close(loadT);
+ if (rdata.status) {
+ layer.closeAll();
+ setTimeout(function () { window.location.reload(); }, 3000);
+ }
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
+ });
+
+}
+
+function modify_basic_auth() {
+ var loadT = layer.msg('正在获取配置,请稍候...', { icon: 16, time: 0, shade: [0.3, '#000'] });
+ $.post('/config?action=get_basic_auth_stat', {}, function (rdata) {
+ layer.close(loadT);
+ layer.open({
+ type: 1,
+ area: "500px",
+ title: "配置BasicAuth认证",
+ closeBtn: 2,
+ shift: 5,
+ shadeClose: false,
+ content: ' '
+ })
+ });
}
\ No newline at end of file
diff --git a/BTPanel/static/js/idown_index.js b/BTPanel/static/js/idown_index.js
deleted file mode 100644
index 5522985f..00000000
--- a/BTPanel/static/js/idown_index.js
+++ /dev/null
@@ -1,3 +0,0 @@
-var idown_version="1.0";$(".layui-layer-page").css({"width":"900px"});$(".bt-w-menu p").click(function(){console.log("点击了菜单");var i=$(this).index();$(this).addClass("bgw").siblings().removeClass("bgw");$(".plugin_body > div").hide().eq(i).show();switch(i){case 0:idown.get_down_index();break;case 1:idown.get_down_new();break;case 2:idown.get_down_active();break;case 3:idown.get_down_stop();break}});var idown={get_down_index:function(){request_plugin("idown","get_panel_indexinfo",{},function(rdata){if(rdata["idown_status"]=="run"){$("#idown_status").prop("checked",true)}else{$("#idown_status").prop("checked",false)}$("#idown_rpc_token").val(rdata["idown_rpc_token"]);$("#webapi_token").val(rdata["idown_webapi_token"]);$("#api_url").val("http://"+rdata["idown_serverip"]+":8001/api");$("#api_help").attr("src","http://"+rdata["idown_serverip"]+":8001/help")})},get_down_new:function(){$("#download_new_link").val("");var obj=document.getElementById("download_new_bt_link");obj.outerHTML=obj.outerHTML;$("#download_textarea_placeholder").show();console.log("显示了下载地址的遮罩层")},get_down_active:function(){request_plugin("idown","download_list_active",{},function(rdata){var num_active=count_array(rdata["Active"]["result"]);var num_wait=count_array(rdata["Wait"]["result"]);var HtmlTable="";if(num_active==0&&num_wait==0){var HtmlTable='| 没有找到相关任务! |
'}else{for(var i=0;i35){filename=filename.substr(0,35);filename=filename+"..."}}catch(err){filename="[METADATA]"+rdata["Active"]["result"][i]["infoHash"]}var size=rdata["Active"]["result"][i]["totalLength"];size=getsize(size,3);var speed=rdata["Active"]["result"][i]["downloadSpeed"];speed=getsize(speed,1);var percent=(rdata["Active"]["result"][i]["completedLength"]/rdata["Active"]["result"][i]["totalLength"]*100).toFixed(3);HtmlTable=HtmlTable+"| "+filename+' | |
';HtmlTable=HtmlTable+'| Size:'+size+" Speed:"+speed+" Percent:"+percent+"% State:"+'正在下载'+" |
"}for(var i=0;i35){filename=filename.substr(0,35);filename=filename+"..."}}catch(err){filename="[METADATA]"+rdata["Wait"]["result"][i]["infoHash"]}var size=rdata["Wait"]["result"][i]["totalLength"];size=getsize(size,3);var speed=rdata["Wait"]["result"][i]["downloadSpeed"];speed=getsize(speed,1);var percent=(rdata["Wait"]["result"][i]["completedLength"]/rdata["Wait"]["result"][i]["totalLength"]*100).toFixed(3);HtmlTable=HtmlTable+"| "+filename+' | |
';HtmlTable=HtmlTable+'| Size:'+size+" Speed:"+speed+" Percent:"+percent+"% State:"+'下载暂停'+" |
"}}$("#table_list_active").html(HtmlTable)})},get_down_stop:function(){request_plugin("idown","download_list_stop",{},function(rdata){var num=count_array(rdata["result"]);var HtmlTable="";if(num==0){var HtmlTable='| 没有找到相关任务! |
'}else{for(var i=0;i35){filename=filename.substr(0,35);filename=filename+"..."}var size=rdata["result"][i]["totalLength"];size=getsize(size,3);var speed=rdata["result"][i]["downloadSpeed"];speed=getsize(speed,1);var percent=(rdata["result"][i]["completedLength"]/rdata["result"][i]["totalLength"]*100).toFixed(3);HtmlTable=HtmlTable+"| "+filename+' | |
';HtmlTable=HtmlTable+'| Size:'+size+" Speed:"+speed+" Percent:"+percent+"% State:"+'下载完成'+" |
"}}$("#table_list_stop").html(HtmlTable)})},button_newdownload:function(){var loadT=layer.msg("正在添加新的下载任务...",{icon:16,time:0,shade:[0.3,"#000"]});
-var txt=$("#download_new_link").val();if(txt!=""){var regex=true;_link=txt;if(_link!=""&®ex){var regex_http=/^http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- ./?%&=]*)?$/;var regex_ftp=/^ftp:\/\/(([1-9]|([1-9]\d)|(1\d\d)|(2([0-4]\d|5[0-5])))\.)((d|([1-9]\d)|(1\d\d)|(2([0-4]\d|5[0-5])))\.){2}([1-9]|([1-9]\d)|(1\d\d)|(2([0-4]\d|5[0-5]))$)|^ftp:\/\/([a-zA-Z0-9_-])+:([a-zA-Z0-9_-])+@(([1-9]|([1-9]\d)|(1\d\d)|(2([0-4]\d|5[0-5])))\.)((d|([1-9]\d)|(1\d\d)|(2([0-4]\d|5[0-5])))\.){2}([1-9]|([1-9]\d)|(1\d\d)|(2([0-4]\d|5[0-5]))$)/;var regex_magnet=/^(magnet:\?xt=urn:btih:)[0-9a-zA-Z]{32,}.*$/;if(!regex_http.test(_link)&&!regex_ftp.test(_link)&&!regex_magnet.test(_link)){layer.close(loadT);layer.msg("您输入的下载地址有误,请输入正确的下载地址,支持http/https/ftp/magnet格式的链接",{icon:5});idown.get_down_new();regex=false}}if(regex==true){data="link="+_link;request_plugin("idown","download_addnew_link",data,function(rdata){if(rdata["server_result"]=="success"){layer.close(loadT);layer.msg("新建下载 任务成功",{icon:1})}else{layer.close(loadT);layer.msg("新建下载任务失败"+rdata["mes"],{icon:5})}idown.get_down_new()})}}else{var bt_link=$("#download_new_bt_link").val();if(bt_link==""){layer.close(loadT);layer.msg("请输入需要下载的文件链接地址或者上传种子文件",{icon:5});idown.get_down_new()}else{var name=$("#download_new_bt_link")[0].files[0].name;var _name=name.split(".");var i=_name.length;if(_name[i-1]!="torrent"&&_name[i-1]!="TORRENT"){layer.close(loadT);layer.msg("仅支持torrent格式的种子文件",{icon:5});idown.get_down_new()}else{var formData=new FormData();formData.append("file",$("#download_new_bt_link")[0].files[0]);request_plugin("idown","download_addnew_bt",formData,function(rdata){if(rdata["server_result"]=="success"){layer.close(loadT);layer.msg("新建BT下载 任务成功",{icon:1})}else{layer.close(loadT);layer.msg("新建BT下载任务失败"+rdata["mes"],{icon:5})}idown.get_down_new()},true)}}}},aria2c_server:function(){if($("#idown_status").prop("checked")){var loadT=layer.msg("正在关闭远程下载服务...",{icon:16,time:0,shade:[0.3,"#000"]});request_plugin("idown","server_stop",{},function(rdata){if(rdata["server_result"]=="success"){layer.close(loadT);layer.msg("关闭远程下载服务成功",{icon:1})}else{layer.close(loadT);layer.msg("关闭远程下载服务失败"+rdata["mes"],{icon:5})}})}else{var loadT=layer.msg("正在启动远程下载服务...",{icon:16,time:0,shade:[0.3,"#000"]});request_plugin("idown","server_start",{},function(rdata){if(rdata["server_result"]=="success"){layer.close(loadT);layer.msg("启动远程下载服务成功",{icon:1})}else{layer.close(loadT);layer.msg("启动远程下载服务失败"+rdata["mes"],{icon:5})}})}},hide_placeholder:function(){$("#download_textarea_placeholder").hide();console.log("隐藏下载地址的遮罩层")},button_start:function(button){var loadT=layer.msg("正在启动任务...",{icon:16,time:0,shade:[0.3,"#000"]});var gid=button.getAttribute("gid");var post="gid="+gid;request_plugin("idown","download_start_alone",post,function(rdata){if(rdata["server_result"]=="success"){layer.close(loadT);layer.msg("启动任务成功...",{icon:1});idown.get_down_active()}else{layer.close(loadT);layer.msg("启动任务失败..."+rdata["mes"],{icon:5})}})},button_pause:function(button){var loadT=layer.msg("正在删除任务...",{icon:16,time:0,shade:[0.3,"#000"]});var gid=button.getAttribute("gid");var post="gid="+gid;request_plugin("idown","download_pause_alone",post,function(rdata){if(rdata["server_result"]=="success"){layer.close(loadT);layer.msg("删除任务成功...",{icon:1});idown.get_down_active()}else{layer.close(loadT);layer.msg("删除任务失败..."+rdata["mes"],{icon:5})}})},button_del_downing:function(button){var loadT=layer.msg("正在删除任务...",{icon:16,time:0,shade:[0.3,"#000"]});var gid=button.getAttribute("gid");var post="gid="+gid;request_plugin("idown","download_del_doing_alone",post,function(rdata){if(rdata["server_result"]=="success"){layer.close(loadT);layer.msg("删除任务成功...",{icon:1});idown.get_down_active()}else{layer.close(loadT);layer.msg("删除任务失败..."+rdata["mes"],{icon:5})}})},button_del_over:function(button,file){var loadT=layer.msg("正在启动任务...",{icon:16,time:0,shade:[0.3,"#000"]});var gid=button.getAttribute("gid");var action;if(file==0){action="deldown"}else{action="delfile"}var post={gid:gid,delaction:action};request_plugin("idown","download_del_over_alone",post,function(rdata){if(rdata["server_result"]=="success"){layer.close(loadT);layer.msg("删除任务成功...",{icon:1});idown.get_down_stop()}else{layer.close(loadT);layer.msg("删除任务失败..."+rdata["mes"],{icon:5})}})},};function request_plugin(plugin_name,function_name,args,callback,isfile,timeout){if(!timeout){timeout=3600}if(!isfile){$.ajax({type:"POST",url:"/plugin?action=a&s="+function_name+"&name="+plugin_name,data:args,timeout:timeout,success:function(rdata){if(!callback){layer.msg(rdata.msg,{icon:rdata.status?1:2});return}return callback(rdata)},error:function(ex){if(!callback){layer.msg("请求过程发现错误!",{icon:2});return}return callback(ex)}})}else{$.ajax({type:"POST",url:"/plugin?action=a&s="+function_name+"&name="+plugin_name,data:args,timeout:timeout,cache:false,processData:false,contentType:false,success:function(rdata){if(!callback){layer.msg(rdata.msg,{icon:rdata.status?1:2});return}return callback(rdata)},error:function(ex){if(!callback){layer.msg("请求过程发现错误!",{icon:2});
-return}return callback(ex)}})}}function count_array(o){var t=typeof o;if(t=="string"){return o.length}else{if(t=="object"){var n=0;for(var i in o){n++}return n}}return false}function getsize(size,num){if(size<=1048576){size=(size/1024).toFixed(num)+"KB"}else{if(size>=1048576&&size<1073741824){size=(size/1048576).toFixed(num)+"MB"}else{if(size>=1073741824){size=(size/1073741824).toFixed(num)+"GB"}}}return size}idown.get_down_index();setInterval("idown.get_down_index()",2000);setInterval("idown.get_down_active()",2000);setInterval("idown.get_down_stop()",2000);
\ No newline at end of file
diff --git a/BTPanel/static/js/soft.js b/BTPanel/static/js/soft.js
index 9249b5b5..225c90fc 100644
--- a/BTPanel/static/js/soft.js
+++ b/BTPanel/static/js/soft.js
@@ -572,9 +572,16 @@ var soft = {
bt.soft.get_soft_find('apache', function (rdata) {
if (rdata.setup) {
if (rdata.version.indexOf('2.2') >= 0) {
- $(".apache24").hide();
- $(".bt_server").remove();
- $(".bt-w-menu p:eq(0)").trigger("click");
+ if (name.indexOf('php-') != -1) {
+ $(".apache24").hide();
+ $(".bt_server").remove();
+ $(".bt-w-menu p:eq(0)").trigger("click");
+ }
+
+ if (name.indexOf('apache') != -1) {
+ $(".bt-soft-menu p:eq(3)").remove()
+ $(".bt-soft-menu p:eq(3)").remove()
+ }
}
}
})
diff --git a/BTPanel/templates/default/config.html b/BTPanel/templates/default/config.html
index 66409f0c..b551225e 100644
--- a/BTPanel/templates/default/config.html
+++ b/BTPanel/templates/default/config.html
@@ -55,6 +55,7 @@ {{data['lan']['C1']}}
并发线程除非每秒有超过10人访问面板,建议值不要超过2,注意:>1时会导致宝塔终端插件异常
超时时间秒, 若用户在{{data['session_timeout']}}秒内没有任何操作,将自动退出面板
安全入口{{data['lan']['CY10']}}面板管理入口,设置后只能通过指定安全入口登录面板,如: /www_bt_cn
+ BasicAuth认证配置为面板增加一道基于BasicAuth的认证服务,有效防止面板被扫
{{data['lan']['CT3']}}{{data['lan']['CY3']}}
{{data['lan']['CT4']}}{{data['lan']['CY4']}}
{{data['lan']['CT5']}}{{data['lan']['CY5']}}
diff --git a/class/config.py b/class/config.py
index e95fd7e0..61a4c538 100644
--- a/class/config.py
+++ b/class/config.py
@@ -859,4 +859,35 @@ def set_cli_php_version(self,get):
if is_chattr != -1: public.ExecShell('chattr +i /usr/bin')
return public.returnMsg(True,'设置成功!')
+
+ #获取BasicAuth状态
+ def get_basic_auth_stat(self,get):
+ path = 'config/basic_auth.json'
+ is_install = True
+ if not os.path.exists(path): return {"basic_user":"","basic_pwd":"","open":False,"is_install":is_install}
+ ba_conf = json.loads(public.readFile(path))
+ ba_conf['is_install'] = is_install
+ return ba_conf
+
+ #设置BasicAuth
+ def set_basic_auth(self,get):
+ is_open = False
+ if get.open == 'True': is_open = True
+ tips = '_bt.cn'
+ path = 'config/basic_auth.json'
+ ba_conf = None
+ if os.path.exists(path):
+ ba_conf = json.loads(public.readFile(path))
+
+ if not ba_conf:
+ ba_conf = {"basic_user":public.md5(get.basic_user.strip() + tips),"basic_pwd":public.md5(get.basic_pwd.strip() + tips),"open":is_open}
+ else:
+ if get.basic_user: ba_conf['basic_user'] = public.md5(get.basic_user.strip() + tips)
+ if get.basic_pwd: ba_conf['basic_pwd'] = public.md5(get.basic_pwd.strip() + tips)
+ ba_conf['open'] = is_open
+
+ public.writeFile(path,json.dumps(ba_conf))
+ os.chmod(path,384)
+ public.writeFile('data/reload.pl','True')
+ return public.returnMsg(True,"设置成功!")
\ No newline at end of file
diff --git a/class/panelPlugin.py b/class/panelPlugin.py
index b6107aac..684e3892 100644
--- a/class/panelPlugin.py
+++ b/class/panelPlugin.py
@@ -603,8 +603,9 @@ def check_status(self,softInfo):
self.get_icon(softInfo['name'])
if softInfo['name'].find('php-') != -1:
v2= softInfo['versions'][0]['m_version'].replace('.','')
- softInfo['fpm'] = os.path.exists('/etc/init.d/php-fpm-' + v2)
+ softInfo['fpm'] = os.path.exists('/www/server/php/' + v2 + '/sbin/php-fpm')
softInfo['status'] = os.path.exists('/tmp/php-cgi-'+v2+'.sock')
+ if not softInfo['fpm']: softInfo['status'] = True
if softInfo['name'] == 'mysql': softInfo['status'] = self.process_exists('mysqld')
if softInfo['name'] == 'phpmyadmin': softInfo['status'] = self.get_phpmyadmin_stat()
return softInfo
diff --git a/class/plugin_deployment.py b/class/plugin_deployment.py
index 2c033b26..98b37734 100644
--- a/class/plugin_deployment.py
+++ b/class/plugin_deployment.py
@@ -308,7 +308,7 @@ def SetupPackage(self,get):
#执行额外shell进行依赖安装
self.WriteLogs(json.dumps({'name':'执行额外SHELL','total':0,'used':0,'pre':0,'speed':0}));
if os.path.exists(path+'/install.sh'):
- os.system('cd '+path+' && bash ' + 'install.sh ' + find['name']);
+ os.system('cd '+path+' && bash ' + 'install.sh ' + find['name'] + " &> install.log");
os.system('rm -f ' + path+'/install.sh')
#是否执行Composer
@@ -369,6 +369,7 @@ def SetupPackage(self,get):
public.writeFile(siteConfigFile,siteConfig)
#清理文件和目录
+ self.WriteLogs(json.dumps({'name':'清理多余的文件','total':0,'used':0,'pre':0,'speed':0}));
for f_path in pinfo['remove_file']:
filename = (path + '/' + f_path).replace('//','/')
if os.path.exists(filename):
diff --git a/class/public.py b/class/public.py
index 211b4cb4..954c6450 100644
--- a/class/public.py
+++ b/class/public.py
@@ -1211,4 +1211,16 @@ def write_request_log():
log_data['uri'] = request.full_path
log_data['user-agent'] = request.headers.get('User-Agent')
WriteFile(log_path + '/' + log_file,json.dumps(log_data) + "\n",'a+')
- except: pass
\ No newline at end of file
+ except: pass
+
+#重载模块
+def mod_reload(mode):
+ if not mode: return False
+ try:
+ if sys.version_info[0] == 2:
+ reload(mode)
+ else:
+ import imp
+ imp.reload(module)
+ return True
+ except: return False
\ No newline at end of file
diff --git a/tools.py b/tools.py
index da7fad71..62706ac9 100644
--- a/tools.py
+++ b/tools.py
@@ -414,14 +414,15 @@ def bt_cli(u_input = 0):
print("(6) 修改面板用户名 (13) 取消IP访问限制")
print("(7) 强制修改MySQL密码 (14) 查看面板默认信息")
print("(22) 显示面板错误日志 (15) 清理系统垃圾")
- print("(0) 取消 (16) 修复面板(检查错误并更新面板文件到最新版)")
+ print("(23) 关闭BasicAuth认证 (16) 修复面板(检查错误并更新面板文件到最新版)")
+ print("(0) 取消 ")
print(raw_tip)
try:
u_input = input("请输入命令编号:")
if sys.version_info[0] == 3: u_input = int(u_input)
except: u_input = 0
- nums = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,22]
+ nums = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,22,23]
if not u_input in nums:
print(raw_tip)
print("已取消!")
@@ -533,8 +534,11 @@ def bt_cli(u_input = 0):
os.system("curl http://download.bt.cn/install/update6.sh|bash")
elif u_input == 22:
os.system('tail -100 /www/server/panel/logs/error.log')
-
-
+ elif u_input == 23:
+ filename = '/www/server/panel/config/basic_auth.json'
+ if os.path.exists(filename): os.remove(filename)
+ os.system('bt reload')
+ print("|-已关闭BasicAuth认证")
From 058e916eb88c1d40b429e75d9057e0d4bb00671a Mon Sep 17 00:00:00 2001
From: "bt.cn" <287962566@qq.com>
Date: Fri, 21 Jun 2019 14:28:00 +0800
Subject: [PATCH 21/79] update .gitignore
---
.gitignore | 271 ----------
BTPanel.pyproj | 1365 ------------------------------------------------
BTPanel.sln | 25 -
3 files changed, 1661 deletions(-)
delete mode 100644 .gitignore
delete mode 100644 BTPanel.pyproj
delete mode 100644 BTPanel.sln
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 913054b8..00000000
--- a/.gitignore
+++ /dev/null
@@ -1,271 +0,0 @@
-## Ignore Visual Studio temporary files, build results, and
-## files generated by popular Visual Studio add-ons.
-
-# User-specific files
-*.suo
-*.user
-*.userosscache
-*.sln.docstates
-
-# User-specific files (MonoDevelop/Xamarin Studio)
-*.userprefs
-
-# Build results
-[Dd]ebug/
-[Dd]ebugPublic/
-[Rr]elease/
-[Rr]eleases/
-x64/
-x86/
-bld/
-[Bb]in/
-[Oo]bj/
-[Ll]og/
-
-# Visual Studio 2015 cache/options directory
-.vs/
-# Uncomment if you have tasks that create the project's static files in wwwroot
-#wwwroot/
-
-# MSTest test Results
-[Tt]est[Rr]esult*/
-[Bb]uild[Ll]og.*
-
-# NUNIT
-*.VisualState.xml
-TestResult.xml
-
-# Build Results of an ATL Project
-[Dd]ebugPS/
-[Rr]eleasePS/
-dlldata.c
-
-# DNX
-project.lock.json
-project.fragment.lock.json
-artifacts/
-
-*_i.c
-*_p.c
-*_i.h
-*.ilk
-*.meta
-*.obj
-*.pch
-*.pdb
-*.pgc
-*.pgd
-*.rsp
-*.sbr
-*.tlb
-*.tli
-*.tlh
-*.tmp
-*.tmp_proj
-*.log
-*.vspscc
-*.vssscc
-.builds
-*.pidb
-*.svclog
-*.scc
-
-# Chutzpah Test files
-_Chutzpah*
-
-# Visual C++ cache files
-ipch/
-*.aps
-*.ncb
-*.opendb
-*.opensdf
-*.sdf
-*.cachefile
-*.VC.db
-*.VC.VC.opendb
-
-# Visual Studio profiler
-*.psess
-*.vsp
-*.vspx
-*.sap
-
-# TFS 2012 Local Workspace
-$tf/
-
-# Guidance Automation Toolkit
-*.gpState
-
-# ReSharper is a .NET coding add-in
-_ReSharper*/
-*.[Rr]e[Ss]harper
-*.DotSettings.user
-
-# JustCode is a .NET coding add-in
-.JustCode
-
-# TeamCity is a build add-in
-_TeamCity*
-
-# DotCover is a Code Coverage Tool
-*.dotCover
-
-# NCrunch
-_NCrunch_*
-.*crunch*.local.xml
-nCrunchTemp_*
-
-# MightyMoose
-*.mm.*
-AutoTest.Net/
-
-# Web workbench (sass)
-.sass-cache/
-
-# Installshield output folder
-[Ee]xpress/
-
-# DocProject is a documentation generator add-in
-DocProject/buildhelp/
-DocProject/Help/*.HxT
-DocProject/Help/*.HxC
-DocProject/Help/*.hhc
-DocProject/Help/*.hhk
-DocProject/Help/*.hhp
-DocProject/Help/Html2
-DocProject/Help/html
-
-# Click-Once directory
-publish/
-
-# Publish Web Output
-*.[Pp]ublish.xml
-*.azurePubxml
-# TODO: Comment the next line if you want to checkin your web deploy settings
-# but database connection strings (with potential passwords) will be unencrypted
-#*.pubxml
-*.publishproj
-
-# Microsoft Azure Web App publish settings. Comment the next line if you want to
-# checkin your Azure Web App publish settings, but sensitive information contained
-# in these scripts will be unencrypted
-PublishScripts/
-
-# NuGet Packages
-*.nupkg
-# The packages folder can be ignored because of Package Restore
-**/packages/*
-# except build/, which is used as an MSBuild target.
-!**/packages/build/
-# Uncomment if necessary however generally it will be regenerated when needed
-#!**/packages/repositories.config
-# NuGet v3's project.json files produces more ignoreable files
-*.nuget.props
-*.nuget.targets
-
-# Microsoft Azure Build Output
-csx/
-*.build.csdef
-
-# Microsoft Azure Emulator
-ecf/
-rcf/
-
-# Windows Store app package directories and files
-AppPackages/
-BundleArtifacts/
-Package.StoreAssociation.xml
-_pkginfo.txt
-
-# Visual Studio cache files
-# files ending in .cache can be ignored
-*.[Cc]ache
-# but keep track of directories ending in .cache
-!*.[Cc]ache/
-
-# Others
-ClientBin/
-~$*
-*~
-*.dbmdl
-*.dbproj.schemaview
-*.jfm
-*.pfx
-*.publishsettings
-node_modules/
-orleans.codegen.cs
-
-# Since there are multiple workflows, uncomment next line to ignore bower_components
-# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
-#bower_components/
-
-# RIA/Silverlight projects
-Generated_Code/
-
-# Backup & report files from converting an old project file
-# to a newer Visual Studio version. Backup files are not needed,
-# because we have git ;-)
-_UpgradeReport_Files/
-Backup*/
-UpgradeLog*.XML
-UpgradeLog*.htm
-
-# SQL Server files
-*.mdf
-*.ldf
-
-# Business Intelligence projects
-*.rdl.data
-*.bim.layout
-*.bim_*.settings
-
-# Microsoft Fakes
-FakesAssemblies/
-
-# GhostDoc plugin setting file
-*.GhostDoc.xml
-
-# Node.js Tools for Visual Studio
-.ntvs_analysis.dat
-
-# Visual Studio 6 build log
-*.plg
-
-# Visual Studio 6 workspace options file
-*.opt
-
-# Visual Studio LightSwitch build output
-**/*.HTMLClient/GeneratedArtifacts
-**/*.DesktopClient/GeneratedArtifacts
-**/*.DesktopClient/ModelManifest.xml
-**/*.Server/GeneratedArtifacts
-**/*.Server/ModelManifest.xml
-_Pvt_Extensions
-
-# Paket dependency manager
-.paket/paket.exe
-paket-files/
-
-# FAKE - F# Make
-.fake/
-
-# JetBrains Rider
-.idea/
-*.sln.iml
-
-# CodeRush
-.cr/
-
-# Python Tools for Visual Studio (PTVS)
-__pycache__/
-*.pyc
-plugin/
-api-demo-python.py
-binit.py
-code_v.py
-demo.py
-tocc.sh
-*.user
-*.pubxml
-*.pyproj
-*.sln
\ No newline at end of file
diff --git a/BTPanel.pyproj b/BTPanel.pyproj
deleted file mode 100644
index d4114035..00000000
--- a/BTPanel.pyproj
+++ /dev/null
@@ -1,1365 +0,0 @@
-
-
-
- 10.0
- Debug
- 2.0
- 971a9e98-428e-48cb-89f1-9042336ab2e1
- .
- {789894c7-04a9-4a11-a6b5-3f4435165112};{1b580a1a-fdb3-4b32-83e1-6407eb2722e6};{349c5851-65df-11da-9384-00065b846f21};{888888a0-9f3d-457c-b088-3a5042f75d52}
- runserver.py
-
-
- .
- Web launcher
- http://localhost
- .
- true
- BTPanel
- BTPanel
-
-
-
-
-
-
- true
- false
-
-
- true
- false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Code
-
-
-
-
-
- Code
-
-
-
- Code
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Code
-
-
-
-
- Code
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- True
- True
- http://localhost
- False
-
-
-
-
-
-
- CurrentPage
- True
- False
- False
- False
-
-
-
-
-
-
-
-
- False
- False
-
-
-
-
-
\ No newline at end of file
diff --git a/BTPanel.sln b/BTPanel.sln
deleted file mode 100644
index 3ca1d184..00000000
--- a/BTPanel.sln
+++ /dev/null
@@ -1,25 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27703.2035
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "BTPanel", "BTPanel.pyproj", "{971A9E98-428E-48CB-89F1-9042336AB2E1}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {971A9E98-428E-48CB-89F1-9042336AB2E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {971A9E98-428E-48CB-89F1-9042336AB2E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {971A9E98-428E-48CB-89F1-9042336AB2E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {971A9E98-428E-48CB-89F1-9042336AB2E1}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {0583A78D-D302-4B1D-A28C-677ED3263CE4}
- EndGlobalSection
-EndGlobal
From b9f97abcff3425deac5bb687a09c55a3f8c91f03 Mon Sep 17 00:00:00 2001
From: "bt.cn" <287962566@qq.com>
Date: Fri, 21 Jun 2019 16:30:25 +0800
Subject: [PATCH 22/79] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=9D=A2=E6=9D=BF?=
=?UTF-8?q?=E8=BF=90=E8=A1=8C=E6=97=A5=E5=BF=97=E6=9F=A5=E7=9C=8B=E6=8C=89?=
=?UTF-8?q?=E9=92=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
BTPanel/__init__.py | 2 +-
BTPanel/static/js/config.js | 2 +-
BTPanel/templates/default/firewall.html | 44 ++++++++++++++++++++++++-
class/config.py | 20 ++++++++---
4 files changed, 60 insertions(+), 8 deletions(-)
diff --git a/BTPanel/__init__.py b/BTPanel/__init__.py
index bfee4684..4de1f2d9 100644
--- a/BTPanel/__init__.py
+++ b/BTPanel/__init__.py
@@ -379,7 +379,7 @@ def config(pdata = None):
if data['basic_auth']['open']: data['basic_auth']['value'] = '已开启'
return render_template( 'config.html',data=data)
import config
- defs = ('get_basic_auth_stat','set_basic_auth','get_cli_php_version','get_tmp_token','set_cli_php_version','DelOldSession', 'GetSessionCount', 'SetSessionConf', 'GetSessionConf','get_ipv6_listen','set_ipv6_status','GetApacheValue','SetApacheValue','GetNginxValue','SetNginxValue','get_token','set_token','set_admin_path','is_pro','get_php_config','get_config','SavePanelSSL','GetPanelSSL','GetPHPConf','SetPHPConf','GetPanelList','AddPanelInfo','SetPanelInfo','DelPanelInfo','ClickPanelInfo','SetPanelSSL','SetTemplates','Set502','setPassword','setUsername','setPanel','setPathInfo','setPHPMaxSize','getFpmConfig','setFpmConfig','setPHPMaxTime','syncDate','setPHPDisable','SetControl','ClosePanel','AutoUpdatePanel','SetPanelLock')
+ defs = ('get_panel_error_logs','clean_panel_error_logs','get_basic_auth_stat','set_basic_auth','get_cli_php_version','get_tmp_token','set_cli_php_version','DelOldSession', 'GetSessionCount', 'SetSessionConf', 'GetSessionConf','get_ipv6_listen','set_ipv6_status','GetApacheValue','SetApacheValue','GetNginxValue','SetNginxValue','get_token','set_token','set_admin_path','is_pro','get_php_config','get_config','SavePanelSSL','GetPanelSSL','GetPHPConf','SetPHPConf','GetPanelList','AddPanelInfo','SetPanelInfo','DelPanelInfo','ClickPanelInfo','SetPanelSSL','SetTemplates','Set502','setPassword','setUsername','setPanel','setPathInfo','setPHPMaxSize','getFpmConfig','setFpmConfig','setPHPMaxTime','syncDate','setPHPDisable','SetControl','ClosePanel','AutoUpdatePanel','SetPanelLock')
return publicObject(config.config(),defs,None,pdata);
@app.route('/ajax',methods=method_all)
diff --git a/BTPanel/static/js/config.js b/BTPanel/static/js/config.js
index a11f3fc0..6e962e5a 100644
--- a/BTPanel/static/js/config.js
+++ b/BTPanel/static/js/config.js
@@ -582,4 +582,4 @@ function modify_basic_auth() {
'
})
});
-}
\ No newline at end of file
+}
diff --git a/BTPanel/templates/default/firewall.html b/BTPanel/templates/default/firewall.html
index 9720b600..ba19c7f2 100644
--- a/BTPanel/templates/default/firewall.html
+++ b/BTPanel/templates/default/firewall.html
@@ -101,6 +101,7 @@ {{data['lan']['H3']}}
@@ -288,7 +289,48 @@
{{data['lan']['H4']}}
data:rdata.data
})
})
- }
+ },
+ //查看面板运行日志
+ get_panel_error_logs: function () {
+ layer.msg(lan.public.the_get, { icon: 16, time: 0, shade: [0.3, '#000'] });
+ $.post('/config?action=get_panel_error_logs', {}, function (rdata) {
+ layer.closeAll();
+ if (!rdata.status) {
+ layer.msg(rdata.msg, { icon: 2 });
+ return;
+ };
+ layer.open({
+ type: 1,
+ title: '面板运行日志',
+ area: ['700px', '490px'],
+ shadeClose: false,
+ closeBtn: 2,
+ content: '
'
+ });
+ setTimeout(function () {
+ $("#crontab-log").text(rdata.msg);
+ var div = document.getElementsByClassName('crontab-log')[0]
+ div.scrollTop = div.scrollHeight;
+ }, 200)
+ }).error(function () {
+ layer.closeAll();
+ layer.msg('无法取回日志信息!', { icon: 2 });
+ });
+ },
+ //清空面板错误日志
+ clean_panel_error_logs:function() {
+ layer.msg(lan.public.the_get, { icon: 16, time: 0, shade: [0.3, '#000'] });
+ $.post('/config?action=clean_panel_error_logs', {}, function (rdata) {
+ layer.closeAll();
+ layer.msg(rdata.msg, { icon: 2 });
+ });
+ }
}
firewall.get_init();
diff --git a/class/config.py b/class/config.py
index 61a4c538..a76094a0 100644
--- a/class/config.py
+++ b/class/config.py
@@ -736,7 +736,6 @@ def is_pro(self,get):
return pluginInfo
def get_token(self,get):
- import json
save_path = '/www/server/panel/config/api.json'
if not os.path.exists(save_path):
data = { "open":False, "token":"", "limit_addr":[] }
@@ -748,9 +747,6 @@ def get_token(self,get):
return data
def set_token(self,get):
- import json
- #panel_password = public.M('users').where('id=?',(1,)).getField('password')
- #if not public.md5(get.panel_password.strip()) == panel_password: return public.returnMsg(False,'面板密码错误!')
if 'request_token' in get: return public.returnMsg(False,'不能通过API接口配置API')
save_path = '/www/server/panel/config/api.json'
data = json.loads(public.ReadFile(save_path))
@@ -857,6 +853,7 @@ def set_cli_php_version(self,get):
public.ExecShell("ln -sf %s %s" % (php_pecl_src,php_pecl))
public.ExecShell("ln -sf %s %s" % (php_pear_src,php_pear))
if is_chattr != -1: public.ExecShell('chattr +i /usr/bin')
+ public.WriteLog('面板设置','设置PHP-CLI版本为: %s' % get.php_version)
return public.returnMsg(True,'设置成功!')
@@ -888,6 +885,19 @@ def set_basic_auth(self,get):
public.writeFile(path,json.dumps(ba_conf))
os.chmod(path,384)
+ public.WriteLog('面板设置','设置BasicAuth状态为: %s' % is_open)
public.writeFile('data/reload.pl','True')
return public.returnMsg(True,"设置成功!")
-
\ No newline at end of file
+
+ #取面板运行日志
+ def get_panel_error_logs(self,get):
+ filename = 'logs/error.log'
+ if not os.path.exists(filename): return public.returnMsg(False,'没有找到运行日志')
+ result = public.GetNumLines(filename,2000)
+ return public.returnMsg(True,result)
+ #清空面板运行日志
+ def clean_panel_error_logs(self,get):
+ filename = 'logs/error.log'
+ public.writeFile(filename,'')
+ public.WriteLog('面板配置','清空面板运行日志')
+ public.returnMsg(True,'已清空!')
\ No newline at end of file
From d4518807885d2cde1fa106aa6fb466d7b580242e Mon Sep 17 00:00:00 2001
From: "bt.cn" <287962566@qq.com>
Date: Fri, 21 Jun 2019 16:48:52 +0800
Subject: [PATCH 23/79] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=80=E9=94=AE?=
=?UTF-8?q?=E9=83=A8=E7=BD=B2=E4=B8=AD=E5=AF=BC=E5=85=A5=E7=9A=84=E8=87=AA?=
=?UTF-8?q?=E5=AE=9A=E4=B9=89=E9=A1=B9=E7=9B=AE=E7=9A=84=E5=88=A0=E9=99=A4?=
=?UTF-8?q?=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
BTPanel/static/js/soft.js | 18 ++++++++++++++++--
BTPanel/templates/default/firewall.html | 4 ++--
class/config.py | 2 +-
3 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/BTPanel/static/js/soft.js b/BTPanel/static/js/soft.js
index 225c90fc..7e9c1492 100644
--- a/BTPanel/static/js/soft.js
+++ b/BTPanel/static/js/soft.js
@@ -350,17 +350,21 @@ var soft = {
简介 | \
支持PHP版本 | \
提供者 | \
-
操作 | \
+
操作 | \
\
';
for (var i = 0; i < rdata.list.length; i++) {
+ var remove_opt = '';
+ if (rdata.list[i].id === 0) {
+ remove_opt = ' |
删除';
+ }
zbody += '
'
+ ' ' + rdata.list[i].title + ' | '
+ '' + rdata.list[i].version + ' | '
+ '' + rdata.list[i].ps + ' | '
+ '' + rdata.list[i].php + ' | '
+ '' + (rdata.list[i].author == '宝塔' ? rdata.list[i].title : rdata.list[i].author) + ' | '
- + '一键部署 | '
+ + '一键部署' + remove_opt+' | '
+ '
'
}
$("#softList").html(zbody);
@@ -368,6 +372,16 @@ var soft = {
});
},
+ remove_other_dep: function (name) {
+ bt.show_confirm('删除自定义项目', '您真的要删除[' + name + ']吗?', function () {
+ var loadT = layer.msg('正在删除,请稍候...', { icon: 16, time: 0, shade: 0.3 });
+ $.post('/deployment?action=DelPackage', { dname: name }, function (rdata) {
+ layer.close(loadT);
+ if (rdata.status) soft.get_dep_list();
+ setTimeout(function () { layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 }); }, 1000);
+ });
+ });
+ },
input_package: function () {
var con = '
\
\
- '
}else{
$(".planname input[name='name']").val(sMsg+'[/www/wwwroot/]');
sOptBody = '
'
@@ -819,6 +819,14 @@ function toBackup(type){
\
'+lan.crontab.save_num+'\
';
+ if (sType == 'sites') {
+ sBody += '\
+
排除目录
\
+ \
+ \
+
\
+
';
+ }
$("#implement").html(sBody);
getselectname();
$(".dropdown ul li a").click(function(){
diff --git a/BTPanel/static/js/files.js b/BTPanel/static/js/files.js
index 0abb23f6..297a7ba1 100644
--- a/BTPanel/static/js/files.js
+++ b/BTPanel/static/js/files.js
@@ -826,7 +826,7 @@ function BatchPasteTo(data,path){
}
function GetExtName(fileName){
var extArr = fileName.split(".");
- var exts = ['folder','folder-unempty','sql','c','cpp','cs','flv','css','js','htm','html','java','log','mht','php','url','xml','ai','bmp','cdr','gif','ico','jpeg','jpg','JPG','png','psd','webp','ape','avi','flv','mkv','mov','mp3','mp4','mpeg','mpg','rm','rmvb','swf','wav','webm','wma','wmv','rtf','docx','fdf','potm','pptx','txt','xlsb','xlsx','7z','cab','iso','rar','zip','gz','bt','file','apk','bookfolder','folder','folder-empty','folder-unempty','fromchromefolder','documentfolder','fromphonefolder','mix','musicfolder','picturefolder','videofolder','sefolder','access','mdb','accdb','sql','c','cpp','cs','js','fla','flv','htm','html','java','log','mht','php','url','xml','ai','bmp','cdr','gif','ico','jpeg','jpg','JPG','png','psd','webp','ape','avi','flv','mkv','mov','mp3','mp4','mpeg','mpg','rm','rmvb','swf','wav','webm','wma','wmv','doc','docm','dotx','dotm','dot','rtf','docx','pdf','fdf','ppt','pptm','pot','potm','pptx','txt','xls','csv','xlsm','xlsb','xlsx','7z','gz','cab','iso','rar','zip','bt','file','apk','css'];
+ var exts = ['folder','folder-unempty','sql','c','cpp','cs','flv','css','js','htm','html','java','log','mht','php','url','xml','ai','bmp','cdr','gif','ico','jpeg','jpg','JPG','png','psd','webp','ape','avi','flv','mkv','mov','mp3','mp4','mpeg','mpg','rm','rmvb','swf','wav','webm','wma','wmv','rtf','docx','fdf','potm','pptx','txt','xlsb','xlsx','7z','cab','iso','bz2','rar','zip','gz','bt','file','apk','bookfolder','folder','folder-empty','folder-unempty','fromchromefolder','documentfolder','fromphonefolder','mix','musicfolder','picturefolder','videofolder','sefolder','access','mdb','accdb','sql','c','cpp','cs','js','fla','flv','htm','html','java','log','mht','php','url','xml','ai','bmp','cdr','gif','ico','jpeg','jpg','JPG','png','psd','webp','ape','avi','flv','mkv','mov','mp3','mp4','mpeg','mpg','rm','rmvb','swf','wav','webm','wma','wmv','doc','docm','dotx','dotm','dot','rtf','docx','pdf','fdf','ppt','pptm','pot','potm','pptx','txt','xls','csv','xlsm','xlsb','xlsx','7z','gz','cab','iso','rar','zip','bt','file','apk','css'];
var extLastName = extArr[extArr.length - 1];
for(var i=0; i 1:
+ exports = param['sBody'].replace("\r\n","\n").replace("\n",",")
+ head += "BT_EXCLUDE=\"" + exports.strip() + "\"\nexport BT_EXCLUDE\n"
wheres={
'path': head + "python " + public.GetConfigValue('setup_path')+"/panel/script/backup.py path "+param['sName']+" "+str(param['save']),
'site' : head + "python " + public.GetConfigValue('setup_path')+"/panel/script/backup.py site "+param['sName']+" "+str(param['save']),
diff --git a/class/panelTask.py b/class/panelTask.py
index b05c1cbb..5a833d87 100644
--- a/class/panelTask.py
+++ b/class/panelTask.py
@@ -257,6 +257,8 @@ def _unzip(self,sfile,dfile,password,log_file):
os.system('echo "'+password+'"|' + rar_file + ' x -u -y "' + sfile + '" "' + dfile + '" &> ' + log_file)
elif sfile[-4:] == '.war':
os.system("unzip -P '"+password+"' -o '" + sfile + "' -d '" + dfile + "' &> " + log_file)
+ elif sfile[-4:] == '.bz2':
+ os.system("tar jxvf '" + sfile + "' -C '" + dfile + "' &> " + log_file)
else:
os.system("gunzip -c " + sfile + " > " + sfile[:-3])
diff --git a/runserver.py b/runserver.py
index 327f707f..072f8f05 100644
--- a/runserver.py
+++ b/runserver.py
@@ -10,6 +10,8 @@
from BTPanel import app,socketio,sys
if __name__ == '__main__':
- PORT = 8888
+ f = open('data/port.pl')
+ PORT = int(f.read())
HOST = '0.0.0.0'
+ f.close()
socketio.run(app,host=HOST,port=PORT)
diff --git a/script/backup.py b/script/backup.py
index 25df150b..cec2a265 100644
--- a/script/backup.py
+++ b/script/backup.py
@@ -13,7 +13,11 @@
import public,db,time
class backupTools:
-
+ __exclude = ""
+
+ def __init__(self):
+ self.get_exclode()
+
def backupSite(self,name,count):
sql = db.Sql();
path = sql.table('sites').where('name=?',(name,)).getField('path');
@@ -27,9 +31,8 @@ def backupSite(self,name,count):
backup_path = sql.table('config').where("id=?",(1,)).getField('backup_path') + '/site';
if not os.path.exists(backup_path): public.ExecShell("mkdir -p " + backup_path);
-
filename= backup_path + "/Web_" + name + "_" + time.strftime('%Y%m%d_%H%M%S',time.localtime()) + '.tar.gz'
- public.ExecShell("cd " + os.path.dirname(path) + " && tar zcvf '" + filename + "' '" + os.path.basename(path) + "' > /dev/null")
+ public.ExecShell("cd " + os.path.dirname(path) + " && tar zcvf '" + filename + "' '" + os.path.basename(path) + "'"+self.__exclude +" > /dev/null")
endDate = time.strftime('%Y/%m/%d %X',time.localtime())
@@ -48,6 +51,7 @@ def backupSite(self,name,count):
print(u"★["+endDate+"] " + log)
print(u"|---保留最新的["+count+u"]份备份")
print(u"|---文件名:"+filename)
+ if self.__exclude: print(u"|---排除规则: " + self.__exclude)
#清理多余备份
backups = sql.table('backup').where('type=? and pid=? and filename!=? and filename!=? and filename!=? and filename!=? and filename!=?',('0',pid,'alioss','txcos','upyun','qiniu','ftp')).field('id,filename').select();
@@ -134,7 +138,7 @@ def backupPath(self,path,count):
backup_path = sql.table('config').where("id=?",(1,)).getField('backup_path') + '/path';
if not os.path.exists(backup_path): os.makedirs(backup_path);
filename= backup_path + "/Path_" + name + "_" + time.strftime('%Y%m%d_%H%M%S',time.localtime()) + '.tar.gz'
- os.system("cd " + os.path.dirname(path) + " && tar zcvf '" + filename + "' '" + os.path.basename(path) + "' > /dev/null")
+ os.system("cd " + os.path.dirname(path) + " && tar zcvf '" + filename + "' '" + os.path.basename(path) + "'" + self.__exclude + " > /dev/null")
endDate = time.strftime('%Y/%m/%d %X',time.localtime())
if not os.path.exists(filename):
@@ -150,6 +154,7 @@ def backupPath(self,path,count):
print(u"★["+endDate+"] " + log)
print(u"|---保留最新的["+count+u"]份备份")
print(u"|---文件名:"+filename)
+ if self.__exclude: print(u"|---排除规则: " + self.__exclude)
#清理多余备份
backups = sql.table('backup').where('type=? and pid=? and name=?',('2',0,path)).field('id,filename').select();
@@ -174,7 +179,14 @@ def backupDatabaseAll(self,save):
for database in databases:
self.backupDatabase(database['name'],save)
-
+ def get_exclode(self):
+ tmp_exclude = os.getenv('BT_EXCLUDE')
+ if not tmp_exclude: return ""
+ for ex in tmp_exclude.split(','):
+ self.__exclude += " --exclude=\"" + ex + "\""
+ self.__exclude += " "
+ return self.__exclude
+
if __name__ == "__main__":
From 087ff05042423b6424213f0e8109223c90e1cbe4 Mon Sep 17 00:00:00 2001
From: "bt.cn" <287962566@qq.com>
Date: Mon, 24 Jun 2019 10:29:35 +0800
Subject: [PATCH 28/79] =?UTF-8?q?=E8=AE=A1=E5=88=92=E4=BB=BB=E5=8A=A1?=
=?UTF-8?q?=E5=A4=87=E4=BB=BD=E7=BD=91=E7=AB=99=E5=92=8C=E7=9B=AE=E5=BD=95?=
=?UTF-8?q?=E6=97=B6=E6=8F=90=E4=BE=9B=E6=96=87=E4=BB=B6=E7=9B=AE=E5=BD=95?=
=?UTF-8?q?=E7=9A=84=E6=8E=92=E9=99=A4=E8=A7=84=E5=88=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../css/315302-20170205164840214-221836365.png | Bin 18551 -> 0 bytes
BTPanel/static/js/crontab.js | 4 ++--
BTPanel/templates/default/crontab.html | 1 +
3 files changed, 3 insertions(+), 2 deletions(-)
delete mode 100644 BTPanel/static/css/315302-20170205164840214-221836365.png
diff --git a/BTPanel/static/css/315302-20170205164840214-221836365.png b/BTPanel/static/css/315302-20170205164840214-221836365.png
deleted file mode 100644
index bbe1668624a9344092d4bf4ff7374281aefeed5c..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 18551
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
hVz~QAEvEUf&&XSzw1JM@UDv=953yIKiWxMS98
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
diff --git a/BTPanel/static/js/crontab.js b/BTPanel/static/js/crontab.js
index 20960932..78bdd0d0 100644
--- a/BTPanel/static/js/crontab.js
+++ b/BTPanel/static/js/crontab.js
@@ -214,7 +214,7 @@ function edit_task_info(id){
\
\
\
-
脚本内容\
+
'+ (obj.from.sType == "toShell" ?'脚本内容':'排除规则')+'\
\
\
\
@@ -821,7 +821,7 @@ function toBackup(type){
';
if (sType == 'sites') {
sBody += '\
-
排除目录
\
+ 排除规则
\
\
\
\
diff --git a/BTPanel/templates/default/crontab.html b/BTPanel/templates/default/crontab.html
index 3e2fc49b..3e5ebc39 100644
--- a/BTPanel/templates/default/crontab.html
+++ b/BTPanel/templates/default/crontab.html
@@ -122,6 +122,7 @@ {{data['lan']['H3']}}
- 当添加完备份任务,应该手动运行一次,并检查备份包是否完整
- 磁盘容量不够、数据库密码错误、网络不稳定等原因,可能导致数据备份不完整
+ - 备份站点和目录时支持文件或目录排除,请将需要排除功能的插件升级到最新版,如:阿里云OSS等