mirror of
https://github.com/midoks/mdserver-web.git
synced 2026-10-11 03:19:26 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7589c14f81 | ||
|
|
4344d774c1 | ||
|
|
4859792096 | ||
|
|
e55c40e973 | ||
|
|
103beb62a4 | ||
|
|
76a34578ad | ||
|
|
f82fdbf939 | ||
|
|
4eaf9eb36c | ||
|
|
9c9f9fc42c | ||
|
|
8301ad6f62 | ||
|
|
d42fb48749 | ||
|
|
fa49a3dbeb | ||
|
|
dd1147c891 | ||
|
|
67b015a50b | ||
|
|
57831168a3 | ||
|
|
f6f7cabddc | ||
|
|
dfec241c3f | ||
|
|
8a78dff571 | ||
|
|
a9486d4fbe | ||
|
|
78d3a091cd | ||
|
|
314005e478 | ||
|
|
55fa911485 | ||
|
|
a72046462c | ||
|
|
0b8fe15b65 | ||
|
|
34f5d12ad9 | ||
|
|
e88544d290 | ||
|
|
a211746de7 | ||
|
|
c417b02844 | ||
|
|
034aaedf48 | ||
|
|
af0ec79072 | ||
|
|
195ccf409e | ||
|
|
7cec26b8a3 | ||
|
|
aacb816b11 | ||
|
|
411798f4bf | ||
|
|
2179db5f8b | ||
|
|
dcced8c0fb | ||
|
|
3e0e42d8a1 | ||
|
|
e5355d3e2f | ||
|
|
0a22e25611 | ||
|
|
5f7a3e5bf6 | ||
|
|
3518548c61 | ||
|
|
08c4b0845d | ||
|
|
8f5fae8e79 | ||
|
|
a151db1c30 | ||
|
|
628c69ed22 | ||
|
|
13bcbc0f3e | ||
|
|
c94838462c | ||
|
|
a147ef6962 | ||
|
|
4ccda15933 | ||
|
|
01074c743d | ||
|
|
0871fa1763 | ||
|
|
aade0ccd98 | ||
|
|
4aed2f91de | ||
|
|
d49dd9f2ac | ||
|
|
cff29194f4 | ||
|
|
ecbfb2500f | ||
|
|
9c43170d4b | ||
|
|
1239a2807f | ||
|
|
1c0a130b49 | ||
|
|
ffb1eb34e0 | ||
|
|
82874d1f7a | ||
|
|
4e05f29fcd | ||
|
|
d5f3b0d442 | ||
|
|
81eec04037 | ||
|
|
5a5dc43e17 | ||
|
|
b4eb2b3192 | ||
|
|
2d1c070e1b | ||
|
|
81364fdfa3 | ||
|
|
9d0d88d465 | ||
|
|
7e2eef8bbf | ||
|
|
8d1315e5be | ||
|
|
fe6a51540e | ||
|
|
6e35683505 | ||
|
|
713c0d1a3c | ||
|
|
8323e0ec73 | ||
|
|
6eae94658f | ||
|
|
07d173d2cf | ||
|
|
23f2b9efac | ||
|
|
9b2ab9276c | ||
|
|
7903e1a286 | ||
|
|
662e05511f | ||
|
|
1f8785acbc | ||
|
|
3eb87cf953 | ||
|
|
124b24885e | ||
|
|
2196983455 | ||
|
|
80a67c4f58 | ||
|
|
ff06f7ef91 | ||
|
|
b16506c8bc | ||
|
|
2d3801dcc0 | ||
|
|
9b83a2ef79 | ||
|
|
6aefa3b7dc | ||
|
|
566fabbf24 | ||
|
|
ea8aa5102b | ||
|
|
b8421d36ae | ||
|
|
24bd8daca0 | ||
|
|
d8047b43fa | ||
|
|
016dde04e7 | ||
|
|
df5d86a883 | ||
|
|
84077de5d1 | ||
|
|
04ed4b180a | ||
|
|
f980dba7ed | ||
|
|
f702f70f89 | ||
|
|
a8e6ee052c | ||
|
|
b3d0a36dcd | ||
|
|
96275303c6 | ||
|
|
0337a1bded | ||
|
|
8bd985fca9 | ||
|
|
b6ef8d1625 | ||
|
|
3dc695508f | ||
|
|
0c769b02e5 | ||
|
|
e289037598 | ||
|
|
63e6a95553 | ||
|
|
8e1d95bf82 | ||
|
|
24fe8b6f5f | ||
|
|
3d366ee774 | ||
|
|
0428956141 | ||
|
|
37747427be | ||
|
|
fb94fb8304 | ||
|
|
65d07d3934 | ||
|
|
5e6ffafeb5 | ||
|
|
572f231fae | ||
|
|
0328dd21e7 | ||
|
|
597d171733 | ||
|
|
745ab9dcd0 | ||
|
|
30323b031c | ||
|
|
f47e6a47df | ||
|
|
0eccebd9da | ||
|
|
0ad5e74fae | ||
|
|
2640ba97c5 | ||
|
|
e5f440ff02 | ||
|
|
7bc9c44ec1 | ||
|
|
9cd74db011 | ||
|
|
5da8e5a7f6 | ||
|
|
4da895b8df | ||
|
|
42eca14168 | ||
|
|
43a3dfd9bd | ||
|
|
794eba4186 | ||
|
|
a4f533acba | ||
|
|
adb3c5250c | ||
|
|
e4226fcdd4 | ||
|
|
d3e9353589 | ||
|
|
757284cdf1 | ||
|
|
58232e10ab | ||
|
|
fde211e026 | ||
|
|
c9a527e487 | ||
|
|
c501efdfac | ||
|
|
80c0bbed71 | ||
|
|
1fb3c30775 | ||
|
|
24ab203770 | ||
|
|
bd0242db2f | ||
|
|
42bf5edd1f | ||
|
|
7b2a011b6a | ||
|
|
76e01201a2 | ||
|
|
16e45cabfc | ||
|
|
c08542ff54 | ||
|
|
5beb76d0b7 | ||
|
|
f16a7e016e | ||
|
|
eb86ac3ee6 | ||
|
|
14c2606532 | ||
|
|
86b8939cb8 | ||
|
|
dd28c1ef56 | ||
|
|
6b24dfc21e | ||
|
|
dc06573125 | ||
|
|
df35e5a780 | ||
|
|
a678d851a0 | ||
|
|
6a706651e4 | ||
|
|
1acdfe4368 | ||
|
|
cae245efca | ||
|
|
238f1e76d8 | ||
|
|
f3a754d1ae | ||
|
|
21aab0573a | ||
|
|
011949ba85 | ||
|
|
f3e7dd1cc0 | ||
|
|
b49d2025eb | ||
|
|
556b0869f2 | ||
|
|
aad6deeb78 | ||
|
|
64601e42c1 | ||
|
|
6555d927ea | ||
|
|
444ff40570 | ||
|
|
7bdcd0ac2b | ||
|
|
6e6a41e6df | ||
|
|
feca2a6d33 | ||
|
|
5e382e7347 | ||
|
|
abc778fb52 | ||
|
|
6b42d35cd4 | ||
|
|
c74a2c9655 | ||
|
|
01543f951a | ||
|
|
d78a5d8f27 | ||
|
|
2a1d759cd2 | ||
|
|
43889f83f7 | ||
|
|
79a0a93959 | ||
|
|
735cf9b872 | ||
|
|
e7c318e560 | ||
|
|
78d03754f6 | ||
|
|
67cc1cac86 | ||
|
|
77ec90980a | ||
|
|
d07b2babfd | ||
|
|
4d9ee94038 | ||
|
|
61479d5db6 | ||
|
|
897c28034d | ||
|
|
b3fef4c104 | ||
|
|
48cec8ee47 | ||
|
|
7c369ef19f | ||
|
|
1411bb1639 | ||
|
|
be875d9d8c | ||
|
|
746dc7ee4d | ||
|
|
ea7ba7d461 | ||
|
|
48ed4156b5 | ||
|
|
ca73d0e280 | ||
|
|
8cef43d9a7 | ||
|
|
75445774a1 | ||
|
|
9b29f19b96 | ||
|
|
1e6655e7f9 | ||
|
|
363656e06c | ||
|
|
a1860bc4fc | ||
|
|
f8ce39bc74 | ||
|
|
969d02ef93 | ||
|
|
a54410df6e | ||
|
|
01e388ea45 | ||
|
|
ef75f22a86 | ||
|
|
97f6b232fd | ||
|
|
2506f5e940 | ||
|
|
dcb23ada41 | ||
|
|
35e1bf048c | ||
|
|
a9e24f8eaf | ||
|
|
2f4ac74f52 | ||
|
|
522122feb6 | ||
|
|
a3c677a926 | ||
|
|
fd1c52530e | ||
|
|
071c690583 | ||
|
|
67c9cd0277 | ||
|
|
61292868ad | ||
|
|
54b2a00b23 | ||
|
|
af6d377664 | ||
|
|
6d55e345b0 | ||
|
|
fab4e68d8d | ||
|
|
8864e91f21 | ||
|
|
f14ce1b66c | ||
|
|
48098efd56 | ||
|
|
04eba8e33f | ||
|
|
89cf7ffafc | ||
|
|
47544520e8 | ||
|
|
bc1fd9a8af | ||
|
|
27efc7ef6e | ||
|
|
47ead816c0 | ||
|
|
31d36182c3 | ||
|
|
c9a58c7ea5 | ||
|
|
a6e59ae37c | ||
|
|
328e1b0ff1 | ||
|
|
f76cc5ceb8 | ||
|
|
d6c74c3f7d | ||
|
|
4f932c36e7 | ||
|
|
0d02d0ebea | ||
|
|
9e207ad4d3 | ||
|
|
f6cfe29956 | ||
|
|
e439111761 | ||
|
|
e576d0b443 | ||
|
|
02e2c42225 | ||
|
|
45dec0a3d6 | ||
|
|
28e2abc829 | ||
|
|
d59c82b7c8 | ||
|
|
32b2158795 | ||
|
|
5a37305c73 | ||
|
|
c043963e8e | ||
|
|
40d755b44e | ||
|
|
00aa791205 | ||
|
|
431b3646af | ||
|
|
910aaa81de |
@@ -0,0 +1,5 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: midoks
|
||||
|
||||
custom: https://afdian.net/a/mdserver-web
|
||||
@@ -65,6 +65,8 @@ phpMyAdmin[5.2.0]支持MySQL[8.0]
|
||||
|
||||
PHP[53-72]支持phpMyAdmin[4.4.15]
|
||||
PHP[72-81]支持phpMyAdmin[5.2.0]
|
||||
|
||||
|
||||
```
|
||||
|
||||
# 特别赞助
|
||||
@@ -78,7 +80,7 @@ PHP[72-81]支持phpMyAdmin[5.2.0]
|
||||
| 服务商 | LOGO | 推广地址 | 优惠码 |
|
||||
| ------------- |----------|-----------|-------|
|
||||
| digitalvirt |[](https://digitalvirt.com/aff.php?aff=154) | https://digitalvirt.com/aff.php?aff=154 | 9SYDY7UH0U |
|
||||
| 搬瓦工 |[](https://bandwagonhost.com/aff.php?aff=54161) | https://bandwagonhost.com/aff.php?aff=54161 | BWH3HYATVBJW |
|
||||
| 搬瓦工 |[](https://bwh81.net/aff.php?aff=54161) | https://bwh81.net/aff.php?aff=54161 | BWH3HYATVBJW |
|
||||
|
||||
# Docker
|
||||
|
||||
@@ -90,15 +92,16 @@ docker run -itd --name mw-server --privileged=true -p 7200:7200 -p 80:80 -p 443:
|
||||
```
|
||||
|
||||
|
||||
### 版本更新 0.9.13
|
||||
### 版本更新 0.10.1
|
||||
|
||||
* MySQL添加外部导入功能。
|
||||
* OpenResty添加性能调整功能。
|
||||
* 优化ubuntu22.04安装过程。
|
||||
* Debian9友好,【SSH终端 1.0】无法使用。
|
||||
* phpMyAdmin优化,需要卸载重装。
|
||||
* 文件管理解压直接覆盖FIX。
|
||||
* 优化文件多选的BUG。
|
||||
|
||||
* 优化弹框。
|
||||
* 修复计划任务[日志切割]。
|
||||
* 优化mysql的与phpmyadmin的连接。
|
||||
* PHP添加`会话管理`功能。
|
||||
* redis优化。
|
||||
* 更新mysql[5.7]的安装。
|
||||
* OP防火墙部分功能优化。
|
||||
|
||||
### JSDelivr安装地址
|
||||
|
||||
@@ -114,6 +117,12 @@ curl -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/instal
|
||||
curl -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/update.sh | bash
|
||||
```
|
||||
|
||||
- 卸载脚本
|
||||
|
||||
```
|
||||
curl -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/uninstall.sh | bash
|
||||
```
|
||||
|
||||
### 备用地址
|
||||
|
||||
- 初始安装
|
||||
@@ -129,6 +138,12 @@ curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts
|
||||
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/update.sh | bash
|
||||
```
|
||||
|
||||
- 卸载脚本
|
||||
|
||||
```
|
||||
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/uninstall.sh | bash
|
||||
```
|
||||
|
||||
|
||||
### 通用软件安装[命令行安装]
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ def initInitD():
|
||||
mw.execShell('mkdir -p /etc/init.d')
|
||||
|
||||
# initd
|
||||
if os.path.exists("/etc/init.d"):
|
||||
if os.path.exists('/etc/init.d'):
|
||||
initd_bin = '/etc/init.d/mw'
|
||||
if not os.path.exists(initd_bin):
|
||||
import shutil
|
||||
|
||||
@@ -15,7 +15,7 @@ from flask import request
|
||||
|
||||
class config_api:
|
||||
|
||||
__version = '0.9.13'
|
||||
__version = '0.10.1'
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@@ -68,8 +68,8 @@ class crontab_api:
|
||||
_list[i]['where_hour']), str(_list[i]['where_minute'])))
|
||||
data.append(tmp)
|
||||
|
||||
_ret = {}
|
||||
_ret['data'] = data
|
||||
rdata = {}
|
||||
rdata['data'] = data
|
||||
|
||||
count = mw.M('crontab').where('', ()).count()
|
||||
_page = {}
|
||||
@@ -78,9 +78,17 @@ class crontab_api:
|
||||
_page['row'] = psize
|
||||
_page['tojs'] = "getCronData"
|
||||
|
||||
_ret['list'] = mw.getPage(_page)
|
||||
_ret['p'] = p
|
||||
return mw.getJson(_ret)
|
||||
rdata['list'] = mw.getPage(_page)
|
||||
rdata['p'] = p
|
||||
|
||||
# backup hock
|
||||
bh_file = mw.getPanelDataDir() + "/hook_backup.json"
|
||||
if os.path.exists(bh_file):
|
||||
hb_data = mw.readFile(bh_file)
|
||||
hb_data = json.loads(hb_data)
|
||||
rdata['backup_hook'] = hb_data
|
||||
|
||||
return mw.getJson(rdata)
|
||||
|
||||
# 设置计划任务状态
|
||||
def setCronStatusApi(self):
|
||||
@@ -409,6 +417,15 @@ class crontab_api:
|
||||
shell = param.sFile
|
||||
else:
|
||||
head = "#!/bin/bash\nPATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin\nexport PATH\n"
|
||||
|
||||
source_bin_activate = '''
|
||||
MW_PATH=%s/bin/activate
|
||||
if [ -f $MW_PATH ];then
|
||||
source $MW_PATH
|
||||
fi
|
||||
''' % (mw.getRunDir(),)
|
||||
|
||||
head = head + source_bin_activate + "\n"
|
||||
log = '.log'
|
||||
|
||||
script_dir = mw.getServerDir() + "/mdserver-web/scripts"
|
||||
|
||||
@@ -758,7 +758,7 @@ class files_api:
|
||||
try:
|
||||
tmps = mw.getRunDir() + '/tmp/panelExec.log'
|
||||
if stype == 'zip':
|
||||
os.system("cd " + path + " && unzip -d '" + dfile +
|
||||
os.system("cd " + path + " && unzip -o -d '" + dfile +
|
||||
"' '" + sfile + "' > " + tmps + " 2>&1 &")
|
||||
else:
|
||||
sfiles = ''
|
||||
|
||||
+18
-9
@@ -161,19 +161,24 @@ def isInstalledWeb():
|
||||
|
||||
|
||||
def restartWeb():
|
||||
return opWeb("reload")
|
||||
|
||||
|
||||
def opWeb(method):
|
||||
if not isInstalledWeb():
|
||||
return False
|
||||
|
||||
# systemd
|
||||
systemd = '/lib/systemd/system/openresty.service'
|
||||
if os.path.exists(systemd):
|
||||
execShell('systemctl reload openresty')
|
||||
execShell('systemctl ' + method + ' openresty')
|
||||
return True
|
||||
|
||||
# initd
|
||||
initd = getServerDir() + '/openresty/init.d/openresty'
|
||||
|
||||
if os.path.exists(initd):
|
||||
execShell(initd + ' ' + 'reload')
|
||||
execShell(initd + ' ' + method)
|
||||
return True
|
||||
|
||||
return False
|
||||
@@ -406,7 +411,7 @@ def writeFile(filename, str):
|
||||
return False
|
||||
|
||||
|
||||
def backFile(self, file, act=None):
|
||||
def backFile(file, act=None):
|
||||
"""
|
||||
@name 备份配置文件
|
||||
@param file 需要备份的文件
|
||||
@@ -415,10 +420,12 @@ def backFile(self, file, act=None):
|
||||
file_type = "_bak"
|
||||
if act:
|
||||
file_type = "_def"
|
||||
execShell("/usr/bin/cp -p {0} {1}".format(file, file + file_type))
|
||||
|
||||
# print("cp -p {0} {1}".format(file, file + file_type))
|
||||
execShell("cp -p {0} {1}".format(file, file + file_type))
|
||||
|
||||
|
||||
def restoreFile(self, file, act=None):
|
||||
def restoreFile(file, act=None):
|
||||
"""
|
||||
@name 还原配置文件
|
||||
@param file 需要还原的文件
|
||||
@@ -427,7 +434,7 @@ def restoreFile(self, file, act=None):
|
||||
file_type = "_bak"
|
||||
if act:
|
||||
file_type = "_def"
|
||||
execShell("/usr/bin/cp -p {1} {0}".format(file, file + file_type))
|
||||
execShell("cp -p {1} {0}".format(file, file + file_type))
|
||||
|
||||
|
||||
def HttpGet(url, timeout=10):
|
||||
@@ -595,12 +602,14 @@ def getLastLine(path, num, p=1):
|
||||
count = start_line + num
|
||||
fp = open(path, 'rb')
|
||||
buf = ""
|
||||
fp.seek(-1, 2)
|
||||
|
||||
fp.seek(0, 2)
|
||||
if fp.read(1) == "\n":
|
||||
fp.seek(-1, 2)
|
||||
fp.seek(0, 2)
|
||||
data = []
|
||||
b = True
|
||||
n = 0
|
||||
|
||||
for i in range(count):
|
||||
while True:
|
||||
newline_pos = str.rfind(str(buf), "\n")
|
||||
@@ -717,7 +726,7 @@ def checkIp(ip):
|
||||
|
||||
def checkPort(port):
|
||||
# 检查端口是否合法
|
||||
ports = ['21', '25', '7200', '888']
|
||||
ports = ['21', '25', '443', '888']
|
||||
if port in ports:
|
||||
return False
|
||||
intport = int(port)
|
||||
|
||||
@@ -9,7 +9,7 @@ if [ -f bin/activate ];then
|
||||
source bin/activate
|
||||
fi
|
||||
|
||||
# export LC_ALL="en_US.UTF-8"
|
||||
export LC_ALL="en_US.UTF-8"
|
||||
|
||||
|
||||
mw_start_task()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
server
|
||||
{
|
||||
listen {$PORT};
|
||||
listen [::]:{$PORT};
|
||||
server_name {$SERVER_NAME};
|
||||
index index.php index.html index.htm default.php default.htm default.html;
|
||||
root {$ROOT_DIR};
|
||||
|
||||
@@ -0,0 +1,418 @@
|
||||
# coding:utf-8
|
||||
|
||||
'''
|
||||
doc: https://docs.python.org/zh-cn/3/library/ftplib.html
|
||||
'''
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import json
|
||||
|
||||
import paramiko
|
||||
import ftplib
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
DEBUG = True
|
||||
BLOCK_SIZE = 1024 * 1024 * 2
|
||||
# BLOCK_SIZE = 50
|
||||
PROGRESS_FILE_NAME = "PROGRESS_FILE_NAME"
|
||||
|
||||
"""
|
||||
=============自定义异常===================
|
||||
"""
|
||||
|
||||
|
||||
class OsError(Exception):
|
||||
"""OS端异常"""
|
||||
|
||||
|
||||
class ObjectNotFound(OsError):
|
||||
"""对象不存在时抛出的异常"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
message = "文件对象不存在。"
|
||||
super(ObjectNotFound, self).__init__(message, *args, **kwargs)
|
||||
|
||||
|
||||
class APIError(Exception):
|
||||
"""API参数错误异常"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
_api_error_msg = 'API资料校验失败,请核实!'
|
||||
super(APIError, self).__init__(_api_error_msg, *args, **kwargs)
|
||||
|
||||
|
||||
class FtpPSClient:
|
||||
_title = "FTP"
|
||||
_name = "ftp"
|
||||
__host = None
|
||||
__port = None
|
||||
__user = None
|
||||
__password = None
|
||||
default_port = 21
|
||||
default_backup_path = "/backup/"
|
||||
config_file = "cfg.json"
|
||||
|
||||
def __init__(self, load_config=True, timeout=10):
|
||||
self.timeout = timeout
|
||||
if load_config:
|
||||
data = self.get_config()
|
||||
self.injection_config(data)
|
||||
|
||||
def get_config(self):
|
||||
default_config = {
|
||||
"ftp_host": '',
|
||||
"ftp_user": '',
|
||||
"ftp_pass": '',
|
||||
"backup_path": self.default_backup_path
|
||||
}
|
||||
|
||||
cfg = mw.getServerDir() + "/backup_ftp/" + self.config_file
|
||||
if os.path.exists(cfg):
|
||||
data = mw.readFile(cfg)
|
||||
return json.loads(data)
|
||||
else:
|
||||
return default_config
|
||||
|
||||
def injection_config(self, data):
|
||||
host = data["ftp_host"].strip()
|
||||
if host.find(':') == -1:
|
||||
self.__port = self.default_port
|
||||
|
||||
self.__host = data['ftp_host'].strip()
|
||||
self.__user = data['ftp_user'].strip()
|
||||
self.__password = data['ftp_pass'].strip()
|
||||
bp = data['backup_path'].strip()
|
||||
if bp:
|
||||
self.backup_path = self.getPath(bp)
|
||||
else:
|
||||
self.backup_path = self.getPath(self.default_backup_path)
|
||||
|
||||
def authorize(self):
|
||||
try:
|
||||
if self.timeout is not None:
|
||||
ftp = ftplib.FTP(timeout=self.timeout)
|
||||
else:
|
||||
ftp = ftplib.FTP()
|
||||
|
||||
debuglevel = 0
|
||||
# if DEBUG:
|
||||
# debuglevel = 3
|
||||
ftp.set_debuglevel(debuglevel)
|
||||
# ftp.set_pasv(True)
|
||||
ftp.connect(self.__host, int(self.__port))
|
||||
ftp.login(self.__user, self.__password)
|
||||
return ftp
|
||||
except Exception as e:
|
||||
raise OsError("无法连接FTP客户端,请检查配置参数是否正确!")
|
||||
|
||||
# 取目录路径
|
||||
def getPath(self, path):
|
||||
if path[-1:] != '/':
|
||||
path += '/'
|
||||
if path[:1] != '/':
|
||||
path = '/' + path
|
||||
return path.replace('//', '/')
|
||||
|
||||
def generateDownloadUrl(self, object_name):
|
||||
|
||||
return 'ftp://' + \
|
||||
self.__user + ':' + \
|
||||
self.__password + '@' + \
|
||||
self.__host + ':' + \
|
||||
"/" + object_name
|
||||
|
||||
def buildDirName(self, data_type, file_name):
|
||||
import re
|
||||
prefix_dict = {
|
||||
"site": "web",
|
||||
"database": "db",
|
||||
"path": "path",
|
||||
}
|
||||
file_regx = prefix_dict.get(data_type) + "_(.+)_20\d+_\d+\."
|
||||
sub_search = re.search(file_regx, file_name)
|
||||
sub_path_name = ""
|
||||
if sub_search:
|
||||
sub_path_name = sub_search.groups()[0]
|
||||
sub_path_name += '/'
|
||||
|
||||
# 构建OS存储路径
|
||||
object_name = self.backup_path + \
|
||||
data_type + '/' + \
|
||||
sub_path_name + \
|
||||
file_name
|
||||
return object_name
|
||||
|
||||
def uploadFile(self, filename, data_type=None, *args, **kwargs):
|
||||
|
||||
client = self.authorize()
|
||||
|
||||
local_file_name = filename
|
||||
filename = os.path.abspath(filename)
|
||||
dirname = os.path.dirname(filename)
|
||||
temp_name = os.path.split(filename)[1]
|
||||
|
||||
object_name = self.buildDirName(data_type, temp_name)
|
||||
|
||||
upload_tmp_dir = os.path.join(dirname, ".upload_tmp")
|
||||
if not os.path.exists(upload_tmp_dir):
|
||||
os.mkdir(upload_tmp_dir)
|
||||
|
||||
print("|-正在上传文件到 {}".format(object_name))
|
||||
|
||||
total_bytes = os.path.getsize(filename)
|
||||
object_md5_name = mw.md5(object_name)
|
||||
pg_file = os.path.join(upload_tmp_dir, object_md5_name + ".pl")
|
||||
|
||||
block_size = BLOCK_SIZE
|
||||
if kwargs.get("block_size"):
|
||||
try:
|
||||
block_size = float(kwargs.get("block_size"))
|
||||
except:
|
||||
pass
|
||||
|
||||
remote_file_size = None
|
||||
if not os.path.exists(pg_file):
|
||||
# import uuid
|
||||
# uid = str(uuid.uuid1())
|
||||
progress_info = {
|
||||
"filename": local_file_name,
|
||||
"total_bytes": total_bytes,
|
||||
"uploaded_bytes": 0,
|
||||
}
|
||||
mw.writeFile(pg_file, json.dumps(progress_info))
|
||||
else:
|
||||
progress_info = json.loads(public.readFile(pg_file))
|
||||
if total_bytes == progress_info.get("total_bytes"):
|
||||
# 取远程文件大小
|
||||
_max_loop = 10
|
||||
while _max_loop > 0:
|
||||
try:
|
||||
time.sleep(1)
|
||||
remote_file_size = client.size(object_name)
|
||||
if remote_file_size > total_bytes:
|
||||
remote_file_size = None
|
||||
break
|
||||
except Exception as e:
|
||||
if DEBUG:
|
||||
print(type(e))
|
||||
print(e)
|
||||
_max_loop -= 1
|
||||
else:
|
||||
remote_file_size = None
|
||||
|
||||
uploaded_bytes = 0 if remote_file_size is None else remote_file_size
|
||||
|
||||
dir_name = os.path.split(object_name)[0]
|
||||
if dir_name:
|
||||
self.createDirP(dir_name)
|
||||
|
||||
upload_start = time.time()
|
||||
|
||||
try:
|
||||
if total_bytes > 1024 * 1024 * 1024:
|
||||
with open(local_file_name, 'rb') as file_handler:
|
||||
if remote_file_size is not None:
|
||||
file_handler.seek(remote_file_size)
|
||||
|
||||
client.voidcmd("TYPE I")
|
||||
datasock = ''
|
||||
esize = ''
|
||||
|
||||
datasock, esize = client.ntransfercmd(
|
||||
"STOR " + object_name, remote_file_size)
|
||||
|
||||
while True:
|
||||
buf = file_handler.read(block_size)
|
||||
if not len(buf):
|
||||
break
|
||||
datasock.sendall(buf)
|
||||
uploaded_bytes += len(buf)
|
||||
if DEBUG:
|
||||
print('\ruploading %.2f%%' %
|
||||
(float(uploaded_bytes) / total_bytes * 100))
|
||||
|
||||
print("uploaded_bytes", uploaded_bytes)
|
||||
if uploaded_bytes == total_bytes:
|
||||
break
|
||||
datasock.close()
|
||||
|
||||
if DEBUG:
|
||||
print('close data handle')
|
||||
try:
|
||||
client.voidcmd('NOOP')
|
||||
except Exception as e:
|
||||
if DEBUG:
|
||||
print("Send NOOP command error:")
|
||||
print(e)
|
||||
else:
|
||||
if DEBUG:
|
||||
print('keep alive cmd success')
|
||||
client.voidresp()
|
||||
if DEBUG:
|
||||
print('No loop cmd')
|
||||
else:
|
||||
# 小于1G文件直接上传
|
||||
file_handler = open(local_file_name, "rb")
|
||||
client.storbinary('STOR %s' % object_name,
|
||||
file_handler, blocksize=block_size)
|
||||
file_handler.close()
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
|
||||
completed_file_size = None
|
||||
_max_loop = 10
|
||||
while _max_loop > 0:
|
||||
try:
|
||||
time.sleep(1)
|
||||
completed_file_size = client.size(object_name)
|
||||
break
|
||||
except Exception as e:
|
||||
_max_loop -= 1
|
||||
if DEBUG:
|
||||
print("size error:" + str(e))
|
||||
|
||||
# 上传完成
|
||||
if completed_file_size == total_bytes:
|
||||
if DEBUG:
|
||||
upload_completed = time.time()
|
||||
upload_diff = upload_completed - upload_start
|
||||
print("文件上传成功, 耗时: {}s。".format(upload_diff))
|
||||
if os.path.exists(pg_file):
|
||||
os.remove(pg_file)
|
||||
return True
|
||||
else:
|
||||
if os.path.exists(pg_file):
|
||||
os.remove(pg_file)
|
||||
print("文件上传后大小不一致!")
|
||||
|
||||
print("completed_file_size:" + str(completed_file_size))
|
||||
print("total_bytes:", total_bytes)
|
||||
print("object_md5_name:", object_md5_name)
|
||||
print("pg_file:", pg_file)
|
||||
print("filename:", filename)
|
||||
print("dirname:", dirname)
|
||||
print("object_name:", object_name)
|
||||
return False
|
||||
|
||||
def createDirP(self, dir_name):
|
||||
"""创建远程目录
|
||||
|
||||
:param dir_name: 目录名称
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
dirnames = dir_name.split('/')
|
||||
ftp = self.authorize()
|
||||
# ftp.cwd(get.path);
|
||||
for dirname in dirnames:
|
||||
if not dirname or not dirname.strip():
|
||||
continue
|
||||
try:
|
||||
flist = ftp.nlst()
|
||||
if not dirname in flist:
|
||||
ftp.mkd(dirname)
|
||||
except:
|
||||
# print("mlsd mode.")
|
||||
try:
|
||||
flist = list(ftp.mlsd())[1:]
|
||||
for f in flist:
|
||||
if dirname == f[0]:
|
||||
break
|
||||
else:
|
||||
ftp.mkd(dirname)
|
||||
except:
|
||||
return False
|
||||
ftp.cwd(dirname)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def createDir(self, path, name):
|
||||
ftp = self.authorize()
|
||||
path = self.getPath(path)
|
||||
ftp.cwd(path)
|
||||
try:
|
||||
ftp.mkd(name)
|
||||
ftp.close()
|
||||
return True
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
ftp.close()
|
||||
return False
|
||||
|
||||
def deleteDir(self, path, dir_name):
|
||||
try:
|
||||
ftp = self.authorize()
|
||||
ftp.rmd(dir_name)
|
||||
return True
|
||||
except ftplib.error_perm as e:
|
||||
print(str(e) + ":" + dir_name)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return False
|
||||
|
||||
def deleteFile(self, filename):
|
||||
try:
|
||||
ftp = self.authorize()
|
||||
ftp.delete(filename)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
return False
|
||||
|
||||
def getList(self, path="/"):
|
||||
ftp = self.authorize()
|
||||
path = self.getPath(path)
|
||||
ftp.cwd(path)
|
||||
mlsd = False
|
||||
try:
|
||||
files = list(ftp.mlsd())
|
||||
mlsd = True
|
||||
except:
|
||||
try:
|
||||
files = ftp.nlst(path)
|
||||
mlsd = False
|
||||
except:
|
||||
raise RuntimeError("FTP服务器数据返回异常!")
|
||||
ftp.close()
|
||||
# print(files)
|
||||
f_list = []
|
||||
dirs = []
|
||||
data = []
|
||||
default_time = '1971/01/01 01:01:01'
|
||||
for dt in files:
|
||||
# print(dt)
|
||||
if mlsd:
|
||||
dt_name = dt[0]
|
||||
dt_info = dt[1]
|
||||
else:
|
||||
if dt.find("/") >= 0:
|
||||
dt = dt.split("/")[-1]
|
||||
tmp = {}
|
||||
tmp['name'] = dt_name
|
||||
if dt_name == '.' or dt_name == '..':
|
||||
continue
|
||||
|
||||
tmp['time'] = dt_info['modify']
|
||||
try:
|
||||
tmp['size'] = dt_info['size']
|
||||
tmp['type'] = "File"
|
||||
tmp['download'] = self.generateDownloadUrl(path + dt_name)
|
||||
f_list.append(tmp)
|
||||
except:
|
||||
tmp['size'] = dt_info['sizd']
|
||||
tmp['type'] = None
|
||||
tmp['download'] = ''
|
||||
dirs.append(tmp)
|
||||
data = dirs + f_list
|
||||
|
||||
mlist = {}
|
||||
mlist['path'] = path
|
||||
mlist['list'] = data
|
||||
return mlist
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
Executable
+101
@@ -0,0 +1,101 @@
|
||||
<style>
|
||||
.upyunCon {
|
||||
height: 428px;
|
||||
}
|
||||
|
||||
.up-place {
|
||||
height: 62px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.up-place .btn {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.up-place .place-input {
|
||||
background-color: #f3f3f3;
|
||||
border: 1px solid #ccc;
|
||||
height: 30px;
|
||||
line-height: 28px;
|
||||
overflow: hidden;
|
||||
margin: 1px 0 0 -1px;
|
||||
width: 340px;
|
||||
}
|
||||
|
||||
.place-input ul {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.place-input ul li {
|
||||
background: url("/static/img/ico/ico-ltr.png") no-repeat right center;
|
||||
float: left;
|
||||
padding-left: 10px;
|
||||
padding-right: 18px;
|
||||
}
|
||||
|
||||
.place-input ul li a {
|
||||
height: 28px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.upyunlist {
|
||||
height: 516px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.up-bottom {
|
||||
background-color: #fafafa;
|
||||
border-top: 1px solid #eee;
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.up-use {
|
||||
line-height: 50px
|
||||
}
|
||||
|
||||
.list-list .cursor span {
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.btn-title {
|
||||
margin-top: 1px
|
||||
}
|
||||
|
||||
.tip {
|
||||
font-size: 10px;
|
||||
font-style: oblique;
|
||||
color: green;
|
||||
}
|
||||
</style>
|
||||
<div class="upyunCon">
|
||||
<div class="up-place pd15">
|
||||
<button id="backBtn" class="btn btn-default btn-sm glyphicon glyphicon-arrow-left pull-left" title="后退"></button>
|
||||
<input id="myPath" style="display:none;" type="text" value="">
|
||||
<div class="place-input pull-left">
|
||||
<div style="width:1400px;height:28px"><ul></ul></div>
|
||||
</div>
|
||||
<button class="refreshBtn btn btn-default btn-sm glyphicon glyphicon-refresh pull-left mr20" title="刷新" style="margin-left:-1px;"></button>
|
||||
<button class="btn btn-default btn-sm pull-right btn-title" onclick="upyunApi()">帐户设置</button>
|
||||
<button class="btn btn-default btn-sm pull-right mr20 btn-title" onclick="createDir()">新建文件夹</button>
|
||||
</div>
|
||||
|
||||
<div class="upyunlist pd15">
|
||||
<div class="divtable" style="margin-bottom:15px">
|
||||
<table class="table table-hover">
|
||||
<thead><tr><th>名称</th><th>大小</th><th>更新时间</th><th class="text-right">操作</th></tr></thead>
|
||||
<tbody class="list-list"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$.getScript( "/plugins/file?name=backup_ftp&f=js/backup_ftp.js", function(){
|
||||
osList('/');
|
||||
});
|
||||
</script>
|
||||
Executable
+250
@@ -0,0 +1,250 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import json
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
_ver = sys.version_info
|
||||
is_py2 = (_ver[0] == 2)
|
||||
is_py3 = (_ver[0] == 3)
|
||||
|
||||
DEBUG = False
|
||||
|
||||
if is_py2:
|
||||
reload(sys)
|
||||
sys.setdefaultencoding('utf-8')
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'backup_ftp'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
sys.path.append(getPluginDir() + "/class")
|
||||
from ftp_client import FtpPSClient
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[2:]
|
||||
tmp = {}
|
||||
args_len = len(args)
|
||||
|
||||
if args_len == 1:
|
||||
t = args[0].strip('{').strip('}')
|
||||
t = t.split(':')
|
||||
tmp[t[0]] = t[1]
|
||||
elif args_len > 1:
|
||||
for i in range(len(args)):
|
||||
t = args[i].split(':')
|
||||
tmp[t[0]] = t[1]
|
||||
|
||||
return tmp
|
||||
|
||||
|
||||
def checkArgs(data, ck=[]):
|
||||
for i in range(len(ck)):
|
||||
if not ck[i] in data:
|
||||
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
|
||||
return (True, mw.returnJson(True, 'ok'))
|
||||
|
||||
|
||||
def status():
|
||||
return 'start'
|
||||
|
||||
|
||||
def getConf():
|
||||
cfg = getServerDir() + "/cfg.json"
|
||||
if not os.path.exists(cfg):
|
||||
return mw.returnJson(False, "未配置", [])
|
||||
data = mw.readFile(cfg)
|
||||
data = json.loads(data)
|
||||
return mw.returnJson(True, "OK", data)
|
||||
|
||||
|
||||
def setConf():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['use_sftp', 'ftp_user',
|
||||
'ftp_pass', 'ftp_host', 'backup_path'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
cfg = getServerDir() + "/cfg.json"
|
||||
|
||||
values = ['ftp_user',
|
||||
'ftp_pass',
|
||||
'ftp_host']
|
||||
for v in values:
|
||||
if args[v] == '':
|
||||
return mw.returnJson(False, '必填资料不能为空,请核实!', [])
|
||||
|
||||
if args['backup_path'] == '':
|
||||
args['backup_path'] = "/backup"
|
||||
|
||||
try:
|
||||
ftp = FtpPSClient(load_config=False)
|
||||
ftp.injection_config(args)
|
||||
data = ftp.getList("/")
|
||||
if data:
|
||||
mw.writeFile(cfg, mw.getJson(args))
|
||||
return mw.returnJson(True, '设置成功', [])
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, "FTP校验失败,请核实!\n" + str(e), [])
|
||||
|
||||
|
||||
def getList():
|
||||
cfg = getServerDir() + "/cfg.json"
|
||||
if not os.path.exists(cfg):
|
||||
return mw.returnJson(False, "未配置FTP,请点击`账户设置`", [])
|
||||
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['path'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
try:
|
||||
ftp = FtpPSClient()
|
||||
flist = ftp.getList(args['path'])
|
||||
return mw.returnJson(True, "ok", flist)
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, str(e), [])
|
||||
|
||||
|
||||
def createDir():
|
||||
cfg = getServerDir() + "/cfg.json"
|
||||
if not os.path.exists(cfg):
|
||||
return mw.returnJson(False, "未配置FTP,请点击`账户设置`", [])
|
||||
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['path', 'name'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
ftp = FtpPSClient()
|
||||
isok = ftp.createDir(args['path'], args['name'])
|
||||
if isok:
|
||||
return mw.returnJson(True, "创建成功")
|
||||
return mw.returnJson(False, "创建失败")
|
||||
|
||||
|
||||
def deleteDir():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['dir_name', 'path'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
ftp = FtpPSClient()
|
||||
isok = ftp.deleteDir(args['path'], args['dir_name'])
|
||||
if isok:
|
||||
return mw.returnJson(True, "删除成功")
|
||||
return mw.returnJson(False, "删除失败")
|
||||
|
||||
|
||||
def deleteFile():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['path', 'filename'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
ftp = FtpPSClient()
|
||||
isok = ftp.deleteFile(args['path'] + "/" + args['filename'])
|
||||
if isok:
|
||||
return mw.returnJson(True, "删除成功")
|
||||
return mw.returnJson(False, "删除失败")
|
||||
|
||||
|
||||
def backupAllFunc(stype):
|
||||
os.chdir(mw.getRunDir())
|
||||
|
||||
name = sys.argv[2]
|
||||
num = sys.argv[3]
|
||||
|
||||
args = stype + " " + name + " " + num
|
||||
|
||||
cmd = 'python3 ' + mw.getRunDir() + '/scripts/backup.py ' + args
|
||||
os.system(cmd)
|
||||
|
||||
# 开始执行上传信息
|
||||
|
||||
prefix_dict = {
|
||||
"site": "web",
|
||||
"database": "db",
|
||||
"path": "path",
|
||||
}
|
||||
|
||||
find_path = mw.getBackupDir() + '/' + stype + '/' + \
|
||||
prefix_dict[stype] + '_' + name
|
||||
|
||||
find_new_file = "ls " + find_path + \
|
||||
"_* | grep tar.gz | cut -d \ -f 1 | awk 'END {print}'"
|
||||
|
||||
filename = mw.execShell(find_new_file)[0].strip()
|
||||
# print("filename:", filename)
|
||||
|
||||
ftp = FtpPSClient()
|
||||
ftp.uploadFile(filename, stype)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def backupSite():
|
||||
# 备份站点
|
||||
pass
|
||||
|
||||
|
||||
def in_array(name, arr=[]):
|
||||
for x in arr:
|
||||
if name == x:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def installPreInspection():
|
||||
return 'ok'
|
||||
|
||||
if __name__ == "__main__":
|
||||
func = sys.argv[1]
|
||||
if func == 'status':
|
||||
print(status())
|
||||
elif func == 'start':
|
||||
print(start())
|
||||
elif func == 'stop':
|
||||
print(stop())
|
||||
elif func == 'restart':
|
||||
print(restart())
|
||||
elif func == 'reload':
|
||||
print(reload())
|
||||
elif func == 'install_pre_inspection':
|
||||
print(installPreInspection())
|
||||
elif func == 'conf':
|
||||
print(getConf())
|
||||
elif func == 'set_config':
|
||||
print(setConf())
|
||||
elif func == "get_list":
|
||||
print(getList())
|
||||
elif func == "create_dir":
|
||||
print(createDir())
|
||||
elif func == "delete_dir":
|
||||
print(deleteDir())
|
||||
elif func == 'delete_file':
|
||||
print(deleteFile())
|
||||
elif in_array(func, ['site', 'database', 'path']):
|
||||
print(backupAllFunc(func))
|
||||
else:
|
||||
print('error')
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"title":"FTP存储空间",
|
||||
"hook":["backup"],
|
||||
"tip":"soft",
|
||||
"name":"backup_ftp",
|
||||
"type":"运行环境",
|
||||
"ps":"将网站或数据库打包备份到FTP存储空间",
|
||||
"versions":["1.0"],
|
||||
"install_pre_inspection":false,
|
||||
"shell":"install.sh",
|
||||
"checks":"server/backup_ftp",
|
||||
"path": "server/backup_ftp",
|
||||
"author":"midoks",
|
||||
"home":"",
|
||||
"date":"2022-10-23",
|
||||
"pid": "4"
|
||||
}
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
sys_os=`uname`
|
||||
|
||||
|
||||
Install_App()
|
||||
{
|
||||
mkdir -p ${serverPath}/backup_ftp
|
||||
echo "${1}" > ${serverPath}/backup_ftp/version.pl
|
||||
echo '安装完成' > $install_tmp
|
||||
|
||||
}
|
||||
|
||||
Uninstall_App()
|
||||
{
|
||||
rm -rf ${serverPath}/backup_ftp
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_App $2
|
||||
else
|
||||
Uninstall_App $2
|
||||
fi
|
||||
Executable
+258
@@ -0,0 +1,258 @@
|
||||
|
||||
|
||||
function bkfPost(method,args,callback){
|
||||
var _args = null;
|
||||
if (typeof(args) == 'string'){
|
||||
_args = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
_args = JSON.stringify(args);
|
||||
}
|
||||
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
$.post('/plugins/run', {name:'backup_ftp', func:method, args:_args}, function(data) {
|
||||
layer.close(loadT);
|
||||
if (!data.status){
|
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof(callback) == 'function'){
|
||||
callback(data);
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
|
||||
function getFtpLocalTime(data){
|
||||
var str = data.slice(0,4)+"/"+data.slice(4,6)+"/"+data.slice(6,8)
|
||||
+ " " + data.slice(8,10)+":"+data.slice(10,12)+":"+data.slice(12,14);
|
||||
return str;
|
||||
}
|
||||
|
||||
// 自定义部分
|
||||
var i = null;
|
||||
//设置API
|
||||
function upyunApi(){
|
||||
|
||||
bkfPost('conf', {}, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
var token = rdata.data;
|
||||
var check_status = token.use_sftp;
|
||||
var sftp_checked = check_status === "true" ? " checked=\"checked\"" : "";
|
||||
|
||||
if (typeof(token.ftp_host) == 'undefined'){
|
||||
token.ftp_host = '';
|
||||
}
|
||||
|
||||
if (typeof(token.ftp_user) == 'undefined'){
|
||||
token.ftp_user = '';
|
||||
}
|
||||
|
||||
if (typeof(token.ftp_pass) == 'undefined'){
|
||||
token.ftp_pass = '';
|
||||
}
|
||||
|
||||
if (typeof(token.backup_path) == 'undefined'){
|
||||
token.backup_path = '';
|
||||
}
|
||||
|
||||
var apicon = '<div class="bingfa mtb15" style="padding-bottom:0px;">\
|
||||
<p>\
|
||||
<span class="span_tit">使用SFTP:</span>\ <input style="width: 20px; vertical-align:middle;" type="checkbox" name="use_sftp"'+sftp_checked+'> 是否使用SFTP进行数据传输 \
|
||||
</p>\
|
||||
<p>\
|
||||
<span class="span_tit">Host:</span>\
|
||||
<input placeholder="请输入主机地址" style="width: 200px;" type="text" name="upyun_service" value="'+token.ftp_host+'"> *服务器地址,FTP默认端口21, SFTP默认端口22\
|
||||
</p>\
|
||||
<p>\
|
||||
<span class="span_tit">用户名:</span>\
|
||||
<input style="width: 200px;" type="text" name="ftp_username" value="'+token.ftp_user+'"> *指定用户名\
|
||||
</p>\
|
||||
<p>\
|
||||
<span class="span_tit">密码:</span>\
|
||||
<input style="width: 200px;" type="password" name="ftp_password" value="'+token.ftp_pass+'"> *登录密码\
|
||||
</p>\
|
||||
<p>\
|
||||
<span class="span_tit">存储位置:</span>\
|
||||
<input placeholder="请输入存储位置" style="width: 200px;" type="text" name="backup_path" value="'+token.backup_path+'"> *相对于根目录的路径,默认是/backup\
|
||||
</p>\
|
||||
</div>';
|
||||
layer.open({
|
||||
type: 1,
|
||||
area: "600px",
|
||||
title: "FTP/SFTP帐户设置",
|
||||
closeBtn: 1,
|
||||
shift: 5,
|
||||
shadeClose: false,
|
||||
btn: ['确定','取消'],
|
||||
content:apicon,
|
||||
yes:function(index,layero){
|
||||
var data = {
|
||||
use_sftp:$("input[name='use_sftp']").prop('checked'),
|
||||
ftp_user:$("input[name='ftp_username']").val(),
|
||||
ftp_pass:$("input[name='ftp_password']").val(),
|
||||
ftp_host:$("input[name='upyun_service']").val(),
|
||||
backup_path:$("input[name='backup_path']").val()
|
||||
}
|
||||
bkfPost('set_config', data, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
if (rdata.status){
|
||||
showMsg(rdata.msg,function(){
|
||||
layer.close(index);
|
||||
osList("/");
|
||||
},{icon:1},2000);
|
||||
} else{
|
||||
layer.msg(rdata.msg,{icon:2});
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createDir(){
|
||||
layer.open({
|
||||
type: 1,
|
||||
area: "400px",
|
||||
title: "创建目录",
|
||||
closeBtn: 1,
|
||||
shift: 5,
|
||||
shadeClose: false,
|
||||
btn: ['确定','取消'],
|
||||
content:'<div class="bingfa bt-form c6" style="padding-bottom: 10px;">\
|
||||
<p>\
|
||||
<span class="span_tit">目录名称:</span>\
|
||||
<input style="width: 200px;" type="text" name="newPath" value="">\
|
||||
</p>\
|
||||
</div>',
|
||||
success:function(){
|
||||
$("input[name='newPath']").focus().keyup(function(e){
|
||||
if(e.keyCode == 13) $(".layui-layer-btn0").click();
|
||||
});
|
||||
},
|
||||
yes:function(index,layero){
|
||||
var name = $("input[name='newPath']").val();
|
||||
if(name == ''){
|
||||
layer.msg('目录名称不能为空!',{icon:2});
|
||||
return;
|
||||
}
|
||||
var path = $("#myPath").val();
|
||||
var dirname = name;
|
||||
// var loadT = layer.msg('正在创建目录['+dirname+']...',{icon:16,time:0,shade: [0.3, '#000']});
|
||||
bkfPost('create_dir', {path:path,name:dirname}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
if(rdata.status) {
|
||||
showMsg(rdata.msg, function(){
|
||||
layer.close(index);
|
||||
osList(path);
|
||||
} ,{icon:1}, 2000);
|
||||
} else{
|
||||
layer.msg(rdata.msg,{icon:2});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//删除文件
|
||||
function deleteFile(name, is_dir){
|
||||
if (is_dir === false){
|
||||
safeMessage('删除文件','删除后将无法恢复,真的要删除['+name+']吗?',function(){
|
||||
var path = $("#myPath").val();
|
||||
var filename = name;
|
||||
bkfPost('delete_file', {filename:filename,path:path}, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
osList(path);
|
||||
},{icon:rdata.status?1:2},2000);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
safeMessage('删除文件夹','删除后将无法恢复,真的要删除['+name+']吗?',function(){
|
||||
var path = $("#myPath").val();
|
||||
bkfPost('delete_dir', {dir_name:name,path:path}, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
osList(path);
|
||||
},{icon:rdata.status?1:2},2000);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function osList(path){
|
||||
bkfPost('get_list', {path:path}, function(rdata){
|
||||
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
if(rdata.status === false){
|
||||
showMsg(rdata.msg,function(){
|
||||
upyunApi();
|
||||
},{icon:2},2000);
|
||||
return;
|
||||
}
|
||||
|
||||
var mlist = rdata.data;
|
||||
// console.log(mlist);
|
||||
var listBody = ''
|
||||
var listFiles = ''
|
||||
for(var i=0;i<mlist.list.length;i++){
|
||||
if(mlist.list[i].type == null){
|
||||
listBody += '<tr><td class="cursor" onclick="osList(\''+(path+'/'+mlist.list[i].name).replace('//','/')+'\')"><span class="ico ico-folder"></span>\<span>'+mlist.list[i].name+'</span></td>\
|
||||
<td>-</td>\
|
||||
<td>-</td>\
|
||||
<td class="text-right"><a class="btlink" onclick="deleteFile(\''+mlist.list[i].name+'\', true)">删除</a></td></tr>'
|
||||
}else{
|
||||
listFiles += '<tr><td class="cursor"><span class="ico ico-file"></span>\<span>'+mlist.list[i].name+'</span></td>\
|
||||
<td>'+toSize(mlist.list[i].size)+'</td>\
|
||||
<td>'+getFtpLocalTime(mlist.list[i].time)+'</td>\
|
||||
<td class="text-right"><a target="_blank" href="'+mlist.list[i].download+'" class="btlink">下载</a> | <a class="btlink" onclick="deleteFile(\''+mlist.list[i].name+'\', false)">删除</a></td></tr>'
|
||||
}
|
||||
}
|
||||
listBody += listFiles;
|
||||
|
||||
var pathLi='';
|
||||
var tmp = path.split('/')
|
||||
var pathname = '';
|
||||
var n = 0;
|
||||
for(var i=0;i<tmp.length;i++){
|
||||
if(n > 0 && tmp[i] == '') continue;
|
||||
var dirname = tmp[i];
|
||||
if(dirname == '') {
|
||||
dirname = '根目录';
|
||||
n++;
|
||||
}
|
||||
pathname += '/' + tmp[i];
|
||||
pathname = pathname.replace('//','/');
|
||||
pathLi += '<li><a title="'+pathname+'" onclick="osList(\''+pathname+'\')">'+dirname+'</a></li>';
|
||||
}
|
||||
var um = 1;
|
||||
if(tmp[tmp.length-1] == '') um = 2;
|
||||
var backPath = tmp.slice(0,tmp.length-um).join('/') || '/';
|
||||
$('#myPath').val(path);
|
||||
$(".upyunCon .place-input ul").html(pathLi);
|
||||
$(".upyunlist .list-list").html(listBody);
|
||||
|
||||
upPathLeft();
|
||||
|
||||
$('#backBtn').unbind().click(function() {
|
||||
osList(backPath);
|
||||
});
|
||||
|
||||
$('.upyunCon .refreshBtn').unbind().click(function(){
|
||||
osList(path);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//计算当前目录偏移
|
||||
function upPathLeft(){
|
||||
var UlWidth = $(".place-input ul").width();
|
||||
var SpanPathWidth = $(".place-input").width() - 20;
|
||||
var Ml = UlWidth - SpanPathWidth;
|
||||
if(UlWidth > SpanPathWidth ){
|
||||
$(".place-input ul").css("left",-Ml)
|
||||
}
|
||||
else{
|
||||
$(".place-input ul").css("left",0)
|
||||
}
|
||||
}
|
||||
// $('.layui-layer-page').css('height','670px');
|
||||
@@ -80,7 +80,8 @@ innodb_data_home_dir = {$SERVER_APP_PATH}/data
|
||||
innodb_data_file_path = ibdata1:10M:autoextend
|
||||
innodb_log_group_home_dir = {$SERVER_APP_PATH}/data
|
||||
innodb_buffer_pool_size = 16M
|
||||
innodb_log_file_size = 5M
|
||||
#innodb_log_file_size = 5M
|
||||
innodb_redo_log_capacity=10485760
|
||||
innodb_log_buffer_size = 8M
|
||||
innodb_flush_log_at_trx_commit = 2
|
||||
innodb_lock_wait_timeout = 120
|
||||
|
||||
+107
-3
@@ -827,6 +827,69 @@ def setDbBackup():
|
||||
return mw.returnJson(True, 'ok')
|
||||
|
||||
|
||||
def importDbExternal():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['file', 'name'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
file = args['file']
|
||||
name = args['name']
|
||||
|
||||
import_dir = mw.getRootDir() + '/backup/import/'
|
||||
|
||||
file_path = import_dir + file
|
||||
if not os.path.exists(file_path):
|
||||
return mw.returnJson(False, '文件突然消失?')
|
||||
|
||||
exts = ['sql', 'gz', 'zip']
|
||||
tmp = file.split('.')
|
||||
ext = tmp[len(tmp) - 1]
|
||||
if ext not in exts:
|
||||
return mw.returnJson(False, '导入数据库格式不对!')
|
||||
|
||||
tmp = file.split('/')
|
||||
tmpFile = tmp[len(tmp) - 1]
|
||||
tmpFile = tmpFile.replace('.sql.' + ext, '.sql')
|
||||
tmpFile = tmpFile.replace('.' + ext, '.sql')
|
||||
tmpFile = tmpFile.replace('tar.', '')
|
||||
|
||||
# print(tmpFile)
|
||||
import_sql = ""
|
||||
if file.find("sql.gz") > -1:
|
||||
cmd = 'cd ' + import_dir + ' && gzip -dc ' + \
|
||||
file + " > " + import_dir + tmpFile
|
||||
info = mw.execShell(cmd)
|
||||
if info[1] == "":
|
||||
import_sql = import_dir + tmpFile
|
||||
|
||||
if file.find(".zip") > -1:
|
||||
cmd = 'cd ' + import_dir + ' && unzip -o ' + file
|
||||
mw.execShell(cmd)
|
||||
import_sql = import_dir + tmpFile
|
||||
|
||||
if file.find("tar.gz") > -1:
|
||||
cmd = 'cd ' + import_dir + ' && tar -zxvf ' + file
|
||||
mw.execShell(cmd)
|
||||
import_sql = import_dir + tmpFile
|
||||
|
||||
if import_sql == "":
|
||||
return mw.returnJson(False, '未找SQL文件')
|
||||
|
||||
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
|
||||
sock = getSocketFile()
|
||||
|
||||
os.environ["MYSQL_PWD"] = pwd
|
||||
mysql_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + \
|
||||
pwd + ' ' + name + ' < ' + import_sql
|
||||
|
||||
# print(mysql_cmd)
|
||||
os.system(mysql_cmd)
|
||||
os.remove(import_sql)
|
||||
|
||||
return mw.returnJson(True, 'ok')
|
||||
|
||||
|
||||
def importDbBackup():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['file', 'name'])
|
||||
@@ -855,13 +918,17 @@ def importDbBackup():
|
||||
|
||||
def deleteDbBackup():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['filename'])
|
||||
data = checkArgs(args, ['filename', 'path'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
path = args['path']
|
||||
full_file = ""
|
||||
bkDir = mw.getRootDir() + '/backup/database'
|
||||
|
||||
os.remove(bkDir + '/' + args['filename'])
|
||||
full_file = bkDir + '/' + args['filename']
|
||||
if path != "":
|
||||
full_file = path + "/" + args['filename']
|
||||
os.remove(full_file)
|
||||
return mw.returnJson(True, 'ok')
|
||||
|
||||
|
||||
@@ -893,6 +960,39 @@ def getDbBackupList():
|
||||
return mw.returnJson(True, 'ok', rr)
|
||||
|
||||
|
||||
def getDbBackupImportList():
|
||||
|
||||
bkImportDir = mw.getRootDir() + '/backup/import'
|
||||
if not os.path.exists(bkImportDir):
|
||||
os.mkdir(bkImportDir)
|
||||
|
||||
blist = os.listdir(bkImportDir)
|
||||
|
||||
rr = []
|
||||
for x in range(0, len(blist)):
|
||||
name = blist[x]
|
||||
p = bkImportDir + '/' + name
|
||||
data = {}
|
||||
data['name'] = name
|
||||
|
||||
rsize = os.path.getsize(p)
|
||||
data['size'] = mw.toSize(rsize)
|
||||
|
||||
t = os.path.getctime(p)
|
||||
t = time.localtime(t)
|
||||
|
||||
data['time'] = time.strftime('%Y-%m-%d %H:%M:%S', t)
|
||||
rr.append(data)
|
||||
|
||||
data['file'] = p
|
||||
|
||||
rdata = {
|
||||
"list": rr,
|
||||
"upload_dir": bkImportDir,
|
||||
}
|
||||
return mw.returnJson(True, 'ok', rdata)
|
||||
|
||||
|
||||
def getDbList():
|
||||
args = getArgs()
|
||||
page = 1
|
||||
@@ -2427,10 +2527,14 @@ if __name__ == "__main__":
|
||||
print(setDbBackup())
|
||||
elif func == 'import_db_backup':
|
||||
print(importDbBackup())
|
||||
elif func == 'import_db_external':
|
||||
print(importDbExternal())
|
||||
elif func == 'delete_db_backup':
|
||||
print(deleteDbBackup())
|
||||
elif func == 'get_db_backup_list':
|
||||
print(getDbBackupList())
|
||||
elif func == 'get_db_backup_import_list':
|
||||
print(getDbBackupImportList())
|
||||
elif func == 'add_db':
|
||||
print(addDb())
|
||||
elif func == 'del_db':
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"path": "server/mysql/VERSION",
|
||||
"todo_versions":["5.6","5.7","8.0"],
|
||||
"versions":["5.5", "5.6", "5.7","8.0"],
|
||||
"updates":["5.5.62","5.6.50", "5.7.32","8.0.22"],
|
||||
"updates":["5.5.62","5.6.50", "5.7.32","8.0.30"],
|
||||
"shell":"install.sh",
|
||||
"checks":"server/mysql",
|
||||
"path":"server/mysql",
|
||||
|
||||
+190
-75
@@ -1,18 +1,9 @@
|
||||
function str2Obj(str){
|
||||
var data = {};
|
||||
kv = str.split('&');
|
||||
for(i in kv){
|
||||
v = kv[i].split('=');
|
||||
data[v[0]] = v[1];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function myPost(method,args,callback, title){
|
||||
|
||||
var _args = null;
|
||||
if (typeof(args) == 'string'){
|
||||
_args = JSON.stringify(str2Obj(args));
|
||||
_args = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
_args = JSON.stringify(args);
|
||||
}
|
||||
@@ -40,7 +31,7 @@ function myPostN(method,args,callback, title){
|
||||
|
||||
var _args = null;
|
||||
if (typeof(args) == 'string'){
|
||||
_args = JSON.stringify(str2Obj(args));
|
||||
_args = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
_args = JSON.stringify(args);
|
||||
}
|
||||
@@ -59,7 +50,7 @@ function myPostN(method,args,callback, title){
|
||||
function myAsyncPost(method,args){
|
||||
var _args = null;
|
||||
if (typeof(args) == 'string'){
|
||||
_args = JSON.stringify(str2Obj(args));
|
||||
_args = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
_args = JSON.stringify(args);
|
||||
}
|
||||
@@ -606,7 +597,7 @@ function setDbAccess(username){
|
||||
yes:function(index){
|
||||
var data = $("#set_db_access").serialize();
|
||||
data = decodeURIComponent(data);
|
||||
var dataObj = str2Obj(data);
|
||||
var dataObj = toArrayObject(data);
|
||||
if(!dataObj['access']){
|
||||
dataObj['access'] = dataObj['dataAccess'];
|
||||
if ( dataObj['dataAccess'] == 'ip'){
|
||||
@@ -672,33 +663,15 @@ function setDbPass(id, username, password){
|
||||
}
|
||||
|
||||
function addDatabase(type){
|
||||
if (type==1){
|
||||
var data = $("#add_db").serialize();
|
||||
data = decodeURIComponent(data);
|
||||
var dataObj = str2Obj(data);
|
||||
if(!dataObj['address']){
|
||||
dataObj['address'] = dataObj['dataAccess'];
|
||||
}
|
||||
myPost('add_db', dataObj, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
if (rdata.status){
|
||||
dbList();
|
||||
}
|
||||
$('.layui-layer-close1').click();
|
||||
},{icon: rdata.status ? 1 : 2},600);
|
||||
});
|
||||
return;
|
||||
}
|
||||
var index = layer.open({
|
||||
layer.open({
|
||||
type: 1,
|
||||
skin: 'demo-class',
|
||||
area: '500px',
|
||||
title: '添加数据库',
|
||||
closeBtn: 1,
|
||||
shift: 5,
|
||||
shadeClose: true,
|
||||
content: "<form class='bt-form pd20 pb70' id='add_db'>\
|
||||
btn:["提交","关闭"],
|
||||
content: "<form class='bt-form pd20' id='add_db'>\
|
||||
<div class='line'>\
|
||||
<span class='tname'>数据库名</span>\
|
||||
<div class='info-r'><input name='name' class='bt-input-text mr5' placeholder='新的数据库名称' type='text' style='width:65%' value=''>\
|
||||
@@ -726,28 +699,39 @@ function addDatabase(type){
|
||||
</div>\
|
||||
</div>\
|
||||
<input type='hidden' name='ps' value='' />\
|
||||
<div class='bt-form-submit-btn'>\
|
||||
<button id='my_mod_close' type='button' class='btn btn-danger btn-sm btn-title'>关闭</button>\
|
||||
<button type='button' class='btn btn-success btn-sm btn-title' onclick=\"addDatabase(1)\" >提交</button>\
|
||||
</div>\
|
||||
</form>",
|
||||
});
|
||||
success:function(){
|
||||
$("input[name='name']").keyup(function(){
|
||||
var v = $(this).val();
|
||||
$("input[name='db_user']").val(v);
|
||||
$("input[name='ps']").val(v);
|
||||
});
|
||||
|
||||
$("input[name='name']").keyup(function(){
|
||||
var v = $(this).val();
|
||||
$("input[name='db_user']").val(v);
|
||||
$("input[name='ps']").val(v);
|
||||
});
|
||||
|
||||
$('#my_mod_close').click(function(){
|
||||
$('.layui-layer-close1').click();
|
||||
});
|
||||
$('select[name="dataAccess"]').change(function(){
|
||||
var v = $(this).val();
|
||||
if (v == 'ip'){
|
||||
$(this).after("<input id='dataAccess_subid' class='bt-input-text mr5' type='text' name='address' placeholder='多个IP使用逗号(,)分隔' style='width: 230px; display: inline-block;'>");
|
||||
} else {
|
||||
$('#dataAccess_subid').remove();
|
||||
$('select[name="dataAccess"]').change(function(){
|
||||
var v = $(this).val();
|
||||
if (v == 'ip'){
|
||||
$(this).after("<input id='dataAccess_subid' class='bt-input-text mr5' type='text' name='address' placeholder='多个IP使用逗号(,)分隔' style='width: 230px; display: inline-block;'>");
|
||||
} else {
|
||||
$('#dataAccess_subid').remove();
|
||||
}
|
||||
});
|
||||
},
|
||||
yes:function(index) {
|
||||
var data = $("#add_db").serialize();
|
||||
data = decodeURIComponent(data);
|
||||
var dataObj = toArrayObject(data);
|
||||
if(!dataObj['address']){
|
||||
dataObj['address'] = dataObj['dataAccess'];
|
||||
}
|
||||
myPost('add_db', dataObj, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
if (rdata.status){
|
||||
layer.close(index);
|
||||
dbList();
|
||||
}
|
||||
},{icon: rdata.status ? 1 : 2},600);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -759,7 +743,6 @@ function delDb(id, name){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
dbList();
|
||||
$('.layui-layer-close1').click();
|
||||
},{icon: rdata.status ? 1 : 2}, 600);
|
||||
});
|
||||
});
|
||||
@@ -881,8 +864,11 @@ function openPhpmyadmin(name,username,password){
|
||||
}
|
||||
}
|
||||
|
||||
function delBackup(filename,name){
|
||||
myPost('delete_db_backup',{filename:filename},function(){
|
||||
function delBackup(filename,name,path){
|
||||
if(typeof(path) == "undefined"){
|
||||
path = "";
|
||||
}
|
||||
myPost('delete_db_backup',{filename:filename,path:path},function(){
|
||||
layer.msg('执行成功!');
|
||||
setTimeout(function(){
|
||||
$('.layui-layer-close2').click();
|
||||
@@ -902,6 +888,132 @@ function importBackup(file,name){
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function importDbExternal(file,name){
|
||||
myPost('import_db_external',{file:file,name:name}, function(data){
|
||||
layer.msg('执行成功!');
|
||||
});
|
||||
}
|
||||
|
||||
function setLocalImport(db_name){
|
||||
|
||||
//上传文件
|
||||
function uploadDbFiles(upload_dir){
|
||||
var up_db = layer.open({
|
||||
type:1,
|
||||
closeBtn: 1,
|
||||
title:"上传导入文件["+upload_dir+']',
|
||||
area: ['500px','300px'],
|
||||
shadeClose:false,
|
||||
content:'<div class="fileUploadDiv">\
|
||||
<input type="hidden" id="input-val" value="'+upload_dir+'" />\
|
||||
<input type="file" id="file_input" multiple="true" autocomplete="off" />\
|
||||
<button type="button" id="opt" autocomplete="off">添加文件</button>\
|
||||
<button type="button" id="up" autocomplete="off" >开始上传</button>\
|
||||
<span id="totalProgress" style="position: absolute;top: 7px;right: 147px;"></span>\
|
||||
<span style="float:right;margin-top: 9px;">\
|
||||
<font>文件编码:</font>\
|
||||
<select id="fileCodeing" >\
|
||||
<option value="byte">二进制</option>\
|
||||
<option value="utf-8">UTF-8</option>\
|
||||
<option value="gb18030">GB2312</option>\
|
||||
</select>\
|
||||
</span>\
|
||||
<button type="button" id="filesClose" autocomplete="off">关闭</button>\
|
||||
<ul id="up_box"></ul>\
|
||||
</div>',
|
||||
success:function(){
|
||||
$('#filesClose').click(function(){
|
||||
layer.close(up_db);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
uploadStart(function(){
|
||||
getList();
|
||||
});
|
||||
}
|
||||
|
||||
function getList(){
|
||||
myPost('get_db_backup_import_list',{}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
|
||||
var file_list = rdata.data.list;
|
||||
var upload_dir = rdata.data.upload_dir;
|
||||
|
||||
var tbody = '';
|
||||
for (var i = 0; i < file_list.length; i++) {
|
||||
tbody += '<tr>\
|
||||
<td><span> ' + file_list[i]['name'] + '</span></td>\
|
||||
<td><span> ' + file_list[i]['size'] + '</span></td>\
|
||||
<td><span> ' + file_list[i]['time'] + '</span></td>\
|
||||
<td style="text-align: right;">\
|
||||
<a class="btlink" onclick="importDbExternal(\'' + file_list[i]['name'] + '\',\'' +db_name+ '\')">导入</a> | \
|
||||
<a class="btlink del" index="'+i+'">删除</a>\
|
||||
</td>\
|
||||
</tr>';
|
||||
}
|
||||
|
||||
$('#import_db_file_list').html(tbody);
|
||||
$('input[name="upload_dir"]').val(upload_dir);
|
||||
|
||||
$("#import_db_file_list .del").on('click',function(){
|
||||
var index = $(this).attr('index');
|
||||
var filename = file_list[index]["name"];
|
||||
myPost('delete_db_backup',{filename:filename,path:upload_dir},function(){
|
||||
showMsg('执行成功!', function(){
|
||||
getList();
|
||||
},{icon:1},2000);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var layerIndex = layer.open({
|
||||
type: 1,
|
||||
title: "从文件导入数据",
|
||||
area: ['600px', '380px'],
|
||||
closeBtn: 1,
|
||||
shadeClose: false,
|
||||
content: '<div class="pd15">\
|
||||
<div class="db_list">\
|
||||
<button id="btn_file_upload" class="btn btn-success btn-sm" type="button">从本地上传</button>\
|
||||
</div >\
|
||||
<div class="divtable">\
|
||||
<input type="hidden" name="upload_dir" value=""> \
|
||||
<div id="database_fix" style="height:150px;overflow:auto;border:#ddd 1px solid">\
|
||||
<table class="table table-hover "style="border:none">\
|
||||
<thead>\
|
||||
<tr>\
|
||||
<th>文件名称</th>\
|
||||
<th>文件大小</th>\
|
||||
<th>备份时间</th>\
|
||||
<th style="text-align: right;">操作</th>\
|
||||
</tr>\
|
||||
</thead>\
|
||||
<tbody id="import_db_file_list" class="gztr"></tbody>\
|
||||
</table>\
|
||||
</div>\
|
||||
<ul class="help-info-text c7">\
|
||||
<li>仅支持sql、zip、sql.gz、(tar.gz|gz|tgz)</li>\
|
||||
<li>zip、tar.gz压缩包结构:test.zip或test.tar.gz压缩包内,必需包含test.sql</li>\
|
||||
<li>若文件过大,您还可以使用SFTP工具,将数据库文件上传到/www/backup/import</li>\
|
||||
</ul>\
|
||||
</div>\
|
||||
</div>',
|
||||
success:function(index){
|
||||
$('#btn_file_upload').click(function(){
|
||||
var upload_dir = $('input[name="upload_dir"]').val();
|
||||
uploadDbFiles(upload_dir);
|
||||
});
|
||||
|
||||
getList();
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
function setBackup(db_name,obj){
|
||||
myPost('get_db_backup_list', {name:db_name}, function(data){
|
||||
|
||||
@@ -914,21 +1026,21 @@ function setBackup(db_name,obj){
|
||||
<td><span> ' + rdata.data[i]['time'] + '</span></td>\
|
||||
<td style="text-align: right;">\
|
||||
<a class="btlink" onclick="importBackup(\'' + rdata.data[i]['name'] + '\',\'' +db_name+ '\')">导入</a> | \
|
||||
<a class="btlink" onclick="downloadBackup(\'' + rdata.data[i]['file'] + '\')">下载</a> | \
|
||||
<a class="btlink" onclick="delBackup(\'' + rdata.data[i]['name'] + '\',\'' +db_name+ '\')">删除</a>\
|
||||
</td>\
|
||||
</tr> ';
|
||||
}
|
||||
|
||||
var s = layer.open({
|
||||
var layerIndex = layer.open({
|
||||
type: 1,
|
||||
title: "数据库备份详情",
|
||||
area: ['600px', '280px'],
|
||||
closeBtn: 2,
|
||||
closeBtn: 1,
|
||||
shadeClose: false,
|
||||
content: '<div class="pd15">\
|
||||
<div class="db_list">\
|
||||
<button id="btn_backup" class="btn btn-success btn-sm" type="button">备份</button>\
|
||||
<button id="btn_local_import" class="btn btn-success btn-sm" type="button">外部导入</button>\
|
||||
</div >\
|
||||
<div class="divtable">\
|
||||
<div id="database_fix" style="height:150px;overflow:auto;border:#ddd 1px solid">\
|
||||
@@ -945,18 +1057,21 @@ function setBackup(db_name,obj){
|
||||
</table>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>'
|
||||
});
|
||||
</div>',
|
||||
success:function(index){
|
||||
$('#btn_backup').click(function(){
|
||||
myPost('set_db_backup',{name:db_name}, function(data){
|
||||
showMsg('执行成功!', function(){
|
||||
layer.close(layerIndex);
|
||||
setBackup(db_name,obj);
|
||||
}, {icon:1}, 2000);
|
||||
});
|
||||
});
|
||||
|
||||
$('#btn_backup').click(function(){
|
||||
myPost('set_db_backup',{name:db_name}, function(data){
|
||||
layer.msg('执行成功!');
|
||||
|
||||
setTimeout(function(){
|
||||
layer.close(s);
|
||||
setBackup(db_name,obj);
|
||||
},2000);
|
||||
});
|
||||
$('#btn_local_import').click(function(){
|
||||
setLocalImport(db_name);
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1237,7 +1352,7 @@ function repTools(db_name, res){
|
||||
type: 1,
|
||||
title: "MySQL工具箱【" + db_name + "】",
|
||||
area: ['780px', '580px'],
|
||||
closeBtn: 2,
|
||||
closeBtn: 1,
|
||||
shadeClose: false,
|
||||
content: '<div class="pd15">\
|
||||
<div class="db_list">\
|
||||
@@ -1332,7 +1447,7 @@ function addMasterRepSlaveUser(){
|
||||
yes:function(index){
|
||||
var data = $("#add_master").serialize();
|
||||
data = decodeURIComponent(data);
|
||||
var dataObj = str2Obj(data);
|
||||
var dataObj = toArrayObject(data);
|
||||
if(!dataObj['address']){
|
||||
dataObj['address'] = dataObj['dataAccess'];
|
||||
}
|
||||
@@ -1377,7 +1492,7 @@ function updateMasterRepSlaveUser(username){
|
||||
$('#submit_update_master').click(function(){
|
||||
var data = $("#update_master").serialize();
|
||||
data = decodeURIComponent(data);
|
||||
var dataObj = str2Obj(data);
|
||||
var dataObj = toArrayObject(data);
|
||||
myPost('update_master_rep_slave_user', data, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
@@ -1488,7 +1603,7 @@ function setDbMasterAccess(username){
|
||||
yes:function(index){
|
||||
var data = $("#set_db_access").serialize();
|
||||
data = decodeURIComponent(data);
|
||||
var dataObj = str2Obj(data);
|
||||
var dataObj = toArrayObject(data);
|
||||
if(!dataObj['access']){
|
||||
dataObj['access'] = dataObj['dataAccess'];
|
||||
if ( dataObj['dataAccess'] == 'ip'){
|
||||
|
||||
@@ -17,7 +17,7 @@ sysName=`uname`
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
mysqlDir=${serverPath}/source/mysql
|
||||
|
||||
VERSION="5.7.39"
|
||||
VERSION=5.7.39
|
||||
|
||||
|
||||
Install_mysql()
|
||||
@@ -64,11 +64,11 @@ Install_mysql()
|
||||
cd ${rootPath}/plugins/mysql/lib && /bin/bash rpcgen.sh
|
||||
|
||||
if [ ! -f ${mysqlDir}/mysql-boost-${VERSION}.tar.gz ];then
|
||||
wget -O ${mysqlDir}/mysql-boost-${VERSION}.tar.gz --tries=3 https://cdn.mysql.com/Downloads/MySQL-5.7/mysql-boost-${VERSION}.tar.gz
|
||||
wget -O ${mysqlDir}/mysql-boost-${VERSION}.tar.gz --tries=3 https://cdn.mysql.com/archives/mysql-5.7/mysql-boost-${VERSION}.tar.gz
|
||||
fi
|
||||
|
||||
#检测文件是否损坏.
|
||||
md5_mysql_ok=db1b672fc257bd46356c7af26dd22801
|
||||
md5_mysql_ok=d949b0ef81c3f52f7ef0874066244221
|
||||
if [ -f ${mysqlDir}/mysql-boost-${VERSION}.tar.gz ];then
|
||||
md5_mysql=`md5sum ${mysqlDir}/mysql-boost-${VERSION}.tar.gz | awk '{print $1}'`
|
||||
if [ "${md5_mysql_ok}" == "${md5_mysql}" ]; then
|
||||
@@ -76,7 +76,7 @@ Install_mysql()
|
||||
else
|
||||
# 重新下载
|
||||
rm -rf ${mysqlDir}/mysql-${VERSION}
|
||||
wget -O ${mysqlDir}/mysql-boost-${VERSION}.tar.gz --tries=3 https://cdn.mysql.com/Downloads/MySQL-5.7/mysql-boost-${VERSION}.tar.gz
|
||||
wget -O ${mysqlDir}/mysql-boost-${VERSION}.tar.gz --tries=3 https://cdn.mysql.com/archives/mysql-5.7/mysql-boost-${VERSION}.tar.gz
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ fi
|
||||
VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
|
||||
|
||||
|
||||
VERSION=8.0.28
|
||||
VERSION=8.0.30
|
||||
Install_mysql()
|
||||
{
|
||||
mkdir -p ${mysqlDir}
|
||||
@@ -107,11 +107,11 @@ Install_mysql()
|
||||
fi
|
||||
|
||||
if [ ! -f ${mysqlDir}/mysql-boost-${VERSION}.tar.gz ];then
|
||||
wget -O ${mysqlDir}/mysql-boost-${VERSION}.tar.gz --tries=3 https://cdn.mysql.com/Downloads/MySQL-8.0/mysql-boost-${VERSION}.tar.gz
|
||||
wget -O ${mysqlDir}/mysql-boost-${VERSION}.tar.gz --tries=3 https://cdn.mysql.com/archives/mysql-8.0/mysql-boost-${VERSION}.tar.gz
|
||||
fi
|
||||
|
||||
#检测文件是否损坏.
|
||||
md5_mysql_ok=362b8141ecaf425b803fe55292e2df98
|
||||
md5_mysql_ok=313d625fcaa932bd87b48f0cf9b40f1c
|
||||
if [ -f ${mysqlDir}/mysql-boost-${VERSION}.tar.gz ];then
|
||||
md5_mysql=`md5sum ${mysqlDir}/mysql-boost-${VERSION}.tar.gz | awk '{print $1}'`
|
||||
if [ "${md5_mysql_ok}" == "${md5_mysql}" ]; then
|
||||
@@ -119,7 +119,7 @@ Install_mysql()
|
||||
else
|
||||
# 重新下载
|
||||
rm -rf ${mysqlDir}/mysql-${VERSION}
|
||||
wget -O ${mysqlDir}/mysql-boost-${VERSION}.tar.gz --tries=3 https://cdn.mysql.com/Downloads/MySQL-8.0/mysql-boost-${VERSION}.tar.gz
|
||||
wget -O ${mysqlDir}/mysql-boost-${VERSION}.tar.gz --tries=3 https://cdn.mysql.com/archives/mysql-8.0/mysql-boost-${VERSION}.tar.gz
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
class luamaker:
|
||||
"""
|
||||
lua 处理器
|
||||
"""
|
||||
@staticmethod
|
||||
def makeLuaTable(table):
|
||||
"""
|
||||
table 转换为 lua table 字符串
|
||||
"""
|
||||
_tableMask = {}
|
||||
_keyMask = {}
|
||||
|
||||
def analysisTable(_table, _indent, _parent):
|
||||
if isinstance(_table, tuple):
|
||||
_table = list(_table)
|
||||
if isinstance(_table, list):
|
||||
_table = dict(zip(range(1, len(_table) + 1), _table))
|
||||
if isinstance(_table, dict):
|
||||
_tableMask[id(_table)] = _parent
|
||||
cell = []
|
||||
thisIndent = _indent + " "
|
||||
for k in _table:
|
||||
if sys.version_info[0] == 2:
|
||||
if type(k) not in [int, float, bool, list, dict, tuple]:
|
||||
k = k.encode()
|
||||
|
||||
if not (isinstance(k, str) or isinstance(k, int) or isinstance(k, float)):
|
||||
return
|
||||
key = isinstance(
|
||||
k, int) and "[" + str(k) + "]" or "[\"" + str(k) + "\"]"
|
||||
if _parent + key in _keyMask.keys():
|
||||
return
|
||||
_keyMask[_parent + key] = True
|
||||
var = None
|
||||
v = _table[k]
|
||||
if sys.version_info[0] == 2:
|
||||
if type(v) not in [int, float, bool, list, dict, tuple]:
|
||||
v = v.encode()
|
||||
if isinstance(v, str):
|
||||
# print("lua", var)
|
||||
v = v.replace("\\", "\\\\")
|
||||
v = v.replace("\"", "\\\"")
|
||||
var = "\"" + v + "\""
|
||||
|
||||
elif isinstance(v, bool):
|
||||
var = v and "true" or "false"
|
||||
elif isinstance(v, int) or isinstance(v, float):
|
||||
var = str(v)
|
||||
else:
|
||||
var = analysisTable(v, thisIndent, _parent + key)
|
||||
|
||||
cell.append(thisIndent + key + " = " + str(var))
|
||||
lineJoin = ",\n"
|
||||
return "{\n" + lineJoin.join(cell) + "\n" + _indent + "}"
|
||||
else:
|
||||
pass
|
||||
return analysisTable(table, "", "root")
|
||||
@@ -0,0 +1,17 @@
|
||||
PRAGMA synchronous = 0;
|
||||
PRAGMA page_size = 4096;
|
||||
PRAGMA journal_mode = wal;
|
||||
PRAGMA journal_size_limit = 1073741824;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `logs` (
|
||||
`time` INTEGER,
|
||||
`ip` TEXT,
|
||||
`domain` TEXT,
|
||||
`server_name` TEXT,
|
||||
`method` TEXT,
|
||||
`status_code` INTEGER,
|
||||
`user_agent` TEXT,
|
||||
`uri` TEXT,
|
||||
`rule_name` TEXT,
|
||||
`reason` TEXT
|
||||
);
|
||||
@@ -1,8 +1,10 @@
|
||||
lua_shared_dict limit 30m;
|
||||
lua_shared_dict drop_ip 10m;
|
||||
lua_shared_dict drop_sum 10m;
|
||||
lua_package_path "{$WAF_PATH}/lua/?.lua;{$ROOT_PATH}/openresty/lualib/?.lua;;";
|
||||
lua_shared_dict waf_limit 30m;
|
||||
lua_shared_dict waf_drop_ip 10m;
|
||||
lua_shared_dict waf_drop_sum 10m;
|
||||
lua_package_path "{$WAF_PATH}/html/?.lua;{$WAF_PATH}/conf/?.lua;{$WAF_PATH}/lua/?.lua;{$ROOT_PATH}/openresty/lualib/?.lua;;";
|
||||
lua_package_cpath "{$WAF_PATH}/conf/?.so;{$ROOT_PATH}/openresty/lualib/?.so;;";
|
||||
|
||||
init_worker_by_lua_file {$WAF_PATH}/lua/init_worker.lua;
|
||||
access_by_lua_file {$WAF_PATH}/lua/init.lua;
|
||||
|
||||
#init_by_lua_file {$WAF_PATH}/lua/init.lua;
|
||||
#access_by_lua_file {$WAF_PATH}/lua/waf.lua;
|
||||
# init_by_lua_file {$WAF_PATH}/lua/init.lua;
|
||||
|
||||
@@ -1,4 +1,18 @@
|
||||
<style>
|
||||
|
||||
.overflow_hide {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.cur {
|
||||
background-color: #20a53a;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/*waf*/
|
||||
.lib-con-title {
|
||||
height: 26px;
|
||||
@@ -231,8 +245,8 @@
|
||||
<p onclick="wafScreen();">首页</p>
|
||||
<p onclick="wafGloabl();">全局配置</p>
|
||||
<p onclick="wafSite();">站点配置</p>
|
||||
<p onclick="wafHistory();">封锁历史</p>
|
||||
<p onclick="wafLogs();">操作日志</p>
|
||||
<p onclick="wafLogs();">封锁历史</p>
|
||||
<!-- <p onclick="wafOpLogs();">操作日志</p> -->
|
||||
</div>
|
||||
<!-- lib-con -->
|
||||
<div class="bt-w-con pd15">
|
||||
|
||||
+270
-26
@@ -52,11 +52,50 @@ def checkArgs(data, ck=[]):
|
||||
return (True, mw.returnJson(True, 'ok'))
|
||||
|
||||
|
||||
sys.path.append(getPluginDir() + "/class")
|
||||
from luamaker import luamaker
|
||||
|
||||
|
||||
def listToLuaFile(path, lists):
|
||||
content = luamaker.makeLuaTable(lists)
|
||||
content = "return " + content
|
||||
mw.writeFile(path, content)
|
||||
|
||||
|
||||
def htmlToLuaFile(path, content):
|
||||
content = "return [[" + content + "]]"
|
||||
mw.writeFile(path, content)
|
||||
|
||||
|
||||
def getConf():
|
||||
path = mw.getServerDir() + "/openresty/nginx/conf/nginx.conf"
|
||||
return path
|
||||
|
||||
|
||||
def pSqliteDb(dbname='logs'):
|
||||
name = "waf"
|
||||
db_dir = getServerDir() + '/logs/'
|
||||
|
||||
if not os.path.exists(db_dir):
|
||||
mw.execShell('mkdir -p ' + db_dir)
|
||||
|
||||
file = db_dir + name + '.db'
|
||||
if not os.path.exists(file):
|
||||
conn = mw.M(dbname).dbPos(db_dir, name)
|
||||
sql = mw.readFile(getPluginDir() + '/conf/init.sql')
|
||||
sql_list = sql.split(';')
|
||||
for index in range(len(sql_list)):
|
||||
conn.execute(sql_list[index])
|
||||
else:
|
||||
conn = mw.M(dbname).dbPos(db_dir, name)
|
||||
|
||||
conn.execute("PRAGMA synchronous = 0")
|
||||
conn.execute("PRAGMA page_size = 4096")
|
||||
conn.execute("PRAGMA journal_mode = wal")
|
||||
conn.execute("PRAGMA journal_size_limit = 1073741824")
|
||||
return conn
|
||||
|
||||
|
||||
def initDomainInfo():
|
||||
data = []
|
||||
path_domains = getJsonPath('domains')
|
||||
@@ -107,7 +146,7 @@ def initSiteInfo():
|
||||
site_contents_new[name] = site_contents[name]
|
||||
else:
|
||||
tmp = {}
|
||||
tmp['cdn'] = False
|
||||
tmp['cdn'] = True
|
||||
tmp['log'] = True
|
||||
tmp['get'] = True
|
||||
tmp['post'] = True
|
||||
@@ -120,6 +159,7 @@ def initSiteInfo():
|
||||
tmp['user-agent'] = config_contents['user-agent']
|
||||
tmp['cookie'] = config_contents['cookie']
|
||||
tmp['scan'] = config_contents['scan']
|
||||
tmp['safe_verify'] = config_contents['safe_verify']
|
||||
|
||||
cdn_header = ['x-forwarded-for',
|
||||
'x-real-ip',
|
||||
@@ -132,7 +172,6 @@ def initSiteInfo():
|
||||
'cdn-src-ip',
|
||||
'cdn-real-ip',
|
||||
'cf-connecting-ip',
|
||||
'cf-connecting-ip',
|
||||
'x-cluster-client-ip',
|
||||
'wl-proxy-client-ip',
|
||||
'proxy-client-ip',
|
||||
@@ -178,7 +217,9 @@ def initTotalInfo():
|
||||
tmp['get'] = 0
|
||||
tmp['post'] = 0
|
||||
tmp['total'] = 0
|
||||
tmp['url_ext'] = 0
|
||||
tmp['path'] = 0
|
||||
tmp['php_path'] = 0
|
||||
tmp['upload_ext'] = 0
|
||||
_name = {}
|
||||
_name[name] = tmp
|
||||
total_contents['sites'] = _name
|
||||
@@ -211,10 +252,89 @@ def contentReplace(content):
|
||||
return content
|
||||
|
||||
|
||||
def autoMakeLuaConfSingle(file):
|
||||
# path = getPluginDir() + "/waf/rule/" + file + ".json"
|
||||
path = getServerDir() + "/waf/rule/" + file + ".json"
|
||||
to_path = getServerDir() + "/waf/conf/rule_" + file + ".lua"
|
||||
content = mw.readFile(path)
|
||||
# print(content)
|
||||
content = json.loads(content)
|
||||
listToLuaFile(to_path, content)
|
||||
|
||||
|
||||
def autoMakeLuaImportSingle(file):
|
||||
path = getServerDir() + "/waf/" + file + ".json"
|
||||
to_path = getServerDir() + "/waf/conf/waf_" + file + ".lua"
|
||||
content = mw.readFile(path)
|
||||
# print(content)
|
||||
content = json.loads(content)
|
||||
listToLuaFile(to_path, content)
|
||||
|
||||
|
||||
def autoMakeLuaHtmlSingle(file):
|
||||
path = getServerDir() + "/waf/html/" + file + ".html"
|
||||
to_path = getServerDir() + "/waf/html/html_" + file + ".lua"
|
||||
content = mw.readFile(path)
|
||||
htmlToLuaFile(to_path, content)
|
||||
|
||||
|
||||
def autoMakeLuaConf():
|
||||
conf_list = ['args', 'cookie', 'ip_black', 'ip_white',
|
||||
'ipv6_black', 'post', 'scan_black', 'url',
|
||||
'url_white', 'user_agent']
|
||||
for x in conf_list:
|
||||
autoMakeLuaConfSingle(x)
|
||||
|
||||
import_list = ['config', 'site', 'domains']
|
||||
for x in import_list:
|
||||
autoMakeLuaImportSingle(x)
|
||||
|
||||
html_list = ['get', 'post', 'safe_js', 'user_agent', 'cookie', 'other']
|
||||
for x in html_list:
|
||||
autoMakeLuaHtmlSingle(x)
|
||||
|
||||
|
||||
def initDefaultInfo():
|
||||
path = getServerDir()
|
||||
djson = path + "/waf/domains.json"
|
||||
default_json = path + "/waf/default.json"
|
||||
if os.path.exists(djson):
|
||||
content = mw.readFile(djson)
|
||||
content = json.loads(content)
|
||||
|
||||
ddata = {}
|
||||
dlist = []
|
||||
for i in content:
|
||||
dlist.append(i["name"])
|
||||
|
||||
dlist.append('unset')
|
||||
ddata["list"] = dlist
|
||||
if len(ddata["list"]) < 1:
|
||||
ddata["default"] = "unset"
|
||||
else:
|
||||
ddata["default"] = dlist[0]
|
||||
|
||||
mw.writeFile(default_json, json.dumps(ddata))
|
||||
|
||||
|
||||
def autoMakeConfig():
|
||||
path = getServerDir()
|
||||
|
||||
initDomainInfo()
|
||||
initSiteInfo()
|
||||
initTotalInfo()
|
||||
autoMakeLuaConf()
|
||||
|
||||
|
||||
def restartWeb():
|
||||
autoMakeConfig()
|
||||
mw.restartWeb()
|
||||
|
||||
|
||||
def initDreplace():
|
||||
|
||||
path = getServerDir()
|
||||
if not os.path.exists(path + '/waf'):
|
||||
if not os.path.exists(path + '/waf/lua'):
|
||||
sdir = getPluginDir() + '/waf'
|
||||
cmd = 'cp -rf ' + sdir + ' ' + path
|
||||
mw.execShell(cmd)
|
||||
@@ -245,6 +365,11 @@ def initDreplace():
|
||||
content = contentReplace(content)
|
||||
mw.writeFile(config_common, content)
|
||||
|
||||
init_worker = path + "/waf/lua/init_worker.lua"
|
||||
content = mw.readFile(init_worker)
|
||||
content = contentReplace(content)
|
||||
mw.writeFile(init_worker, content)
|
||||
|
||||
waf_conf = mw.getServerDir() + "/openresty/nginx/conf/luawaf.conf"
|
||||
waf_tpl = getPluginDir() + "/conf/luawaf.conf"
|
||||
content = mw.readFile(waf_tpl)
|
||||
@@ -254,6 +379,10 @@ def initDreplace():
|
||||
initDomainInfo()
|
||||
initSiteInfo()
|
||||
initTotalInfo()
|
||||
autoMakeLuaConf()
|
||||
initDefaultInfo()
|
||||
|
||||
pSqliteDb()
|
||||
|
||||
if not mw.isAppleSystem():
|
||||
mw.execShell("chown -R www:www " + path)
|
||||
@@ -267,6 +396,9 @@ def start():
|
||||
conf = conf.replace('#include luawaf.conf;', "include luawaf.conf;")
|
||||
mw.writeFile(path, conf)
|
||||
|
||||
import tool_task
|
||||
tool_task.createBgTask()
|
||||
|
||||
mw.restartWeb()
|
||||
return 'ok'
|
||||
|
||||
@@ -277,6 +409,10 @@ def stop():
|
||||
conf = conf.replace('include luawaf.conf;', "#include luawaf.conf;")
|
||||
|
||||
mw.writeFile(path, conf)
|
||||
|
||||
import tool_task
|
||||
tool_task.removeBgTask()
|
||||
|
||||
mw.restartWeb()
|
||||
return 'ok'
|
||||
|
||||
@@ -288,8 +424,19 @@ def restart():
|
||||
|
||||
def reload():
|
||||
stop()
|
||||
mw.execShell('rm -rf ' + mw.getServerDir() +
|
||||
"/openresty/nginx/logs/error.log")
|
||||
|
||||
path = getServerDir()
|
||||
path_tpl = getPluginDir()
|
||||
|
||||
config = path + "/waf/lua/init.lua"
|
||||
config_tpl = path_tpl + "/waf/lua/init.lua"
|
||||
content = mw.readFile(config_tpl)
|
||||
content = contentReplace(content)
|
||||
mw.writeFile(config, content)
|
||||
|
||||
errlog = mw.getServerDir() + "/openresty/nginx/logs/error.log"
|
||||
mw.execShell('rm -rf ' + errlog)
|
||||
|
||||
start()
|
||||
return 'ok'
|
||||
|
||||
@@ -340,7 +487,7 @@ def addRule():
|
||||
|
||||
cjson = mw.getJson(content)
|
||||
mw.writeFile(fpath, cjson)
|
||||
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!', content)
|
||||
|
||||
|
||||
@@ -362,7 +509,7 @@ def removeRule():
|
||||
|
||||
cjson = mw.getJson(content)
|
||||
mw.writeFile(fpath, cjson)
|
||||
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!', content)
|
||||
|
||||
|
||||
@@ -387,7 +534,7 @@ def setRuleState():
|
||||
|
||||
cjson = mw.getJson(content)
|
||||
mw.writeFile(fpath, cjson)
|
||||
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!', content)
|
||||
|
||||
|
||||
@@ -418,7 +565,7 @@ def modifyRule():
|
||||
|
||||
cjson = mw.getJson(content)
|
||||
mw.writeFile(fpath, cjson)
|
||||
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!', content)
|
||||
|
||||
|
||||
@@ -459,6 +606,7 @@ def addSiteRule():
|
||||
|
||||
cjson = mw.getJson(content)
|
||||
mw.writeFile(path, cjson)
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
|
||||
@@ -494,6 +642,7 @@ def addIpWhite():
|
||||
|
||||
cjson = mw.getJson(content)
|
||||
mw.writeFile(path, cjson)
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
|
||||
@@ -514,6 +663,8 @@ def removeIpWhite():
|
||||
|
||||
cjson = mw.getJson(content)
|
||||
mw.writeFile(path, cjson)
|
||||
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
|
||||
@@ -549,6 +700,8 @@ def addIpBlack():
|
||||
|
||||
cjson = mw.getJson(content)
|
||||
mw.writeFile(path, cjson)
|
||||
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
|
||||
@@ -569,6 +722,8 @@ def removeIpBlack():
|
||||
|
||||
cjson = mw.getJson(content)
|
||||
mw.writeFile(path, cjson)
|
||||
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
|
||||
@@ -587,6 +742,7 @@ def setIpv6Black():
|
||||
|
||||
cjson = mw.getJson(content)
|
||||
mw.writeFile(path, cjson)
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
|
||||
@@ -603,9 +759,10 @@ def delIpv6Black():
|
||||
content = json.loads(content)
|
||||
|
||||
content.remove(addr)
|
||||
|
||||
cjson = mw.getJson(content)
|
||||
mw.writeFile(path, cjson)
|
||||
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
|
||||
@@ -628,6 +785,8 @@ def removeSiteRule():
|
||||
|
||||
cjson = mw.getJson(content)
|
||||
mw.writeFile(path, cjson)
|
||||
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
|
||||
@@ -642,11 +801,13 @@ def setObjStatus():
|
||||
cobj = json.loads(content)
|
||||
|
||||
o = args['obj']
|
||||
status = args['statusCode']
|
||||
status = int(args['statusCode'])
|
||||
cobj[o]['status'] = status
|
||||
|
||||
cjson = mw.getJson(cobj)
|
||||
mw.writeFile(conf, cjson)
|
||||
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
|
||||
@@ -666,6 +827,32 @@ def setRetry():
|
||||
cjson = mw.getJson(cobj)
|
||||
mw.writeFile(conf, cjson)
|
||||
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!', [])
|
||||
|
||||
|
||||
def setSafeVerify():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['auto', 'time', 'cpu'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
conf = getJsonPath('config')
|
||||
content = mw.readFile(conf)
|
||||
cobj = json.loads(content)
|
||||
|
||||
cobj['safe_verify']['time'] = args['time']
|
||||
cobj['safe_verify']['cpu'] = args['cpu']
|
||||
|
||||
if args['auto'] == '0':
|
||||
cobj['safe_verify']['auto'] = False
|
||||
else:
|
||||
cobj['safe_verify']['auto'] = True
|
||||
|
||||
cjson = mw.getJson(cobj)
|
||||
mw.writeFile(conf, cjson)
|
||||
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!', [])
|
||||
|
||||
|
||||
@@ -676,7 +863,7 @@ def setSiteRetry():
|
||||
def setCcConf():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['siteName', 'cycle', 'limit',
|
||||
'endtime', 'is_open_global', 'increase'])
|
||||
'endtime', 'is_open_global'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
@@ -695,6 +882,8 @@ def setCcConf():
|
||||
|
||||
cjson = mw.getJson(cobj)
|
||||
mw.writeFile(conf, cjson)
|
||||
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!', [])
|
||||
|
||||
|
||||
@@ -711,6 +900,8 @@ def saveScanRule():
|
||||
path = getRuleJsonPath('scan_black')
|
||||
cjson = mw.getJson(args)
|
||||
mw.writeFile(path, cjson)
|
||||
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!', [])
|
||||
|
||||
|
||||
@@ -750,6 +941,26 @@ def getSiteConfig():
|
||||
return mw.returnJson(True, 'ok!', content)
|
||||
|
||||
|
||||
def getSiteListData():
|
||||
path = getServerDir() + "/waf/default.json"
|
||||
data = mw.readFile(path)
|
||||
return json.loads(data)
|
||||
|
||||
|
||||
def setDefaultSite(name):
|
||||
path = getServerDir() + "/waf/default.json"
|
||||
data = mw.readFile(path)
|
||||
data = json.loads(data)
|
||||
data['default'] = name
|
||||
mw.writeFile(path, json.dumps(data))
|
||||
return mw.returnJson(True, 'OK')
|
||||
|
||||
|
||||
def getDefaultSite():
|
||||
data = getSiteListData()
|
||||
return mw.returnJson(True, 'OK', data)
|
||||
|
||||
|
||||
def getSiteConfigByName():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['siteName'])
|
||||
@@ -783,6 +994,8 @@ def addSiteCdnHeader():
|
||||
|
||||
cjson = mw.getJson(content)
|
||||
mw.writeFile(path, cjson)
|
||||
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '添加成功!')
|
||||
|
||||
|
||||
@@ -802,6 +1015,8 @@ def removeSiteCdnHeader():
|
||||
|
||||
cjson = mw.getJson(content)
|
||||
mw.writeFile(path, cjson)
|
||||
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '删除成功!')
|
||||
|
||||
|
||||
@@ -824,29 +1039,44 @@ def importData():
|
||||
|
||||
path = getRuleJsonPath(args['s_Name'])
|
||||
mw.writeFile(path, args['pdata'])
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
|
||||
def getLogsList():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['siteName'])
|
||||
data = checkArgs(args, ['site', 'page', 'page_size', 'tojs'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
data = []
|
||||
path = getServerDir() + '/logs'
|
||||
page = int(args['page'])
|
||||
page_size = int(args['page_size'])
|
||||
domain = args['site']
|
||||
tojs = args['tojs']
|
||||
|
||||
if not os.path.exists(path):
|
||||
return mw.returnJson(False, '还未生成!', [])
|
||||
conn = pSqliteDb('logs')
|
||||
|
||||
files = os.listdir(path)
|
||||
for f in files:
|
||||
if f == '.DS_Store':
|
||||
continue
|
||||
f = f.split('_')
|
||||
if f[0] == args['siteName']:
|
||||
fl = f[1].split('.')
|
||||
data.append(fl[0])
|
||||
field = 'time,ip,domain,server_name,method,uri,user_agent,rule_name,reason'
|
||||
limit = str(page_size) + ' offset ' + str(page_size * (page - 1))
|
||||
|
||||
condition = ''
|
||||
conn = conn.field(field)
|
||||
conn = conn.where("1=1", ()).where("domain=?", (domain,))
|
||||
|
||||
clist = conn.limit(limit).order('time desc').inquiry()
|
||||
count_key = "count(*) as num"
|
||||
count = conn.field(count_key).limit('').order('').inquiry()
|
||||
# print(count)
|
||||
count = count[0][count_key]
|
||||
|
||||
data = {}
|
||||
_page = {}
|
||||
_page['count'] = count
|
||||
_page['p'] = page
|
||||
_page['row'] = page_size
|
||||
_page['tojs'] = tojs
|
||||
data['page'] = mw.getPage(_page)
|
||||
data['data'] = clist
|
||||
|
||||
return mw.returnJson(True, 'ok!', data)
|
||||
|
||||
@@ -893,6 +1123,7 @@ def setObjOpen():
|
||||
|
||||
cjson = mw.getJson(cobj)
|
||||
mw.writeFile(conf, cjson)
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
|
||||
@@ -922,6 +1153,7 @@ def setSiteObjOpen():
|
||||
|
||||
cjson = mw.getJson(content)
|
||||
mw.writeFile(path, cjson)
|
||||
restartWeb()
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
|
||||
@@ -942,6 +1174,12 @@ def installPreInspection():
|
||||
return 'ok'
|
||||
|
||||
|
||||
def cleanDropIp():
|
||||
url = "http://127.0.0.1/clean_waf_drop_ip"
|
||||
data = mw.httpGet(url)
|
||||
return mw.returnJson(True, 'ok!', data)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
func = sys.argv[1]
|
||||
if func == 'status':
|
||||
@@ -998,12 +1236,16 @@ if __name__ == "__main__":
|
||||
print(setSiteCcConf())
|
||||
elif func == 'set_retry':
|
||||
print(setRetry())
|
||||
elif func == 'set_safe_verify':
|
||||
print(setSafeVerify())
|
||||
elif func == 'set_site_retry':
|
||||
print(setSiteRetry())
|
||||
elif func == 'save_scan_rule':
|
||||
print(saveScanRule())
|
||||
elif func == 'get_site_config':
|
||||
print(getSiteConfig())
|
||||
elif func == 'get_default_site':
|
||||
print(getDefaultSite())
|
||||
elif func == 'get_site_config_byname':
|
||||
print(getSiteConfigByName())
|
||||
elif func == 'add_site_cdn_header':
|
||||
@@ -1024,5 +1266,7 @@ if __name__ == "__main__":
|
||||
print(getWafConf())
|
||||
elif func == 'waf_site':
|
||||
print(getWafSite())
|
||||
elif func == 'clean_drop_ip':
|
||||
print(cleanDropIp())
|
||||
else:
|
||||
print('error')
|
||||
|
||||
@@ -11,5 +11,5 @@
|
||||
"home":"https://github.com/loveshell/ngx_lua_waf",
|
||||
"date":"2019-04-21",
|
||||
"pid": "1",
|
||||
"versions": ["0.1"]
|
||||
"versions": ["0.2.3"]
|
||||
}
|
||||
@@ -7,31 +7,99 @@ rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
|
||||
action=$1
|
||||
version=$2
|
||||
sys_os=`uname`
|
||||
|
||||
if [ -f ${rootPath}/bin/activate ];then
|
||||
source ${rootPath}/bin/activate
|
||||
fi
|
||||
|
||||
if [ "$sys_os" == "Darwin" ];then
|
||||
BAK='_bak'
|
||||
else
|
||||
BAK=''
|
||||
fi
|
||||
|
||||
|
||||
Install_of(){
|
||||
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
mkdir -p $serverPath/source/op_waf
|
||||
mkdir -p $serverPath/op_waf
|
||||
|
||||
echo '0.1' > $serverPath/op_waf/version.pl
|
||||
# luarocks
|
||||
if [ ! -f $serverPath/source/op_waf/luarocks-3.5.0.tar.gz ];then
|
||||
wget --no-check-certificate -O $serverPath/source/op_waf/luarocks-3.5.0.tar.gz http://luarocks.org/releases/luarocks-3.5.0.tar.gz
|
||||
fi
|
||||
|
||||
# which luarocks
|
||||
# if [ "$?" != "0" ];then
|
||||
if [ ! -d $serverPath/op_waf/luarocks ];then
|
||||
cd $serverPath/source/op_waf && tar xvf luarocks-3.5.0.tar.gz
|
||||
# cd luarocks-3.9.1 && ./configure && make bootstrap
|
||||
|
||||
cd luarocks-3.5.0 && ./configure --prefix=$serverPath/op_waf/luarocks --with-lua-include=$serverPath/openresty/luajit/include/luajit-2.1 --with-lua-bin=$serverPath/openresty/luajit/bin
|
||||
make -I${serverPath}/openresty/luajit/bin
|
||||
make install
|
||||
fi
|
||||
|
||||
|
||||
if [ ! -f $serverPath/source/op_waf/lsqlite3_fsl09y.zip ];then
|
||||
wget --no-check-certificate -O $serverPath/source/op_waf/lsqlite3_fsl09y.zip http://lua.sqlite.org/index.cgi/zip/lsqlite3_fsl09y.zip?uuid=fsl_9y
|
||||
cd $serverPath/source/op_waf && unzip lsqlite3_fsl09y.zip
|
||||
fi
|
||||
|
||||
if [ ! -d $serverPath/source/op_waf/lsqlite3_fsl09y ];then
|
||||
cd $serverPath/source/op_waf && unzip lsqlite3_fsl09y.zip
|
||||
fi
|
||||
|
||||
PATH=${serverPath}/openresty/luajit:${serverPath}/openresty/luajit/include/luajit-2.1:$PATH
|
||||
export PATH=$PATH:$serverPath/op_waf/luarocks/bin
|
||||
|
||||
if [ ! -f $serverPath/op_waf/waf/conf/lsqlite3.so ];then
|
||||
if [ "${sys_os}" == "Darwin" ];then
|
||||
cd $serverPath/source/op_waf/lsqlite3_fsl09y
|
||||
find_cfg=`cat Makefile | grep 'SQLITE_DIR'`
|
||||
if [ "$find_cfg" == "" ];then
|
||||
LIB_SQLITE_DIR=`brew info sqlite | grep /usr/local/Cellar/sqlite | cut -d \ -f 1 | awk 'END {print}'`
|
||||
echo $LIB_SQLITE_DIR
|
||||
sed -i $BAK "s#\$(ROCKSPEC)#\$(ROCKSPEC) SQLITE_DIR=${LIB_SQLITE_DIR}#g" Makefile
|
||||
fi
|
||||
make
|
||||
else
|
||||
cd $serverPath/source/op_waf/lsqlite3_fsl09y && make
|
||||
fi
|
||||
fi
|
||||
|
||||
# copy to code path
|
||||
DEFAULT_DIR=$serverPath/op_waf/luarocks/lib/lua/5.1
|
||||
if [ -f ${DEFAULT_DIR}/lsqlite3.so ];then
|
||||
mkdir -p $serverPath/op_waf/waf/conf
|
||||
cp -rf ${DEFAULT_DIR}/lsqlite3.so $serverPath/op_waf/waf/conf/lsqlite3.so
|
||||
fi
|
||||
|
||||
echo "${version}" > $serverPath/op_waf/version.pl
|
||||
echo 'install ok' > $install_tmp
|
||||
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/op_waf/index.py start
|
||||
|
||||
|
||||
|
||||
# cd ${rootPath} && python3 ${rootPath}/plugins/op_waf/index.py restart
|
||||
}
|
||||
|
||||
Uninstall_of(){
|
||||
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/op_waf/index.py stop
|
||||
rm -rf $serverPath/op_waf
|
||||
if [ "$?" == "0" ];then
|
||||
rm -rf $serverPath/op_waf
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
action=$1
|
||||
type=$2
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_of
|
||||
|
||||
+369
-199
@@ -69,8 +69,10 @@ function setObjOpen(ruleName){
|
||||
owPost('set_obj_open', {obj:ruleName},function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
if (rdata.status){
|
||||
layer.msg(rdata.msg,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
wafGloabl();
|
||||
|
||||
showMsg(rdata.msg, function(){
|
||||
wafGloabl();
|
||||
},{icon:1,time:2000,shade: [0.3, '#000']},2000);
|
||||
} else {
|
||||
layer.msg('设置失败!',{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
}
|
||||
@@ -84,7 +86,7 @@ function saveCcRule(siteName,is_open_global, type) {
|
||||
if(type == 2){
|
||||
// set_aicc_open('start');
|
||||
increase = "0";
|
||||
}else{
|
||||
} else {
|
||||
// set_aicc_open('stop');
|
||||
increase = type;
|
||||
}
|
||||
@@ -164,7 +166,10 @@ function setCcRule(cycle, limit, endtime, siteName, increase){
|
||||
<li>请不要设置过于严格的CC规则,以免影响正常用户体验</li>\
|
||||
<li><font style="color:red;display:'+ (siteName == 'undefined'?'display: inline-block;':'none') +';">全局应用:全局设置当前CC规则,且覆盖当前全部站点的CC规则</font></li>\
|
||||
</ul>\
|
||||
<div class="bt-form-submit-btn"><button type="button" class="btn btn-danger btn-sm btn_cc_all" style="margin-right:10px;display:'+ (siteName == 'undefined'?'display: inline-block;':'none') +';">全局应用</button><button type="button" class="btn btn-success btn-sm btn_cc_present">应用</button></div>\
|
||||
<div class="bt-form-submit-btn">\
|
||||
<button type="button" class="btn btn-danger btn-sm btn_cc_all" style="margin-right:10px;display:'+ (siteName == 'undefined'?'display: inline-block;':'none') +';">全局应用</button>\
|
||||
<button type="button" class="btn btn-success btn-sm btn_cc_present">应用</button>\
|
||||
</div>\
|
||||
</form>',
|
||||
success:function(layero,index){
|
||||
$('.btn_cc_all').click(function(){
|
||||
@@ -201,9 +206,12 @@ function setRetry(retry_cycle, retry, retry_time, siteName) {
|
||||
</div>\
|
||||
<ul class="help-info-text c7 ptb10">\
|
||||
<li><font style="color:red;">'+ retry_cycle + '</font> 秒内累计恶意请求超过 <font style="color:red;">' + retry + '</font> 次,封锁 <font style="color:red;">' + retry_time + '</font> 秒</li>\
|
||||
<li><font style="color:red;">全局应用:全局设置当前恶意容忍规则,且覆盖当前全部站点的恶意容忍规则</li>\
|
||||
<li><font style="color:red;">全局应用:全局设置当前恶意容忍规则,且覆盖当前全部站点的恶意容忍规则</font></li>\
|
||||
</ul>\
|
||||
<div class="bt-form-submit-btn"><button type="button" class="btn btn-danger btn-sm btn_retry_all" style="margin-right:10px;display:'+ (siteName == undefined?'inline-block;':'none') +';">全局应用</button><button type="button" class="btn btn-success btn-sm btn_retry_present">应用</button></div>\
|
||||
<div class="bt-form-submit-btn">\
|
||||
<button type="button" class="btn btn-danger btn-sm btn_retry_all" style="margin-right:10px;display:'+ (siteName == undefined?'inline-block;':'none') +';">全局应用</button>\
|
||||
<button type="button" class="btn btn-success btn-sm btn_retry_present">应用</button>\
|
||||
</div>\
|
||||
</form>',
|
||||
success:function(){
|
||||
$('.btn_retry_all').click(function(){
|
||||
@@ -217,6 +225,65 @@ function setRetry(retry_cycle, retry, retry_time, siteName) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
//设置safe_verify规则
|
||||
function setSafeVerify(auto, cpu, time, siteName) {
|
||||
var svlayer = layer.open({
|
||||
type: 1,
|
||||
title: "设置强制安全验证",
|
||||
area: '500px',
|
||||
closeBtn: 1,
|
||||
shadeClose: false,
|
||||
content: '<form class="bt-form pd20 pb70">\
|
||||
<div class="line">\
|
||||
<span class="tname">CPU</span>\
|
||||
<div class="info-r"><input class="bt-input-text" name="cpu" type="number" max-number="100" value="'+ cpu + '" /> %</div>\
|
||||
</div>\
|
||||
<div class="line">\
|
||||
<span class="tname">通行时间</span>\
|
||||
<div class="info-r"><input class="bt-input-text" name="time" type="number" value="'+ time + '" /> 秒</div>\
|
||||
</div>\
|
||||
<div class="line">\
|
||||
<span class="tname">开启自动</span>\
|
||||
<div class="info-r">\
|
||||
<select class="bt-input-text mr5" style="width:80px" name="auto">\
|
||||
<option value="0" '+(auto==false?"selected=selected":"")+'>关闭</option>\
|
||||
<option value="1" '+(auto==true?"selected=selected":"")+'>开启</option>\
|
||||
</select>\
|
||||
</div>\
|
||||
</div>\
|
||||
<ul class="help-info-text c7 ptb10">\
|
||||
<li><font style="color:red;">全局设置强制安全验证</font></li>\
|
||||
<li>开启自动后:cpu超过['+cpu+'%]后,强制验证。</li>\
|
||||
</ul>\
|
||||
<div class="bt-form-submit-btn">\
|
||||
<button type="button" class="btn btn-success btn-sm btn_sv_present">应用</button>\
|
||||
</div>\
|
||||
</form>',
|
||||
success:function(index){
|
||||
$('.btn_sv_present').click(function(){
|
||||
var pdata = {
|
||||
siteName: siteName,
|
||||
cpu: $("input[name='cpu']").val(),
|
||||
auto: $("select[name='auto']").val(),
|
||||
time: $("input[name='time']").val(),
|
||||
}
|
||||
var act = 'set_safe_verify';
|
||||
owPost(act, pdata, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg, function() {
|
||||
layer.close(svlayer);
|
||||
wafGloabl();
|
||||
},{ icon: rdata.status ? 1 : 2 },1000);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//保存retry规则
|
||||
function saveRetry(siteName,type) {
|
||||
var pdata = {
|
||||
@@ -253,15 +320,6 @@ function addRule(ruleName) {
|
||||
},1000);
|
||||
}
|
||||
});
|
||||
|
||||
// var loadT = layer.msg('正在添加,请稍候..', { icon: 16, time: 0 });
|
||||
// $.post('/plugin?action=a&name=btwaf&s=add_rule', pdata, function (rdata) {
|
||||
// layer.close(loadT);
|
||||
// layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
|
||||
// if (rdata.status) {
|
||||
// set_obj_conf(ruleName, 1);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
function modifyRule(index, ruleName) {
|
||||
@@ -633,6 +691,71 @@ function ipWhite(type) {
|
||||
});
|
||||
}
|
||||
|
||||
//IP白名单
|
||||
function urlWhite(type) {
|
||||
|
||||
var ruleName = "url_white";
|
||||
|
||||
if (type == undefined) {
|
||||
create_l = layer.open({
|
||||
type: 1,
|
||||
title: "管理URL白名单",
|
||||
area: ['700px', '530px'],
|
||||
closeBtn: 1,
|
||||
shadeClose: false,
|
||||
content: '<div class="pd15">\
|
||||
<div style="border-bottom:#ccc 1px solid;margin-bottom:10px;padding-bottom:10px">\
|
||||
<input class="bt-input-text" name="ruleValue" type="text" value="" style="width:470px;margin-right:12px;" placeholder="规则内容,请使用正则表达式">\
|
||||
<input class="bt-input-text mr5" name="rulePs" type="text" style="width:120px;" placeholder="描述">\
|
||||
<button class="btn btn-success btn-sm va0 pull-right" onclick="addRule(\''+ ruleName + '\');">添加</button>\</div>\
|
||||
<div class="divtable">\
|
||||
<div id="jc-file-table" class="table_head_fix" style="max-height:300px;overflow:auto;border:#ddd 1px solid">\
|
||||
<table class="table table-hover" style="border:none">\
|
||||
<thead>\
|
||||
<tr>\
|
||||
<th width="360">规则</th>\
|
||||
<th>说明</th>\
|
||||
<th>操作</th>\
|
||||
<th style="text-align: right;">状态</th>\
|
||||
</tr>\
|
||||
</thead>\
|
||||
<tbody id="set_obj_conf_con" class="gztr"></tbody>\
|
||||
</table>\
|
||||
</div>\
|
||||
</div>\
|
||||
<ul class="help-info-text c7 ptb10">\
|
||||
<li style="color:red;">注意:如果您不了解正则表达式,请不要随意修改规则内容</li>\
|
||||
<li>您可以添加或修改规则内容,但请使用正则表达式</li>\
|
||||
<li>内置规则允许修改,但不可以直接删除,您可以设置规则状态来定义防火墙是否使用此规则</li>\
|
||||
</ul></div>'
|
||||
});
|
||||
tableFixed("jc-file-table");
|
||||
}
|
||||
|
||||
getRuleByName(ruleName, function(data){
|
||||
var tmp = $.parseJSON(data.data);
|
||||
var rdata = $.parseJSON(tmp.data);
|
||||
console.log(rdata);
|
||||
var tbody = ''
|
||||
for (var i = 0; i < rdata.length; i++) {
|
||||
var removeRule = ''
|
||||
if (rdata[i][3] != 0) removeRule = ' | <a class="btlink" onclick="removeRule(\'' + ruleName + '\',' + i + ')">删除</a>';
|
||||
tbody += '<tr>\
|
||||
<td class="rule_body_'+ i + '">' + rdata[i][1] + '</td>\
|
||||
<td class="rule_ps_'+ i + '">' + rdata[i][2] + '</td>\
|
||||
<td class="rule_modify_'+ i + '"><a class="btlink" onclick="modifyRule(' + i + ',\'' + ruleName + '\')">编辑</a>' + removeRule + '</td>\
|
||||
<td class="text-right">\
|
||||
<div class="pull-right">\
|
||||
<input class="btswitch btswitch-ios" id="closeua_'+ i + '" type="checkbox" ' + (rdata[i][0] ? 'checked' : '') + '>\
|
||||
<label class="btswitch-btn" style="width:2.0em;height:1.2em;margin-bottom: 0" for="closeua_'+ i + '" onclick="setRuleState(\'' + ruleName + '\',' + i + ')"></label>\
|
||||
</div>\
|
||||
</td>\
|
||||
</tr>'
|
||||
}
|
||||
$("#set_obj_conf_con").html(tbody);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 获取IPV4黑名单
|
||||
function getIpv4Address(callback){
|
||||
@@ -695,6 +818,23 @@ function addIpBlack() {
|
||||
});
|
||||
}
|
||||
|
||||
function addIpBlackArgs(ip) {
|
||||
var pdata = {
|
||||
start_ip: ip,
|
||||
end_ip: ip,
|
||||
}
|
||||
|
||||
if (pdata['start_ip'].split('.').length < 4 || pdata['end_ip'].split('.').length < 4) {
|
||||
layer.msg('起始IP或结束IP格式不正确!');
|
||||
return;
|
||||
}
|
||||
|
||||
owPost('add_ip_black', pdata, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//从IP黑名单删除IP段
|
||||
function removeIpBlack(index) {
|
||||
@@ -820,17 +960,17 @@ function wafScreen(){
|
||||
|
||||
con += '<div class="screen">\
|
||||
<div class="line"><span class="name">POST渗透</span><span class="val">'+rdata.rules.post+'</span></div>\
|
||||
<div class="line"><span class="name">GET渗透</span><span class="val">0</span></div>\
|
||||
<div class="line"><span class="name">GET渗透</span><span class="val">'+rdata.rules.args+'</span></div>\
|
||||
<div class="line"><span class="name">CC攻击</span><span class="val">'+rdata.rules.cc+'</span></div>\
|
||||
<div class="line"><span class="name">恶意User-Agent</span><span class="val">'+rdata.rules.user_agent+'</span></div>\
|
||||
<div class="line"><span class="name">Cookie渗透</span><span class="val">'+rdata.rules.cookie+'</span></div>\
|
||||
<div class="line"><span class="name">恶意扫描</span><span class="val">'+rdata.rules.scan+'</span></div>\
|
||||
<div class="line"><span class="name">恶意HEAD请求</span><span class="val">0</span></div>\
|
||||
<div class="line"><span class="name">URI自定义拦截</span><span class="val">'+rdata.rules.args+'</span></div>\
|
||||
<div class="line"><span class="name">URI自定义拦截</span><span class="val">'+rdata.rules.url+'</span></div>\
|
||||
<div class="line"><span class="name">URI保护</span><span class="val">'+rdata.rules.args+'</span></div>\
|
||||
<div class="line"><span class="name">恶意文件上传</span><span class="val">0</span></div>\
|
||||
<div class="line"><span class="name">禁止的扩展名</span><span class="val">'+rdata.rules.url_ext+'</span></div>\
|
||||
<div class="line"><span class="name">禁止PHP脚本</span><span class="val">0</span></div>\
|
||||
<div class="line"><span class="name">恶意文件上传</span><span class="val">'+rdata.rules.upload_ext+'</span></div>\
|
||||
<div class="line"><span class="name">禁止的扩展名</span><span class="val">'+rdata.rules.path+'</span></div>\
|
||||
<div class="line"><span class="name">禁止PHP脚本</span><span class="val">'+rdata.rules.php_path+'</span></div>\
|
||||
</div>';
|
||||
|
||||
con += '<div style="width:660px;"><ul class="help-info-text c7">\
|
||||
@@ -878,6 +1018,16 @@ function wafGloabl(){
|
||||
<td style="text-align: center;">--</td>\
|
||||
<td class="text-right"><a class="btlink" onclick="setRetry('+ rdata.retry.retry_cycle + ',' + rdata.retry.retry + ',' + rdata.retry.retry_time + ')">初始规则</a></td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td>强制安全验证</td>\
|
||||
<td>'+rdata.safe_verify.ps+'</td>\
|
||||
<td>--</td>\
|
||||
<td style="text-align: center;"><div class="ssh-item">\
|
||||
<input class="btswitch btswitch-ios" id="close_safe_verify" type="checkbox" '+(rdata.safe_verify.open ? 'checked' : '')+'>\
|
||||
<label class="btswitch-btn" for="close_safe_verify" onclick="setObjOpen(\'safe_verify\')"></label></div>\
|
||||
</td>\
|
||||
<td class="text-right"><a class="btlink" onclick="setSafeVerify('+ rdata.safe_verify.auto + ',' + rdata.safe_verify.cpu + ',' + rdata.safe_verify.time + ')">设置</a> | <a class="btlink" href="javascript:;" onclick="onlineEditFile(0,\''+rdata['reqfile_path']+'/safe_js.html\')">响应内容</a></td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td>GET-URI过滤</td>\
|
||||
<td>'+ rdata.get.ps + '</td>\
|
||||
@@ -918,6 +1068,11 @@ function wafGloabl(){
|
||||
<label class="btswitch-btn" for="closescan" onclick="setObjOpen(\'scan\')"></label>\
|
||||
</div></td><td class="text-right"><a class="btlink" onclick="scanRule()">设置</a></td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td>URL白名单</td><td>所有规则对URL白名单无效</td><td style="text-align: center;">--</td>\
|
||||
<td style="text-align: center;">--</td>\
|
||||
<td class="text-right"><a class="btlink" onclick="urlWhite()">设置</a></td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td>IP白名单</td><td>所有规则对IP白名单无效</td><td style="text-align: center;">--</td>\
|
||||
<td style="text-align: center;">--</td>\
|
||||
@@ -940,7 +1095,7 @@ function wafGloabl(){
|
||||
|
||||
con += '<div style="width:645px;margin-top:10px;"><ul class="help-info-text c7">\
|
||||
<li>继承: 全局设置将在站点配置中自动继承为默认值</li>\
|
||||
<li>优先级: IP白名单>IP黑名单>URL白名单>URL黑名单>CC防御>禁止国外IP访问>User-Agent>URI过滤>URL参数>Cookie>POST</li>\
|
||||
<li>优先级: IP白名单>IP黑名单>URL白名单>URL黑名单>CC防御>User-Agent>URI过滤>URL参数>Cookie>POST</li>\
|
||||
</ul></div>';
|
||||
$(".soft-man-con").html(con);
|
||||
});
|
||||
@@ -956,146 +1111,6 @@ function back_css(v) {
|
||||
}
|
||||
}
|
||||
|
||||
//查看网站日志
|
||||
function siteWafLog(siteName) {
|
||||
var loadT = layer.msg('正在处理,请稍候..', { icon: 16, time: 0 });
|
||||
owPost('get_logs_list', { siteName: siteName } , function (data) {
|
||||
var tmp = $.parseJSON(data.data);
|
||||
var rdata = tmp.data;
|
||||
var selectLogDay = "";
|
||||
var day = rdata[0];
|
||||
for (var i = 0; i < rdata.length; i++) {
|
||||
selectLogDay += '<option value="' + rdata[i] + '">' + rdata[i] + '</option>';
|
||||
}
|
||||
if (rdata == "") {
|
||||
layer.msg("暂无日志记录", { icon: 6, shade: 0.3, time: 1000 });
|
||||
return
|
||||
}
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: "日志【" + siteName + "】",
|
||||
area: ['880px', '500px'],
|
||||
closeBtn: 1,
|
||||
shadeClose: false,
|
||||
content: '<div class="lib-box pd15 lib-box-log">\
|
||||
<div class="lib-con-title" style="height:40px"><select id="selectLogDay" class="bt-input-text" onchange="siteLogCon(\''+ siteName + '\',this.options[this.options.selectedIndex].value,1)">' + selectLogDay + '</select></div>\
|
||||
<div class="lib-con">\
|
||||
<div class="divtable">\
|
||||
<div id="site_waf_log" style="max-height:400px;overflow:auto;border:#ddd 1px solid">\
|
||||
<table class="table table-hover" style="border:none;">\
|
||||
<thead><tr><th width="150">时间</th><th width="120">用户IP</th><th width="70">类型</th><th>URI地址</th><th class="tdhide">User-Agent</th><th width="60">状态</th><th width="100">过滤器</th><th class="tdhide">过滤规则</th><th width="100" class="text-right">操作</th></tr></thead>\
|
||||
<tbody id="LogDayCon"></tbody>\
|
||||
</table>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="page pull-right" id="size_log_page" style="margin-top:10px"></div>\
|
||||
</div>\
|
||||
</div>'
|
||||
});
|
||||
siteLogCon(siteName, day, 1);
|
||||
tableFixed("site_waf_log");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//日志内容
|
||||
function siteLogCon(siteName, day, page) {
|
||||
if (!page) page = 1;
|
||||
var last = page - 1;
|
||||
var next = page + 1;
|
||||
var pagehtml = '';
|
||||
$("#site_waf_log").scrollTop(0);
|
||||
|
||||
owPost('get_safe_logs', { siteName: siteName, toDate: day, p: page }, function(data){
|
||||
var tmp = $.parseJSON(data.data);
|
||||
if (!tmp.status){
|
||||
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
|
||||
return;
|
||||
}
|
||||
var rdata = tmp.data;
|
||||
var con = '';
|
||||
for (var i = 0; i < rdata.length; i++) {
|
||||
con += '<tr>\
|
||||
<td class="td0">'+ escapeHTML(rdata[i][0]) + '</td>\
|
||||
<td class="td1"><a class="btlink" href="javascript:add_log_ip_black(\''+ escapeHTML(rdata[i][1]) + '\');" title="加入黑名单">' + escapeHTML(rdata[i][1]) + '</a></td>\
|
||||
<td class="td2">'+ escapeHTML(rdata[i][2]) + '</td>\
|
||||
<td class="td3"><span class="td3txt">'+ escapeHTML(rdata[i][3]) + '</span></td>\
|
||||
<td class="tdhide td4">'+ escapeHTML(rdata[i][4]) + '</td><td>已拦截</td>\
|
||||
<td class="td5"><span class="filtertext">'+ escapeHTML(rdata[i][5]) + '</span></td>\
|
||||
<td class="tdhide td6">'+ escapeHTML(rdata[i][6]) + '</td>\
|
||||
<td class="text-right"><a href="javascript:;" class="btlink submit_msg" data-index="'+ i +'">误报</a> | <a href="javascript:;" class="btlink btwaf_details" data-index="'+ i +'">详细</a></td>\
|
||||
</tr>'
|
||||
}
|
||||
|
||||
$("#LogDayCon").html(con);
|
||||
pagehtml = '<a class="Pstart" onclick="site_log_con(\'' + siteName + '\',\'' + day + '\',1)">首页</a><a class="prevPage" onclick="site_log_con(\'' + siteName + '\',\'' + day + '\',' + last + ')">上一页</a><a class="nextPage" onclick="site_log_con(\'' + siteName + '\',\'' + day + '\',' + next + ')">下一页</a><a class="Pcount">第 ' + page + ' 页</a>';
|
||||
$("#size_log_page").html(pagehtml);
|
||||
if (rdata.length < 1) $(".nextPage").hide();
|
||||
if (last < 1) $(".prevPage").hide();
|
||||
|
||||
// 发送误报请求
|
||||
$(".submit_msg").click(function () {
|
||||
var _this = $(this);
|
||||
var res = rdata[$(this).attr('data-index')];
|
||||
layer.confirm('是否确定提交误报反馈?', { title: '误报反馈',closeBtn:2,icon:3}, function () {
|
||||
var url_address = res[3];
|
||||
var rule_arry = res[6].split(" >> ");
|
||||
var pdata = { url_rule: url_address };
|
||||
var loadT = layer.msg('正在添加URL白名单..', { icon: 16, time: 0 });
|
||||
$.post('/plugin?action=a&name=btwaf&s=add_url_white', pdata, function (rdata) {
|
||||
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
|
||||
layer.close(loadT);
|
||||
if (rule_arry[1] != undefined){ $.get('https://www.bt.cn/Api/add_waf_logs?data=' + rule_arry[1],function(rdata){},'jsonp')}
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
// 详情
|
||||
$(".btwaf_details").click(function () {
|
||||
var res = rdata[$(this).attr('data-index')];
|
||||
var time = res[0]; //时间
|
||||
var ip_address = res[1]; //IP地址
|
||||
var req_type = res[2]; // 请求类型
|
||||
var url_address = res[3]; // 请求类型
|
||||
var user_agent = res[4]; // 请求类型
|
||||
var filters = res[5]; //过滤器
|
||||
var filter_rule = ''; //过滤规则
|
||||
var rule_arry = res[6].split(" >> ");
|
||||
var incoming_value = '',risk_value = ''; //传入值,风险值
|
||||
if(rule_arry.length == 0) filter_rule = rule_arry[0]
|
||||
incoming_value = rule_arry[1] == undefined?'空':rule_arry[1];
|
||||
risk_value = incoming_value.match(new RegExp(rule_arry[0].replace(/\//g,'\\/'),'i'));
|
||||
risk_value = risk_value?risk_value[0]:'空';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: time + "详情",
|
||||
area: '600px',
|
||||
closeBtn: 1,
|
||||
shadeClose: false,
|
||||
content: '<div class="pd15 lib-box">\
|
||||
<table class="table" style="border:#ddd 1px solid; margin-bottom:10px">\
|
||||
<tbody><tr><th>时间</th><td>'+ escapeHTML(time) + '</td><th>用户IP</th><td><a class="btlink" href="javascript:add_log_ip_black(\'' + escapeHTML(ip_address) + '\')" title="加入黑名单">' + escapeHTML(ip_address) + '</a></td></tr><tr><th>类型</th><td>' + escapeHTML(req_type) + '</td><th>过滤器</th><td>' + escapeHTML(filters) + '</td></tr></tbody></table>\
|
||||
<div><b style="margin-left:10px">URI地址</b></div>\
|
||||
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(url_address) + '</div></div>\
|
||||
<div><b style="margin-left:10px">User-Agent</b></div>\
|
||||
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(user_agent) + '</div></div>\
|
||||
<div><b style="margin-left:10px">过滤规则</b></div>\
|
||||
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(rule_arry[0]) + '</div></div>\
|
||||
<div><b style="margin-left:10px">传入值</b></div>\
|
||||
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(incoming_value) + '</div></div>\
|
||||
<div><b style="margin-left:10px">风险值</b></div>\
|
||||
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(risk_value) + '</div></div>\
|
||||
</div>'
|
||||
})
|
||||
})
|
||||
$("#LogDayCon td").click(function () {
|
||||
$(this).parents("tr").addClass("active").siblings().removeClass("active");
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function html_encode(value) {
|
||||
return $('<div></div>').html(value).text();
|
||||
}
|
||||
@@ -1543,7 +1558,6 @@ function siteWafConfig(siteName, type) {
|
||||
|
||||
|
||||
function wafSite(){
|
||||
|
||||
owPost('get_site_config', {}, function(data){
|
||||
var tmp = $.parseJSON(data.data);
|
||||
var rdata = $.parseJSON(tmp.data);
|
||||
@@ -1553,32 +1567,20 @@ function wafSite(){
|
||||
i += 1;
|
||||
tbody += '<tr>\
|
||||
<td><a onclick="siteWafConfig(\''+ k + '\')" class="sitename btlink" title="' + k + '">' + k + '</a></td>\
|
||||
<td>\
|
||||
<input onclick="setSiteObjState(\''+ k + '\',\'get\')" type="checkbox" ' + (v.get ? 'checked' : '') + '><span class="' + back_css(v.total[1].value) + '" title="拦截GET渗透次数:' + v.total[1].value + '">' + v.total[1].value + '</span>\
|
||||
</td>\
|
||||
<td>\
|
||||
<input onclick="setSiteObjState(\''+ k + '\',\'post\')" type="checkbox" ' + (v.post ? 'checked' : '') + '><span class="' + back_css(v.total[0].value) + '" title="拦截POST渗透次数:' + v.total[0].value + '">' + v.total[0].value + '</span>\
|
||||
</td>\
|
||||
<td>\
|
||||
<input onclick="setSiteObjState(\''+ k + '\',\'user-agent\')" type="checkbox" ' + (v['user-agent'] ? 'checked' : '') + '><span class="' + back_css(v.total[3].value) + '" title="拦截恶意User-Agent次数:' + v.total[3].value + '">' + v.total[3].value + '</span>\
|
||||
</td>\
|
||||
<td>\
|
||||
<input onclick="setSiteObjState(\''+ k + '\',\'cookie\')" type="checkbox" ' + (v.cookie ? 'checked' : '') + '><span class="' + back_css(v.total[4].value) + '" title="拦截Cookie渗透次数:' + v.total[4].value + '">' + v.total[4].value + '</span>\
|
||||
</td>\
|
||||
<td>\
|
||||
<input onclick="setSiteObjState(\''+ k + '\',\'cdn\')" type="checkbox" ' + (v.cdn ? 'checked' : '') + '>\
|
||||
</td>\
|
||||
<td>\
|
||||
<input onclick="setSiteObjState(\''+ k + '\',\'cc\')" type="checkbox" ' + (v.cc.open ? 'checked' : '') + '><span class="' + back_css(v.total[2].value) + '" title="拦截CC攻击次数:' + v.total[2].value + '">' + v.total[2].value + '</span>\
|
||||
</td>\
|
||||
<td><input onclick="setSiteObjState(\''+ k + '\',\'get\')" type="checkbox" ' + (v.get ? 'checked' : '') + '><span class="' + back_css(v.total[1].value) + '" title="拦截GET渗透次数:' + v.total[1].value + '">' + v.total[1].value + '</span></td>\
|
||||
<td><input onclick="setSiteObjState(\''+ k + '\',\'post\')" type="checkbox" ' + (v.post ? 'checked' : '') + '><span class="' + back_css(v.total[0].value) + '" title="拦截POST渗透次数:' + v.total[0].value + '">' + v.total[0].value + '</span></td>\
|
||||
<td><input onclick="setSiteObjState(\''+ k + '\',\'user-agent\')" type="checkbox" ' + (v['user-agent'] ? 'checked' : '') + '><span class="' + back_css(v.total[3].value) + '" title="拦截恶意User-Agent次数:' + v.total[3].value + '">' + v.total[3].value + '</span></td>\
|
||||
<td><input onclick="setSiteObjState(\''+ k + '\',\'cookie\')" type="checkbox" ' + (v.cookie ? 'checked' : '') + '><span class="' + back_css(v.total[4].value) + '" title="拦截Cookie渗透次数:' + v.total[4].value + '">' + v.total[4].value + '</span></td>\
|
||||
<td><input onclick="setSiteObjState(\''+ k + '\',\'cdn\')" type="checkbox" ' + (v.cdn ? 'checked' : '') + '></td>\
|
||||
<td><input onclick="setSiteObjState(\''+ k + '\',\'cc\')" type="checkbox" ' + (v.cc.open ? 'checked' : '') + '><span class="' + back_css(v.total[2].value) + '" title="拦截CC攻击次数:' + v.total[2].value + '">' + v.total[2].value + '</span></td>\
|
||||
<td>\
|
||||
<div class="ssh-item" style="margin-left:0">\
|
||||
<input class="btswitch btswitch-ios" id="closeget_'+ i + '" type="checkbox" ' + (v.open ? 'checked' : '') + '>\
|
||||
<label class="btswitch-btn" for="closeget_'+ i + '" onclick="setSiteObjState(\'' + k + '\',\'open\')"></label>\
|
||||
</div>\
|
||||
</td>\
|
||||
<td class="text-right"><a onclick="siteWafLog(\''+ k + '\')" class="btlink ' + (v.log_size > 0 ? 'dot' : '') + '">日志</a> | <a onclick="siteWafConfig(\'' + k + '\')" class="btlink">设置</a></td>\
|
||||
</tr>'
|
||||
<td class="text-right"><a onclick="wafLogs(\''+ k + '\')" class="btlink ' + (v.log_size > 0 ? 'dot' : '') + '">日志</a> | <a onclick="siteWafConfig(\'' + k + '\')" class="btlink">设置</a></td>\
|
||||
</tr>';
|
||||
});
|
||||
|
||||
var con = '<div class="lib-box">\
|
||||
@@ -1612,27 +1614,195 @@ function wafSite(){
|
||||
|
||||
|
||||
|
||||
function wafHistory(){
|
||||
|
||||
function wafLogRequest(page){
|
||||
var args = {};
|
||||
args['page'] = page;
|
||||
args['page_size'] = 10;
|
||||
args['site'] = $('select[name="site"]').val();
|
||||
|
||||
var query_date = 'today';
|
||||
if ($('#time_choose').attr("data-name") != ''){
|
||||
query_date = $('#time_choose').attr("data-name");
|
||||
} else {
|
||||
query_date = $('#search_time button.cur').attr("data-name");
|
||||
}
|
||||
|
||||
args['query_date'] = query_date;
|
||||
args['tojs'] = 'wafLogRequest';
|
||||
|
||||
owPost('get_logs_list', args, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
var list = '';
|
||||
var data = rdata.data.data;
|
||||
if (data.length > 0){
|
||||
for(i in data){
|
||||
list += '<tr>';
|
||||
list += '<td><span class="overflow_hide" style="width:112px;">' + getLocalTime(data[i]['time'])+'</span></td>';
|
||||
list += '<td><span class="overflow_hide" style="width:50px;">' + data[i]['domain'] +'</span></td>';
|
||||
list += '<td><span class="overflow_hide" style="width:60px;">' + data[i]['ip'] +'</span></td>';
|
||||
list += '<td><span class="overflow_hide" style="width:50px;">' + data[i]['uri'] +'</span></td>';
|
||||
list += '<td><span class="overflow_hide" style="width:50px;">' + data[i]['rule_name'] +'</span></td>';
|
||||
list += '<td><span class="overflow_hide" style="width:200px;">' + data[i]['reason'] +'</span></td>';
|
||||
list += '<td><a data-id="'+i+'" href="javascript:;" class="btlink details" title="详情">详情</a></td>';
|
||||
list += '</tr>';
|
||||
}
|
||||
} else{
|
||||
list += '<tr><td colspan="8" style="text-align:center;">封锁日志为空</td></tr>';
|
||||
}
|
||||
|
||||
var table = '<div class="tablescroll">\
|
||||
<table id="DataBody" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
|
||||
<thead><tr>\
|
||||
<th>时间</th>\
|
||||
<th>域名</th>\
|
||||
<th>IP</th>\
|
||||
<th>URI</th>\
|
||||
<th>规则名</th>\
|
||||
<th>原因</th>\
|
||||
<th style="text-align:right;">操作</th></tr></thead>\
|
||||
<tbody>\
|
||||
'+ list +'\
|
||||
</tbody></table>\
|
||||
</div>\
|
||||
<div id="wsPage" class="dataTables_paginate paging_bootstrap page"></div>';
|
||||
$('#ws_table').html(table);
|
||||
$('#wsPage').html(rdata.data.page);
|
||||
|
||||
$(".tablescroll .details").click(function(){
|
||||
var index = $(this).attr('data-id');
|
||||
var res = data[index];
|
||||
var ip = res.ip;
|
||||
var time = getLocalTime(res.time);
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: "【"+res.domain + "】详情",
|
||||
area: '600px',
|
||||
closeBtn: 1,
|
||||
shadeClose: false,
|
||||
content: '<div class="pd15 lib-box">\
|
||||
<table class="table" style="border:#ddd 1px solid; margin-bottom:10px">\
|
||||
<tbody><tr><th>时间</th><td>'+ time + '</td><th>用户IP</th><td><a class="btlink" href="javascript:addIpBlackArgs(\'' + escapeHTML(ip) + '\')" title="加入黑名单">' + escapeHTML(ip) + '</a></td></tr><tr><th>类型</th><td>' + escapeHTML(res.method) + '</td><th>过滤器</th><td>' + escapeHTML(res.rule_name) + '</td></tr></tbody></table>\
|
||||
<div><b style="margin-left:10px">URI地址</b></div>\
|
||||
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(res.uri) + '</div></div>\
|
||||
<div><b style="margin-left:10px">User-Agent</b></div>\
|
||||
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(res.user_agent) + '</div></div>\
|
||||
<div><b style="margin-left:10px">过滤规则</b></div>\
|
||||
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(res.rule_name) + '</div></div>\
|
||||
<div><b style="margin-left:10px">Reason</b></div>\
|
||||
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(res.reason) + '</div></div>\
|
||||
</div>'
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function wafLogs(){
|
||||
var randstr = getRandomString(10);
|
||||
|
||||
|
||||
var html = '<div>\
|
||||
<div style="padding-bottom:10px;">\
|
||||
<span>网站: </span>\
|
||||
<select class="bt-input-text" name="site" style="margin-left:4px;width:100px;">\
|
||||
<option value="unset">未设置</option>\
|
||||
</select>\
|
||||
<span style="margin-left:10px">时间: </span>\
|
||||
<div class="input-group" style="margin-left:10px;width:350px;display: inline-table;vertical-align: top;">\
|
||||
<div id="search_time" class="input-group-btn btn-group-sm">\
|
||||
<button data-name="today" type="button" class="btn btn-default">今日</button>\
|
||||
<button data-name="yesterday" type="button" class="btn btn-default">昨日</button>\
|
||||
<button data-name="l7" type="button" class="btn btn-default">近7天</button>\
|
||||
<button data-name="l30" type="button" class="btn btn-default">近30天</button>\
|
||||
</div>\
|
||||
<span class="last-span"><input data-name="" type="text" id="time_choose" lay-key="1000001_'+randstr+'" class="form-control btn-group-sm" autocomplete="off" placeholder="自定义时间" style="display: inline-block;font-size: 12px;padding: 0 10px;height:30px;width: 200px;"></span>\
|
||||
</div>\
|
||||
<div style="float:right;"><button id="UncoverAll" class="btn btn-success btn-sm">解封所有</button></div>\
|
||||
</div>\
|
||||
<div class="divtable mtb10" id="ws_table"></div>\
|
||||
</div>';
|
||||
$(".soft-man-con").html(html);
|
||||
// wafLogRequest(1);
|
||||
|
||||
$("#UncoverAll").click(function(){
|
||||
owPost('clean_drop_ip',{},function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
var ndata = $.parseJSON(rdata.data);
|
||||
if (ndata.status == 0){
|
||||
layer.msg("解封所有成功",{icon:1,time:2000,shade: [0.3, '#000']});
|
||||
} else{
|
||||
layer.msg("解封所有异常:"+ndata.msg,{icon:5,time:2000,shade: [0.3, '#000']});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
//日期范围
|
||||
laydate.render({
|
||||
elem: '#time_choose',
|
||||
value:'',
|
||||
range:true,
|
||||
done:function(value, startDate, endDate){
|
||||
if(!value){
|
||||
return false;
|
||||
}
|
||||
|
||||
$('#search_time button').each(function(){
|
||||
$(this).removeClass('cur');
|
||||
});
|
||||
|
||||
var timeA = value.split('-');
|
||||
var start = $.trim(timeA[0]+'-'+timeA[1]+'-'+timeA[2])
|
||||
var end = $.trim(timeA[3]+'-'+timeA[4]+'-'+timeA[5])
|
||||
query_txt = toUnixTime(start + " 00:00:00") + "-"+ toUnixTime(end + " 00:00:00")
|
||||
|
||||
$('#time_choose').attr("data-name",query_txt);
|
||||
$('#time_choose').addClass("cur");
|
||||
|
||||
wafLogRequest(1);
|
||||
},
|
||||
});
|
||||
|
||||
$('#search_time button:eq(0)').addClass('cur');
|
||||
$('#search_time button').click(function(){
|
||||
$('#search_time button').each(function(){
|
||||
if ($(this).hasClass('cur')){
|
||||
$(this).removeClass('cur');
|
||||
}
|
||||
});
|
||||
$('#time_choose').attr("data-name",'');
|
||||
$('#time_choose').removeClass("cur");
|
||||
|
||||
$(this).addClass('cur');
|
||||
|
||||
wafLogRequest(1);
|
||||
});
|
||||
|
||||
owPost('get_default_site',{},function(rdata){
|
||||
$('select[name="site"]').html('');
|
||||
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
var rdata = rdata.data;
|
||||
var default_site = rdata["default"];
|
||||
var select = '';
|
||||
for (var i = 0; i < rdata["list"].length; i++) {
|
||||
if (default_site == rdata["list"][i]){
|
||||
select += '<option value="'+rdata["list"][i]+'" selected>'+rdata["list"][i]+'</option>';
|
||||
} else{
|
||||
select += '<option value="'+rdata["list"][i]+'">'+rdata["list"][i]+'</option>';
|
||||
}
|
||||
}
|
||||
$('select[name="site"]').html(select);
|
||||
wafLogRequest(1);
|
||||
|
||||
$('select[name="site"]').change(function(){
|
||||
wafLogRequest(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
var con = '<button class="btn btn-success btn-sm" onclick="UncoverAll()">解封所有</button>';
|
||||
con += '<div class="divtable mt10">\
|
||||
<table class="table table-hover waftable" style="color:#fff;">\
|
||||
<thead><tr><th width="18%">开始时间</th>\
|
||||
<th width="44%">IP</th>\
|
||||
<th width="10%">站点</th>\
|
||||
<th width="10%">封锁原因</th>\
|
||||
<th width="10%">封锁时长</th>\
|
||||
<th style="text-align: center;" width="10%">状态</th>\
|
||||
</thead>\
|
||||
</table>\
|
||||
</div>';
|
||||
$(".soft-man-con").html(con);
|
||||
}
|
||||
|
||||
|
||||
function wafLogs(){
|
||||
function wafOpLogs(){
|
||||
var con = '<div class="divtable">\
|
||||
<table class="table table-hover waftable" style="color:#fff;">\
|
||||
<thead><tr><th width="18%">名称</th>\
|
||||
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
|
||||
# echo $rootPath
|
||||
|
||||
resty=$rootPath/openresty/bin/resty
|
||||
|
||||
RUN_CMD=$resty
|
||||
if [ ! -f $resty ];then
|
||||
RUN_CMD=/www/server/openresty/bin/resty
|
||||
fi
|
||||
|
||||
|
||||
# test
|
||||
# $RUN_CMD simple.lua
|
||||
# $RUN_CMD test_gsub.lua
|
||||
|
||||
# $RUN_CMD --shdict 'limit 10m' test_find_server_name.lua
|
||||
# $RUN_CMD --stap --shdict 'limit 10m' test_find_server_name.lua
|
||||
|
||||
# $RUN_CMD test_rand.lua
|
||||
$RUN_CMD test_ffi_time.lua
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
local function target()
|
||||
ngx.re.find("hello, world.", [[\w+\.]], "jo")
|
||||
end
|
||||
for i = 1, 100 do
|
||||
target()
|
||||
end
|
||||
|
||||
collectgarbage()
|
||||
|
||||
ngx.update_time()
|
||||
local begin = ngx.now()
|
||||
local N = 1e7
|
||||
for i = 1, N do
|
||||
target()
|
||||
end
|
||||
ngx.update_time()
|
||||
|
||||
ngx.say("elapsed: ", (ngx.now() - begin) / N)
|
||||
@@ -0,0 +1,62 @@
|
||||
local function target()
|
||||
ngx.re.find("hello, world.", [[\w+\.]], "jo")
|
||||
end
|
||||
for i = 1, 100 do
|
||||
target()
|
||||
end
|
||||
|
||||
-- 以上为预热操作
|
||||
collectgarbage()
|
||||
|
||||
local ffi = require("ffi")
|
||||
ffi.cdef[[
|
||||
struct timeval {
|
||||
long int tv_sec;
|
||||
long int tv_usec;
|
||||
};
|
||||
int gettimeofday(struct timeval *tv, void *tz);
|
||||
]];
|
||||
local tm = ffi.new("struct timeval");
|
||||
|
||||
-- 返回微秒级时间戳
|
||||
local function current_time_millis()
|
||||
ffi.C.gettimeofday(tm,nil);
|
||||
local sec = tonumber(tm.tv_sec);
|
||||
local usec = tonumber(tm.tv_usec);
|
||||
return sec + usec * 10^-6;
|
||||
end
|
||||
|
||||
|
||||
ngx.update_time()
|
||||
local begin = ngx.now()
|
||||
local N = 1e7
|
||||
for i = 1, N do
|
||||
target()
|
||||
end
|
||||
ngx.update_time()
|
||||
|
||||
ngx.say("elapsed: ", (ngx.now() - begin) / N)
|
||||
|
||||
|
||||
ngx.update_time()
|
||||
local begin = ngx.now()
|
||||
local N = 1e7
|
||||
for i = 1, N do
|
||||
target()
|
||||
end
|
||||
ngx.update_time()
|
||||
|
||||
ngx.say("elapsed[1]: ", (ngx.now() - begin) / N)
|
||||
|
||||
|
||||
|
||||
|
||||
ngx.update_time()
|
||||
local begin = current_time_millis()
|
||||
local N = 1e7
|
||||
for i = 1, N do
|
||||
target()
|
||||
end
|
||||
ngx.update_time()
|
||||
|
||||
ngx.say("ffi elapsed: ", (current_time_millis() - begin) / N)
|
||||
@@ -0,0 +1,75 @@
|
||||
local function target()
|
||||
ngx.re.find("hello, world.", [[\w+\.]], "jo")
|
||||
end
|
||||
for i = 1, 100 do
|
||||
target()
|
||||
end
|
||||
|
||||
-- 以上为预热操作
|
||||
collectgarbage()
|
||||
|
||||
local config_domains = {
|
||||
[1] = {
|
||||
["name"] = "t1.cn",
|
||||
["path"] = "/www/wwwroot/t1.cn",
|
||||
["domains"] = {
|
||||
[1] = "t1.cn",
|
||||
[2] = "t3.cn"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
local function get_server_name(request_name)
|
||||
for _,v in ipairs(config_domains)
|
||||
do
|
||||
for _,cd_name in ipairs(v['domains'])
|
||||
do
|
||||
if request_name == cd_name then
|
||||
return v['name']
|
||||
end
|
||||
end
|
||||
end
|
||||
return request_name
|
||||
end
|
||||
|
||||
|
||||
local function get_server_name_cache(request_name)
|
||||
local cache_name = ngx.shared.limit:get(request_name)
|
||||
if cache_name then return cache_name end
|
||||
|
||||
for _,v in ipairs(config_domains)
|
||||
do
|
||||
for _,cd_name in ipairs(v['domains'])
|
||||
do
|
||||
if request_name == cd_name then
|
||||
ngx.shared.limit:set(cd_name,v['name'],3600)
|
||||
return v['name']
|
||||
end
|
||||
end
|
||||
end
|
||||
return request_name
|
||||
end
|
||||
|
||||
|
||||
ngx.update_time()
|
||||
local begin = ngx.now()
|
||||
local N = 1e7
|
||||
for i = 1, N do
|
||||
get_server_name("t3.cn")
|
||||
end
|
||||
ngx.update_time()
|
||||
|
||||
ngx.say("test get_server_name elapsed: ", (ngx.now() - begin) / N)
|
||||
|
||||
|
||||
|
||||
|
||||
ngx.update_time()
|
||||
local begin = ngx.now()
|
||||
local N = 1e7
|
||||
for i = 1, N do
|
||||
get_server_name_cache("t3.cn")
|
||||
end
|
||||
ngx.update_time()
|
||||
|
||||
ngx.say("test get_server_name_cache elapsed: ", (ngx.now() - begin) / N)
|
||||
@@ -0,0 +1,47 @@
|
||||
|
||||
local function target()
|
||||
ngx.re.find("hello, world.", [[\w+\.]], "jo")
|
||||
end
|
||||
for i = 1, 100 do
|
||||
target()
|
||||
end
|
||||
-- 以上为预热操作
|
||||
collectgarbage()
|
||||
|
||||
local function test_string_gsub(str,reps)
|
||||
local resultStrList = {}
|
||||
string.gsub(str,'[^'..reps..']+', function(w)
|
||||
table.insert(resultStrList,w)
|
||||
return w
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
local function test_ngx_string_gsub(str,reps)
|
||||
local resultStrList = {}
|
||||
ngx.re.gsub(str,'[^'..reps..']+', function(w)
|
||||
table.insert(resultStrList,w[0])
|
||||
return w
|
||||
end, "ijo")
|
||||
end
|
||||
|
||||
ngx.update_time()
|
||||
local begin = ngx.now()
|
||||
local N = 1e6
|
||||
for i = 1, N do
|
||||
test_string_gsub("2409:8a62:e20:95f0:45b7:233e:f003:c0ab",",")
|
||||
end
|
||||
ngx.update_time()
|
||||
|
||||
ngx.say("test_string_gsub elapsed: ", (ngx.now() - begin) / N)
|
||||
|
||||
|
||||
ngx.update_time()
|
||||
local begin = ngx.now()
|
||||
local N = 1e6
|
||||
for i = 1, N do
|
||||
test_ngx_string_gsub("2409:8a62:e20:95f0:45b7:233e:f003:c0ab",",")
|
||||
end
|
||||
ngx.update_time()
|
||||
|
||||
ngx.say("test_ngx_string_gsub elapsed: ", (ngx.now() - begin) / N)
|
||||
@@ -0,0 +1,72 @@
|
||||
local function target()
|
||||
ngx.re.find("hello, world.", [[\w+\.]], "jo")
|
||||
end
|
||||
for i = 1, 100 do
|
||||
target()
|
||||
end
|
||||
|
||||
-- 以上为预热操作
|
||||
collectgarbage()
|
||||
|
||||
|
||||
|
||||
local function get_random_t1(n)
|
||||
math.randomseed(ngx.time())
|
||||
local t = {
|
||||
"0","1","2","3","4","5","6","7","8","9",
|
||||
"a","b","c","d","e","f","g","h","i","j",
|
||||
"k","l","m","n","o","p","q","r","s","t",
|
||||
"u","v","w","x","y","z",
|
||||
"A","B","C","D","E","F","G","H","I","J",
|
||||
"K","L","M","N","O","P","Q","R","S","T",
|
||||
"U","V","W","X","Y","Z",
|
||||
}
|
||||
local s = ""
|
||||
for i = 1, n do
|
||||
s = s .. t[math.random(#t)]
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function get_random_t2(n)
|
||||
local t = {
|
||||
"0","1","2","3","4","5","6","7","8","9",
|
||||
"a","b","c","d","e","f","g","h","i","j",
|
||||
"k","l","m","n","o","p","q","r","s","t",
|
||||
"u","v","w","x","y","z",
|
||||
"A","B","C","D","E","F","G","H","I","J",
|
||||
"K","L","M","N","O","P","Q","R","S","T",
|
||||
"U","V","W","X","Y","Z",
|
||||
}
|
||||
local s = ""
|
||||
for i = 1, n do
|
||||
s = s .. t[math.random(#t)]
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
ngx.update_time()
|
||||
local begin = ngx.now()
|
||||
local N = 1e5
|
||||
for i = 1, N do
|
||||
get_random_t1(16)
|
||||
end
|
||||
ngx.update_time()
|
||||
|
||||
ngx.say("test get_random_t1 elapsed: ", (ngx.now() - begin) / N)
|
||||
|
||||
|
||||
ngx.update_time()
|
||||
local begin = ngx.now()
|
||||
local N = 1e5
|
||||
math.randomseed(ngx.time())
|
||||
for i = 1, N do
|
||||
get_random_t2(16)
|
||||
end
|
||||
ngx.update_time()
|
||||
|
||||
ngx.say("test get_random_t2 elapsed: ", (ngx.now() - begin) / N)
|
||||
|
||||
|
||||
+160
-6
@@ -23,6 +23,17 @@ TEST_URL = "http://t1.cn/"
|
||||
# TEST_URL = "https://www.zzzvps.com/"
|
||||
|
||||
|
||||
def writeFile(filename, str):
|
||||
# 写文件内容
|
||||
try:
|
||||
fp = open(filename, 'w+')
|
||||
fp.write(str)
|
||||
fp.close()
|
||||
return True
|
||||
except Exception as e:
|
||||
return False
|
||||
|
||||
|
||||
def httpGet(url, timeout=10):
|
||||
import urllib.request
|
||||
|
||||
@@ -35,6 +46,61 @@ def httpGet(url, timeout=10):
|
||||
return str(e)
|
||||
|
||||
|
||||
def httpGet__Header(url, headers, timeout=10):
|
||||
import urllib.request
|
||||
try:
|
||||
req = urllib.request.Request(url, headers=headers)
|
||||
response = urllib.request.urlopen(req)
|
||||
result = response.read().decode('utf-8')
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
|
||||
|
||||
def httpUpload(url, timeout=10):
|
||||
try:
|
||||
import requests
|
||||
|
||||
files = {
|
||||
'file': open('/Users/midoks/Desktop/mwdev/server/op_waf/version.pl', 'rb')
|
||||
}
|
||||
res = requests.post(url=url, files=files)
|
||||
return res
|
||||
except Exception as e:
|
||||
return "http.upload:" + str(e)
|
||||
|
||||
|
||||
def httpUploadPhp(url, timeout=10):
|
||||
try:
|
||||
import requests
|
||||
|
||||
writeFile("/tmp/tmp.php", "")
|
||||
|
||||
files = {
|
||||
'file': open('/tmp/tmp.php', 'rb')
|
||||
}
|
||||
res = requests.post(url=url, files=files)
|
||||
return res
|
||||
except Exception as e:
|
||||
return "http.upload:" + str(e)
|
||||
|
||||
|
||||
def httpUploadPhpData(url, timeout=10):
|
||||
try:
|
||||
import requests
|
||||
|
||||
writeFile("/tmp/tmp.py", "<?php echo '123123';?>")
|
||||
|
||||
files = {
|
||||
'file': open('/tmp/tmp.py', 'rb')
|
||||
}
|
||||
res = requests.post(url=url, files=files)
|
||||
return res
|
||||
except Exception as e:
|
||||
return "http.upload:" + str(e)
|
||||
|
||||
|
||||
def httpGet__UA(url, ua, timeout=10):
|
||||
import urllib.request
|
||||
headers = {'user-agent': ua}
|
||||
@@ -48,6 +114,19 @@ def httpGet__UA(url, ua, timeout=10):
|
||||
return str(e)
|
||||
|
||||
|
||||
def httpGet__cdn(url, ip, timeout=10):
|
||||
import urllib.request
|
||||
headers = {'x-forwarded-for': ip}
|
||||
try:
|
||||
req = urllib.request.Request(url, headers=headers)
|
||||
response = urllib.request.urlopen(req)
|
||||
result = response.read().decode('utf-8')
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
|
||||
|
||||
def httpPost(url, data, timeout=10):
|
||||
"""
|
||||
发送POST请求
|
||||
@@ -94,7 +173,7 @@ def test_Dir():
|
||||
url = TEST_URL + '?t=../etc/passwd'
|
||||
print("args test start")
|
||||
url_val = httpGet(url, 10)
|
||||
# print(url_val)
|
||||
print(url_val)
|
||||
print("args test end")
|
||||
|
||||
|
||||
@@ -109,6 +188,43 @@ def test_UA():
|
||||
print("user-agent test end")
|
||||
|
||||
|
||||
def test_Header():
|
||||
'''
|
||||
user-agent 过滤
|
||||
'''
|
||||
url = TEST_URL
|
||||
print("user-agent test start")
|
||||
url_val = httpGet__Header(url, {'X-forwarded-For': '../etc/passwd'})
|
||||
print(url_val)
|
||||
print("user-agent test end")
|
||||
|
||||
|
||||
def test_UA_for(num):
|
||||
'''
|
||||
user-agent 过滤
|
||||
'''
|
||||
url = TEST_URL
|
||||
print("user-agent test start")
|
||||
for x in range(num):
|
||||
url_val = httpGet__UA(url, 'ApacheBench')
|
||||
print(url_val)
|
||||
print("user-agent test end")
|
||||
|
||||
|
||||
def test_cdn():
|
||||
'''
|
||||
user-agent 过滤
|
||||
'''
|
||||
url = TEST_URL
|
||||
print("cdn test start")
|
||||
url_val = httpGet__cdn(url, '2409:8a62:e20:95f0:45b7:233e:f003:c0ab')
|
||||
print(url_val)
|
||||
|
||||
url_val2 = httpGet__cdn(url, '91.245.227.173')
|
||||
print(url_val2)
|
||||
print("cdn test end")
|
||||
|
||||
|
||||
def test_POST():
|
||||
'''
|
||||
user-agent 过滤
|
||||
@@ -125,7 +241,7 @@ def test_scan():
|
||||
'''
|
||||
目录保存
|
||||
'''
|
||||
url = TEST_URL + '/acunetix_wvs_security_test?t=1'
|
||||
url = TEST_URL + 'acunetix_wvs_security_test?t=1'
|
||||
print("scan test start")
|
||||
url_val = httpGet(url, 10)
|
||||
print(url_val)
|
||||
@@ -158,16 +274,54 @@ def test_url_ext():
|
||||
print("url_ext end")
|
||||
|
||||
|
||||
def test_OK():
|
||||
'''
|
||||
目录保存
|
||||
'''
|
||||
url = TEST_URL
|
||||
print("ok test start")
|
||||
url_val = httpGet(url, 10)
|
||||
print(url_val)
|
||||
print("ok test end")
|
||||
|
||||
|
||||
def test_Upload():
|
||||
'''
|
||||
上传文件
|
||||
'''
|
||||
url = TEST_URL
|
||||
print("upload test start")
|
||||
url_val = httpUpload(url, 10)
|
||||
print(url_val)
|
||||
|
||||
print("upload test end")
|
||||
|
||||
print("upload php test start")
|
||||
url_val = httpUploadPhp(url, 10)
|
||||
print(url_val)
|
||||
print("upload php test start")
|
||||
|
||||
print("upload php data test start")
|
||||
url_val = httpUploadPhpData(url, 10)
|
||||
print(url_val)
|
||||
print("upload php data test start")
|
||||
|
||||
|
||||
def test_start():
|
||||
# test_OK()
|
||||
# test_Dir()
|
||||
# test_UA()
|
||||
# test_POST()
|
||||
# test_scan()
|
||||
test_Header()
|
||||
# test_UA_for(1000)
|
||||
test_POST()
|
||||
test_scan()
|
||||
# test_CC()
|
||||
test_url_ext()
|
||||
# test_url_ext()
|
||||
# test_cdn()
|
||||
# test_Upload()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.system('cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/op_waf && sh install.sh uninstall 0.1 && sh install.sh install 0.1')
|
||||
os.system('cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/op_waf && sh install.sh uninstall 0.2.2 && sh install.sh install 0.2.2')
|
||||
os.system('cd /Users/midoks/Desktop/mwdev/server/mdserver-web/ && python3 plugins/openresty/index.py stop && python3 plugins/openresty/index.py start')
|
||||
test_start()
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
#!/bin/sh
|
||||
export PATH=$PATH:/opt/stap/bin:/opt/stapxx
|
||||
|
||||
# https://moonbingbing.gitbooks.io/openresty-best-practices/content/flame_graph/install.html
|
||||
# apt install elfutils
|
||||
# sudo apt-get install -y systemtap gcc
|
||||
# sudo apt-get install linux-headers-generic gcc libcap-dev
|
||||
# apt-get install -y libdw-dev
|
||||
# apt-get install -y fakeroot build-essential crash kexec-tools makedumpfile kernel-wedge kernel-package
|
||||
# apt-get install -y git-core libncurses5 libncurses5-dev libelf-dev asciidoc binutils-dev
|
||||
# apt-get build-dep linux
|
||||
|
||||
# cat > /etc/apt/sources.list.d/ddebs.list << EOF
|
||||
# deb http://ddebs.ubuntu.com/ precise main restricted universe multiverse
|
||||
# EOF
|
||||
#
|
||||
# apt-key adv --keyserver keyserver.ubuntu.com --recv-keys ECDCAD72428D7C01
|
||||
# apt-get update
|
||||
|
||||
if [ $# -ne 2 ]
|
||||
then
|
||||
echo "Usage: ./`basename $0` lua/c NAME"
|
||||
exit
|
||||
fi
|
||||
|
||||
pid=`ps -ef|grep openresty | grep -v grep | awk '{print $2}'`
|
||||
name=$2
|
||||
|
||||
|
||||
# /opt/openresty-systemtap-toolkit/ngx-active-reqs -p 496435
|
||||
# /opt/openresty-systemtap-toolkit/sample-bt -p 496435 -t 5 -k > a.bt
|
||||
# kernel-debuginfo-common kernel-debuginfo
|
||||
# apt install -y kernel-debuginfo-common kernel-debuginfo
|
||||
# apt install -y kernel-*
|
||||
|
||||
|
||||
|
||||
# /opt/stapxx/samples/lj-lua-stacks.sxx --arg time=5 --skip-badvars -x 45266 > tmp.bt
|
||||
|
||||
|
||||
if [ ! -d /opt/openresty-systemtap-toolkit ];then
|
||||
cd /opt && git clone https://github.com/openresty/openresty-systemtap-toolkit
|
||||
fi
|
||||
|
||||
if [ ! -d /opt/stapxx ];then
|
||||
cd /opt && git clone https://github.com/openresty/stapxx
|
||||
fi
|
||||
|
||||
# stap++ -I ./tapset -x 45266 --arg limit=10 samples/ngx-upstream-post-conn.sxx
|
||||
# dpkg -i --force-overwrite /var/cache/apt/archives/linux-tools-common_5.4.0-128.144_all.deb
|
||||
|
||||
# /opt/openresty-systemtap-toolkit/ngx-active-reqs -p 45266
|
||||
|
||||
# git clone git://sourceware.org/git/systemtap.git
|
||||
# ./configure --prefix=/opt/stap --disable-docs --disable-publican --disable-refdocs CFLAGS="-g -O2"
|
||||
|
||||
if [ ! -d /opt/FlameGraph ];then
|
||||
cd /opt && git clone https://github.com/brendangregg/FlameGraph
|
||||
fi
|
||||
|
||||
if [ $1 == "lua" ]; then
|
||||
# /opt/openresty-systemtap-toolkit/ngx-sample-lua-bt -p 377452 --luajit20 -t 30 >temp.bt
|
||||
/opt/openresty-systemtap-toolkit/ngx-sample-lua-bt -p $pid --luajit20 -t 30 >temp.bt
|
||||
# /opt/openresty-systemtap-toolkit/fix-lua-bt temp.bt >t1.bt
|
||||
/opt/openresty-systemtap-toolkit/fix-lua-bt temp.bt >${name}.bt
|
||||
elif [ $1 == "c" ]; then
|
||||
# /opt/openresty-systemtap-toolkit/sample-bt -p 496435 -t 10 -u > t2.bt
|
||||
/opt/openresty-systemtap-toolkit/sample-bt -p $pid -t 10 -u > ${name}.bt
|
||||
else
|
||||
echo "type is only lua/c"
|
||||
exit
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# /opt/FlameGraph/stackcollapse-perf.pl perf.unfold &> perf.folded
|
||||
# /opt/FlameGraph/flamegraph.pl perf.folded > perf.svg
|
||||
|
||||
/opt/FlameGraph/stackcollapse-stap.pl ${name}.bt >${name}.cbt
|
||||
/opt/FlameGraph/flamegraph.pl ${name}.cbt >${name}.svg
|
||||
rm -f temp.bt ${name}.bt ${name}.cbt
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
|
||||
# cd /www/server/mdserver-web/plugins/op_waf/t && sh ngx_demo.sh
|
||||
# cd /www/wwwroot/dev156.cachecha.com && sh ngx_demo.sh
|
||||
|
||||
|
||||
# only openresty
|
||||
# pid=`ps -ef|grep openresty | grep -v grep | awk '{print $2}'`
|
||||
# perf record -F 99 -p $pid -g -- sleep 60
|
||||
|
||||
|
||||
#全部
|
||||
perf record -F 99 -g -a -- sleep 60
|
||||
|
||||
|
||||
perf script -i perf.data &> perf.unfold
|
||||
/opt/FlameGraph/stackcollapse-perf.pl perf.unfold &> perf.folded
|
||||
/opt/FlameGraph/flamegraph.pl perf.folded > perf.svg
|
||||
@@ -0,0 +1,29 @@
|
||||
# 火焰图安装 [ubuntu 20.04]
|
||||
```
|
||||
|
||||
sudo apt-get install -y linux-tools-common linux-tools-generic linux-tools-`uname -r`
|
||||
apt-get update -y
|
||||
sudo apt -y install elfutils
|
||||
apt-get install -y systemtap gcc
|
||||
sudo apt-get install -y linux-headers-generic gcc libcap-dev
|
||||
apt install -y kernel-debuginfo-common kernel-debuginfo
|
||||
```
|
||||
|
||||
# 测试有效性
|
||||
```
|
||||
stap -ve 'probe begin { log("hello systemtap!") exit() }'
|
||||
|
||||
|
||||
stap -e 'probe kernel.function("sys_open") {log("hello world") exit()}'
|
||||
|
||||
|
||||
stap -v -e 'probe vfs.read {printf("read performed\n"); exit()}'
|
||||
```
|
||||
|
||||
|
||||
# openresty 测试
|
||||
```
|
||||
|
||||
cd /www/server/mdserver-web/plugins/op_waf/t && sh ngx_debug.sh lua t1
|
||||
cd /www/server/mdserver-web/plugins/op_waf/t && sh ngx_debug.sh c t2
|
||||
```
|
||||
|
||||
@@ -2,8 +2,21 @@
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
|
||||
# apt -y install apache2-utils
|
||||
# yum -y install httpd-tools
|
||||
# ab -c 1000 -n 1000000 http://xx.xx.xx/
|
||||
|
||||
# ab -c 3000 -n 10000000 http://www.zzzvps.com/
|
||||
# /cc https://www.zzzvps.com/ 120
|
||||
# ab -c 10 -n 1000 http://t1.cn/wp-admin/index.php
|
||||
# ab -c 1000 -n 1000000 http://dev156.cachecha.com/
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
|
||||
if [ -f ${rootPath}/bin/activate ];then
|
||||
source ${rootPath}/bin/activate
|
||||
fi
|
||||
|
||||
python3 index.py
|
||||
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ def createBgTask():
|
||||
removeBgTask()
|
||||
args = {
|
||||
"period": "minute-n",
|
||||
"minute-n": "3",
|
||||
"minute-n": "1",
|
||||
}
|
||||
createBgTaskByName(getPluginName(), args)
|
||||
|
||||
@@ -71,7 +71,7 @@ def createBgTaskByName(name, args):
|
||||
print("计划任务已经存在!")
|
||||
return True
|
||||
import crontab_api
|
||||
api = crontab_api.crontab_api()
|
||||
cron_api = crontab_api.crontab_api()
|
||||
|
||||
period = args['period']
|
||||
_hour = ''
|
||||
@@ -87,16 +87,18 @@ def createBgTaskByName(name, args):
|
||||
_where1 = args['minute-n']
|
||||
_minute = ''
|
||||
|
||||
mw_dir = mw.getRunDir()
|
||||
cmd = '''
|
||||
mw_dir=%s
|
||||
rname=%s
|
||||
plugin_path=%s
|
||||
script_path=%s
|
||||
logs_file=$plugin_path/${rname}.log
|
||||
''' % (name, getServerDir(), getPluginDir())
|
||||
''' % (mw_dir, name, getServerDir(), getPluginDir())
|
||||
cmd += 'echo "★【`date +"%Y-%m-%d %H:%M:%S"`】 STSRT★" >> $logs_file' + "\n"
|
||||
cmd += 'echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" >> $logs_file' + "\n"
|
||||
cmd += 'echo "python3 $script_path/tool_task.py run >> $logs_file 2>&1"' + "\n"
|
||||
cmd += 'python3 $script_path/tool_task.py run >> $logs_file 2>&1' + "\n"
|
||||
cmd += 'echo "cd $mw_dir && source bin/activate && python3 $script_path/tool_task.py run >> $logs_file 2>&1"' + "\n"
|
||||
cmd += 'cd $mw_dir && source bin/activate && python3 $script_path/tool_task.py run >> $logs_file 2>&1' + "\n"
|
||||
cmd += 'echo "【`date +"%Y-%m-%d %H:%M:%S"`】 END★" >> $logs_file' + "\n"
|
||||
cmd += 'echo "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" >> $logs_file' + "\n"
|
||||
|
||||
@@ -115,7 +117,7 @@ logs_file=$plugin_path/${rname}.log
|
||||
'urladdress': '',
|
||||
}
|
||||
|
||||
task_id = api.add(params)
|
||||
task_id = cron_api.add(params)
|
||||
if task_id > 0:
|
||||
cfg["task_id"] = task_id
|
||||
cfg["name"] = name
|
||||
@@ -144,8 +146,15 @@ def removeBgTask():
|
||||
return False
|
||||
|
||||
|
||||
def getCpuUsed():
|
||||
import psutil
|
||||
used = psutil.cpu_percent(interval=1)
|
||||
path = getServerDir() + "/cpu.info"
|
||||
mw.writeFile(path, str(int(used)))
|
||||
|
||||
|
||||
def run():
|
||||
print('op lua run ok')
|
||||
getCpuUsed()
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1:
|
||||
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
自动生成配置文件
|
||||
@@ -1 +1 @@
|
||||
{"reqfile_path": "{$WAF_PATH}/html", "retry": {"retry_time": 180, "is_open_global": 0, "retry": 6, "retry_cycle": 60}, "log": true, "scan": {"status": 444, "ps": "\u8fc7\u6ee4\u5e38\u89c1\u626b\u63cf\u6d4b\u8bd5\u5de5\u5177\u7684\u6e17\u900f\u6d4b\u8bd5", "open": true, "reqfile": ""}, "cc": {"status": 444, "ps": "\u8fc7\u8651CC\u653b\u51fb", "limit": 120, "endtime": 300, "open": true, "reqfile": "", "cycle": 60}, "get": {"status": 403, "ps": "\u8fc7\u6ee4uri\u3001uri\u53c2\u6570\u4e2d\u5e38\u89c1sql\u6ce8\u5165\u3001xss\u7b49\u653b\u51fb", "open": true, "reqfile": "get.html"}, "log_save": 30, "user-agent": {"status": 403, "ps": "\u901a\u5e38\u7528\u4e8e\u8fc7\u6ee4\u6d4f\u89c8\u5668\u3001\u8718\u86db\u53ca\u4e00\u4e9b\u81ea\u52a8\u626b\u63cf\u5668", "open": true, "reqfile": "user_agent.html"}, "other": {"status": 403, "ps": "\u5176\u5b83\u975e\u901a\u7528\u8fc7\u6ee4", "reqfile": "other.html"}, "cookie": {"status": 403, "ps": "\u8fc7\u6ee4\u5229\u7528Cookie\u53d1\u8d77\u7684\u6e17\u900f\u653b\u51fb", "open": true, "reqfile": "cookie.html"}, "logs_path": "/www/wwwlogs/waf", "post": {"status": 403, "ps": "\u8fc7\u6ee4POST\u53c2\u6570\u4e2d\u5e38\u89c1sql\u6ce8\u5165\u3001xss\u7b49\u653b\u51fb", "open": true, "reqfile": "post.html"}, "open": true}
|
||||
{"reqfile_path": "{$WAF_PATH}/html", "retry": {"retry_time": 180, "is_open_global": 0, "retry": 6, "retry_cycle": 60}, "log": true, "scan": {"status": 444, "ps": "过滤常见扫描测试工具的渗透测试", "open": true, "reqfile": ""}, "cc": {"status": 444, "ps": "过虑CC攻击", "limit": 120, "endtime": 300, "open": true,"cycle": 60}, "safe_verify":{"status": 200,"ps": "强制安全校验", "reqfile": "safe_js.html","open": false,"cpu":50,"auto":true,"time":86400 },"get": {"status": 200, "ps": "过滤uri、uri参数中常见sql注入、xss等攻击", "open": true, "reqfile": "get.html"}, "log_save": 30, "user-agent": {"status": 200, "ps": "通常用于过滤浏览器、蜘蛛及一些自动扫描器", "open": true, "reqfile": "user_agent.html"}, "other": {"status": 200, "ps": "其它非通用过滤", "reqfile": "other.html"}, "cookie": {"status": 200, "ps": "过滤利用Cookie发起的渗透攻击", "open": true, "reqfile": "cookie.html"}, "logs_path": "/www/wwwlogs/waf", "post": {"status": 200, "ps": "过滤POST参数中常见sql注入、xss等攻击", "open": true, "reqfile": "post.html"}, "open": true}
|
||||
@@ -7,7 +7,7 @@
|
||||
*{margin:0;padding:0;color:#444}
|
||||
body{font-size:14px;font-family:"宋体"}
|
||||
.main{width:600px;margin:10% auto;}
|
||||
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;padding-left: 20px;}
|
||||
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;text-align: center;}
|
||||
.content{background-color:#f3f7f9; height:280px;border:1px dashed #c6d9b6;padding:20px}
|
||||
.t1{border-bottom: 1px dashed #c6d9b6;color: #ff4000;font-weight: bold; margin: 0 0 20px; padding-bottom: 18px;}
|
||||
.t2{margin-bottom:8px; font-weight:bold}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*{margin:0;padding:0;color:#444}
|
||||
body{font-size:14px;font-family:"宋体"}
|
||||
.main{width:600px;margin:10% auto;}
|
||||
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;padding-left: 20px;}
|
||||
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;text-align: center;}
|
||||
.content{background-color:#f3f7f9; height:280px;border:1px dashed #c6d9b6;padding:20px}
|
||||
.t1{border-bottom: 1px dashed #c6d9b6;color: #ff4000;font-weight: bold; margin: 0 0 20px; padding-bottom: 18px;}
|
||||
.t2{margin-bottom:8px; font-weight:bold}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*{margin:0;padding:0;color:#444}
|
||||
body{font-size:14px;font-family:"宋体"}
|
||||
.main{width:600px;margin:10% auto;}
|
||||
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;padding-left: 20px;}
|
||||
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;text-align: center;}
|
||||
.content{background-color:#f3f7f9; height:280px;border:1px dashed #c6d9b6;padding:20px}
|
||||
.t1{border-bottom: 1px dashed #c6d9b6;color: #ff4000;font-weight: bold; margin: 0 0 20px; padding-bottom: 18px;}
|
||||
.t2{margin-bottom:8px; font-weight:bold}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*{margin:0;padding:0;color:#444}
|
||||
body{font-size:14px;font-family:"宋体"}
|
||||
.main{width:600px;margin:10% auto;}
|
||||
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;padding-left: 20px;}
|
||||
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;text-align: center;}
|
||||
.content{background-color:#f3f7f9; height:280px;border:1px dashed #c6d9b6;padding:20px}
|
||||
.t1{border-bottom: 1px dashed #c6d9b6;color: #ff4000;font-weight: bold; margin: 0 0 20px; padding-bottom: 18px;}
|
||||
.t2{margin-bottom:8px; font-weight:bold}
|
||||
|
||||
Executable
+151
@@ -0,0 +1,151 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>OP网站防火墙|安全校验</title>
|
||||
<style>
|
||||
*{margin:0;padding:0;color:#444}
|
||||
.main{width:600px;margin:10% auto;}
|
||||
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;text-align: center;}
|
||||
.content{background-color:#f3f7f9; height:280px;border:1px dashed #c6d9b6;padding:20px}
|
||||
#change{
|
||||
font-size: 200px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="main">
|
||||
<div class="title">OP网站防火墙|安全校验</div>
|
||||
<div class="content">
|
||||
<p id="change">5</p>
|
||||
</div>
|
||||
<div id="status" style="display: none;">false</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
function ajax(type,bool){
|
||||
var xhr = {};
|
||||
if(typeof(type)=='undefined'){
|
||||
xhr.type='HTML';
|
||||
}else{
|
||||
xhr.type=type.toUpperCase();
|
||||
}
|
||||
if(typeof(bool)=='undefined'){
|
||||
xhr.async=true;
|
||||
}else{
|
||||
xhr.async=bool;
|
||||
}
|
||||
xhr.url = '';
|
||||
xhr.send = '';
|
||||
xhr.result=null;
|
||||
|
||||
xhr.createXHR = function(){
|
||||
try{
|
||||
request = new XMLHttpRequest();
|
||||
if(request.overrideMimeType){
|
||||
request.overrideMimeType('text/html');
|
||||
}
|
||||
}catch(e){
|
||||
var v = ['Microsoft.XMLHTTP', 'MSXML.XMLHTTP', 'Microsoft.XMLHTTP',
|
||||
'Msxml2.XMLHTTP.7.0', 'Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.5.0',
|
||||
'Msxml2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP'];
|
||||
for(var i=0;i<v.length;i++){
|
||||
try{
|
||||
request = new ActiveXObject(v[i]);
|
||||
if(request){return request;}
|
||||
}catch(e){continue;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
xhr.XHR = xhr.createXHR();
|
||||
|
||||
xhr.processHandle = function(){
|
||||
if( xhr.XHR.readyState ==4 && xhr.XHR.status==200){
|
||||
if(xhr.type=='HTML'){
|
||||
xhr.result(xhr.XHR.responseText);
|
||||
return xhr.XHR.responseText;
|
||||
}else if(xhr.type=='JSON'){
|
||||
xhr.result(eval('('+xhr.XHR.responseText+')'));
|
||||
return eval('('+xhr.XHR.responseText+')');
|
||||
}else{
|
||||
xhr.result(xhr.XHR.responseXML);
|
||||
return xhr.XHR.responseXML;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xhr.get = function(url,result){
|
||||
//添加回调函数
|
||||
var name ='PHPjs';
|
||||
var r = name + '_' + Math.random().toString().substr(2);//随机
|
||||
|
||||
xhr.url = url+'&'+name+'='+r;
|
||||
|
||||
if(result!=null){
|
||||
xhr.XHR.onreadystatechange = xhr.processHandle;
|
||||
xhr.result = result;
|
||||
}
|
||||
if(window.XMLHttpRequest){
|
||||
xhr.XHR.open('GET',xhr.url,xhr.async);
|
||||
xhr.XHR.send(null);
|
||||
}else{
|
||||
xhr.XHR.open('GET',xhr.url,xhr.async);
|
||||
xhr.XHR.send();
|
||||
}
|
||||
};
|
||||
|
||||
xhr.post = function(url,send,result){
|
||||
xhr.url = url;
|
||||
if(typeof(send) == 'object'){
|
||||
var str = '';
|
||||
for(var pro in send){
|
||||
str +=pro +'='+send[pro]+'&';
|
||||
}
|
||||
xhr.send = str.substr(0,str.length-1);
|
||||
}else{
|
||||
xhr.send = send;
|
||||
}
|
||||
if(result!=null){
|
||||
xhr.XHR.onreadystatechange = xhr.processHandle;
|
||||
xhr.result = result;
|
||||
}
|
||||
xhr.XHR.open('POST',url,xhr.async);
|
||||
xhr.XHR.setRequestHeader('request-type','ajax');
|
||||
xhr.XHR.setRequestHeader('Content-type','application/x-www-form-urlencoded');
|
||||
xhr.XHR.send(xhr.send);
|
||||
}
|
||||
return xhr;
|
||||
}
|
||||
|
||||
ajax('JSON',true).post('{uri}',{'pass':"ok"}, function(data){
|
||||
if (data['status'] == 0){
|
||||
document.getElementById('status').innerHTML = 'ok';
|
||||
location.reload();
|
||||
}
|
||||
});
|
||||
|
||||
var ok = setInterval(function(){
|
||||
var id = document.getElementById('change').innerHTML;
|
||||
id = id - 1;
|
||||
if (id == 0){
|
||||
document.getElementById('change').innerHTML = '稍等';
|
||||
clearInterval(ok);
|
||||
if (document.getElementById('status').innerHTML == 'ok'){
|
||||
location.reload();
|
||||
}
|
||||
} else {
|
||||
document.getElementById('change').innerHTML = id;
|
||||
}
|
||||
},1000);
|
||||
|
||||
</script>
|
||||
</html>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*{margin:0;padding:0;color:#444}
|
||||
body{font-size:14px;font-family:"宋体"}
|
||||
.main{width:600px;margin:10% auto;}
|
||||
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;padding-left: 20px;}
|
||||
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;text-align: center;}
|
||||
.content{background-color:#f3f7f9; height:280px;border:1px dashed #c6d9b6;padding:20px}
|
||||
.t1{border-bottom: 1px dashed #c6d9b6;color: #ff4000;font-weight: bold; margin: 0 0 20px; padding-bottom: 18px;}
|
||||
.t2{margin-bottom:8px; font-weight:bold}
|
||||
|
||||
+372
-192
@@ -4,33 +4,187 @@ local _M = { _VERSION = '0.02' }
|
||||
local mt = { __index = _M }
|
||||
|
||||
local json = require "cjson"
|
||||
local ngx_match = ngx.re.find
|
||||
local sqlite3 = require "lsqlite3"
|
||||
|
||||
local ngx_match = ngx.re.find
|
||||
local debug_mode = false
|
||||
|
||||
local waf_root = "{$WAF_ROOT}"
|
||||
local cpath = waf_root.."/waf/"
|
||||
local logdir = waf_root.."/logs/"
|
||||
local log_dir = waf_root.."/logs/"
|
||||
local rpath = cpath.."/rule/"
|
||||
|
||||
function _M.new(self)
|
||||
|
||||
|
||||
local self = {
|
||||
waf_root = waf_root,
|
||||
cpath = cpath,
|
||||
rpath = rpath,
|
||||
logdir = logdir,
|
||||
logdir = log_dir,
|
||||
config = '',
|
||||
site_config = '',
|
||||
server_name = '',
|
||||
params = nil
|
||||
global_tatal = nil,
|
||||
params = nil,
|
||||
}
|
||||
|
||||
return setmetatable(self, mt)
|
||||
end
|
||||
|
||||
|
||||
function _M.getInstance(self)
|
||||
if rawget(self, "instance") == nil then
|
||||
rawset(self, "instance", self:new())
|
||||
|
||||
if 0 == ngx.worker.id() then
|
||||
self:cron()
|
||||
end
|
||||
end
|
||||
assert(self.instance ~= nil)
|
||||
return self.instance
|
||||
end
|
||||
|
||||
function _M.initDB(self)
|
||||
local path = log_dir .. "/waf.db"
|
||||
db, err = sqlite3.open(path)
|
||||
|
||||
if err then
|
||||
self:D("initDB err:"..tostring(err))
|
||||
return nil
|
||||
end
|
||||
|
||||
db:exec([[PRAGMA synchronous = 0]])
|
||||
db:exec([[PRAGMA cache_size = 8000]])
|
||||
db:exec([[PRAGMA page_size = 32768]])
|
||||
db:exec([[PRAGMA journal_mode = wal]])
|
||||
db:exec([[PRAGMA journal_size_limit = 1073741824]])
|
||||
return db
|
||||
end
|
||||
|
||||
-- 后台任务
|
||||
function _M.cron(self)
|
||||
local timer_every_get_data = function (premature)
|
||||
self.clean_log()
|
||||
end
|
||||
ngx.timer.every(10, timer_every_get_data)
|
||||
|
||||
local timer_every_import_data = function (premature)
|
||||
|
||||
local llen, _ = ngx.shared.waf_limit:llen('waf_limit_logs')
|
||||
if llen == 0 then
|
||||
return true
|
||||
end
|
||||
|
||||
local db = self:initDB()
|
||||
|
||||
db:exec([[BEGIN TRANSACTION]])
|
||||
|
||||
local stmt2 = db:prepare[[INSERT INTO logs(time, ip, domain, server_name, method, status_code, uri, user_agent, rule_name, reason)
|
||||
VALUES(:time, :ip, :domain, :server_name, :method, :status_code, :uri, :user_agent, :rule_name, :reason)]]
|
||||
|
||||
|
||||
if not stmt2 then
|
||||
self:D("waf timer db:prepare fail!:"..tostring(stmt2))
|
||||
return false
|
||||
end
|
||||
|
||||
for i=1,llen do
|
||||
local data, _ = ngx.shared.waf_limit:lpop('waf_limit_logs')
|
||||
-- self:D("waf_limit_logs:"..data)
|
||||
if not data then
|
||||
break
|
||||
end
|
||||
|
||||
local info = json.decode(data)
|
||||
|
||||
stmt2:bind_names{
|
||||
time=info["time"],
|
||||
ip=info["ip"],
|
||||
domain=info["server_name"],
|
||||
server_name=info["server_name"],
|
||||
method=info["method"],
|
||||
status_code=info["status_code"],
|
||||
user_agent=info["user_agent"],
|
||||
uri=info["request_uri"],
|
||||
rule_name=info['rule_name'],
|
||||
reason=info['reason']
|
||||
}
|
||||
|
||||
local res, err = stmt2:step()
|
||||
if tostring(res) == "5" then
|
||||
self:D("waf the step database connection is busy, so it will be stored later.")
|
||||
return false
|
||||
end
|
||||
stmt2:reset()
|
||||
end
|
||||
|
||||
local res, err = db:execute([[COMMIT]])
|
||||
if db and db:isopen() then
|
||||
db:close()
|
||||
end
|
||||
|
||||
end
|
||||
ngx.timer.every(0.5, timer_every_import_data)
|
||||
end
|
||||
|
||||
|
||||
function _M.clean_log(self)
|
||||
local db = self:initDB()
|
||||
local now_date = os.date("*t")
|
||||
local save_day = 90
|
||||
local save_date_timestamp = os.time{year=now_date.year,
|
||||
month=now_date.month, day=now_date.day-save_day, hour=0}
|
||||
-- delete expire data
|
||||
db:exec("DELETE FROM web_logs WHERE time<"..tostring(save_date_timestamp))
|
||||
end
|
||||
|
||||
function _M.log(self, args, rule_name, reason)
|
||||
|
||||
args["rule_name"] = rule_name
|
||||
args["reason"] = reason
|
||||
|
||||
local push_data = json.encode(args)
|
||||
|
||||
ngx.shared.waf_limit:rpush("waf_limit_logs", push_data)
|
||||
-- self:D("push_data:"..push_data)
|
||||
|
||||
-- local db = self:initDB()
|
||||
|
||||
-- local stmt2 = db:prepare[[INSERT INTO logs(time, ip, domain, server_name, method, status_code, uri, user_agent, rule_name, reason)
|
||||
-- VALUES(:time, :ip, :domain, :server_name, :method, :status_code, :uri, :user_agent, :rule_name, :reason)]]
|
||||
|
||||
-- db:exec([[BEGIN TRANSACTION]])
|
||||
|
||||
-- stmt2:bind_names{
|
||||
-- time=args["time"],
|
||||
-- ip=args["ip"],
|
||||
-- domain=args["server_name"],
|
||||
-- server_name=args["server_name"],
|
||||
-- method=args["method"],
|
||||
-- status_code=args["status_code"],
|
||||
-- user_agent=args["user_agent"],
|
||||
-- uri=args["request_uri"],
|
||||
-- rule_name=rule_name,
|
||||
-- reason=reason
|
||||
-- }
|
||||
|
||||
-- local res, err = stmt2:step()
|
||||
-- -- self:D("LOG[1]:"..tostring(res)..":"..tostring(err))
|
||||
|
||||
-- if tostring(res) == "5" then
|
||||
-- self.D("waf the step database connection is busy, so it will be stored later.")
|
||||
-- return false
|
||||
-- end
|
||||
-- stmt2:reset()
|
||||
|
||||
-- local res, err = db:execute([[COMMIT]])
|
||||
-- -- self:D("LOG[2]:"..tostring(res)..":"..tostring(err))
|
||||
-- if db and db:isopen() then
|
||||
-- db:close()
|
||||
-- end
|
||||
-- return true
|
||||
end
|
||||
|
||||
|
||||
function _M.setDebug(self, mode)
|
||||
debug_mode = mode
|
||||
end
|
||||
@@ -38,7 +192,6 @@ end
|
||||
|
||||
-- 调试方式
|
||||
function _M.D(self, msg)
|
||||
|
||||
if not debug_mode then return true end
|
||||
|
||||
local _msg = ''
|
||||
@@ -60,7 +213,8 @@ function _M.D(self, msg)
|
||||
return nil
|
||||
end
|
||||
|
||||
local localtime = os.date("%Y-%m-%d %H:%M:%S")
|
||||
-- local localtime = os.date("%Y-%m-%d %H:%M:%S")
|
||||
local localtime = ngx.localtime()
|
||||
if server_name then
|
||||
fp:write(tostring(_msg) .. "\n")
|
||||
else
|
||||
@@ -72,6 +226,24 @@ function _M.D(self, msg)
|
||||
return true
|
||||
end
|
||||
|
||||
function _M.is_working(self,sign)
|
||||
local work_status = ngx.shared.waf_limit:get(sign.."_working")
|
||||
if work_status ~= nil and work_status == true then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function _M.lock_working(self, sign)
|
||||
local working_key = sign.."_working"
|
||||
ngx.shared.waf_limit:set(working_key, true, 60)
|
||||
end
|
||||
|
||||
function _M.unlock_working(self, sign)
|
||||
local working_key = sign.."_working"
|
||||
ngx.shared.waf_limit:set(working_key, false)
|
||||
end
|
||||
|
||||
|
||||
local function write_file_clear(filename, body)
|
||||
fp = io.open(filename,'w')
|
||||
@@ -127,11 +299,11 @@ function _M.is_max(self,ip1,ip2)
|
||||
end
|
||||
|
||||
function _M.split(self, str,reps )
|
||||
local resultStrList = {}
|
||||
local rsList = {}
|
||||
string.gsub(str,'[^'..reps..']+',function(w)
|
||||
table.insert(resultStrList,w)
|
||||
table.insert(rsList,w)
|
||||
end)
|
||||
return resultStrList
|
||||
return rsList
|
||||
end
|
||||
|
||||
function _M.arrip(self, ipstr)
|
||||
@@ -157,32 +329,41 @@ function _M.compare_ip(self,ips)
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _M.to_json(self, msg)
|
||||
return json.encode(msg)
|
||||
end
|
||||
|
||||
function _M.return_message(self, status, msg)
|
||||
ngx.header.content_type = "application/json;"
|
||||
ngx.status = status
|
||||
ngx.say(json.encode(msg))
|
||||
ngx.exit(status)
|
||||
function _M.return_state(status,msg)
|
||||
result = {}
|
||||
result['status'] = status
|
||||
result['msg'] = msg
|
||||
return result
|
||||
end
|
||||
|
||||
function _M.return_message(self, status, msg)
|
||||
ngx.header.content_type = "application/json"
|
||||
local data = self:return_state(status, msg)
|
||||
ngx.say(json.encode(data))
|
||||
ngx.exit(200)
|
||||
end
|
||||
|
||||
function _M.return_html(self,status,html)
|
||||
function _M.return_html(self, status, html)
|
||||
ngx.header.content_type = "text/html"
|
||||
ngx.status = status
|
||||
ngx.say(html)
|
||||
status = tonumber(status)
|
||||
-- self:D("return_html:"..tostring(status))
|
||||
if status == 200 then
|
||||
ngx.say(html)
|
||||
end
|
||||
ngx.exit(status)
|
||||
end
|
||||
|
||||
function _M.read_file_body(self, filename)
|
||||
-- ngx.log(ngx.ERR,"read_file_body:"..filename)
|
||||
fp = io.open(filename, 'r')
|
||||
if fp == nil then
|
||||
return nil
|
||||
end
|
||||
fbody = fp:read("*a")
|
||||
local fbody = fp:read("*a")
|
||||
fp:close()
|
||||
if fbody == '' then
|
||||
return nil
|
||||
@@ -190,7 +371,38 @@ function _M.read_file_body(self, filename)
|
||||
return fbody
|
||||
end
|
||||
|
||||
function _M.read_file(self, name)
|
||||
f = self.rpath .. name .. '.json'
|
||||
local fbody = self:read_file_body(f)
|
||||
if fbody == nil then
|
||||
return {}
|
||||
end
|
||||
|
||||
local data = json.decode(fbody)
|
||||
return data
|
||||
end
|
||||
|
||||
|
||||
function _M.select_rule(self, rules)
|
||||
if not rules then return {} end
|
||||
new_rules = {}
|
||||
for i,v in ipairs(rules)
|
||||
do
|
||||
if v[1] == 1 then
|
||||
table.insert(new_rules,v[2])
|
||||
end
|
||||
end
|
||||
return new_rules
|
||||
end
|
||||
|
||||
function _M.read_file_table( self, name )
|
||||
return self:select_rule(self:read_file(name))
|
||||
end
|
||||
|
||||
|
||||
function _M.read_file_body_decode(self, name)
|
||||
return json.decode(self:read_file_body(name))
|
||||
end
|
||||
|
||||
function _M.write_file(self, filename, body)
|
||||
fp = io.open(filename,'ab')
|
||||
@@ -203,30 +415,10 @@ function _M.write_file(self, filename, body)
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function _M.write_file_clear(self, filename, body)
|
||||
return write_file_clear(filename, body)
|
||||
end
|
||||
|
||||
|
||||
function _M.write_drop_ip(self, is_drop, drop_time)
|
||||
local filename = self.logdir .. 'drop_ip.log'
|
||||
|
||||
local fp = io.open(filename,'ab')
|
||||
local server_name = self.params["server_name"]
|
||||
local ip = self.params["server_name"]
|
||||
local request_uri = self.params["request_uri"]
|
||||
|
||||
if fp == nil then return false end
|
||||
local logtmp = {os.time(),ip,server_name,request_uri,drop_time,is_drop}
|
||||
local logstr = json.encode(logtmp) .. "\n"
|
||||
fp:write(logstr)
|
||||
fp:flush()
|
||||
fp:close()
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function _M.write_to_file(self, logstr)
|
||||
local server_name = self.params['server_name']
|
||||
local filename = self.logdir .. '/' .. server_name .. '_' .. ngx.today() .. '.log'
|
||||
@@ -234,10 +426,19 @@ function _M.write_to_file(self, logstr)
|
||||
return true
|
||||
end
|
||||
|
||||
-- 是否文件迁入数据库中
|
||||
function _M.is_migrating(self)
|
||||
local migrating = self.waf_root +"/migrating"
|
||||
local file = io.open(migrating, "rb")
|
||||
if file then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function _M.continue_key(self,key)
|
||||
key = tostring(key)
|
||||
if string.len(key) > 64 then return false end;
|
||||
local keys = {"content","contents","body","msg","file","files","img","newcontent"}
|
||||
local keys = { "content", "contents", "body", "msg", "file", "files", "img", "newcontent" }
|
||||
for _,k in ipairs(keys)
|
||||
do
|
||||
if k == key then return false end;
|
||||
@@ -257,7 +458,7 @@ function _M.array_len(self, arr)
|
||||
end
|
||||
|
||||
function _M.is_ipaddr(self, client_ip)
|
||||
local cipn = split(client_ip,'.')
|
||||
local cipn = self:split(client_ip,'.')
|
||||
if self:array_len(cipn) < 4 then return false end
|
||||
for _,v in ipairs({1,2,3,4})
|
||||
do
|
||||
@@ -268,58 +469,29 @@ function _M.is_ipaddr(self, client_ip)
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function _M.read_file_body_decode(self, filename)
|
||||
return json.decode(self:read_file_body(filename))
|
||||
end
|
||||
|
||||
function _M.select_rule(self, rules)
|
||||
if not rules then return {} end
|
||||
new_rules = {}
|
||||
for i,v in ipairs(rules)
|
||||
do
|
||||
if v[1] == 1 then
|
||||
table.insert(new_rules,v[2])
|
||||
end
|
||||
end
|
||||
return new_rules
|
||||
end
|
||||
|
||||
|
||||
function _M.read_file(self, name)
|
||||
f = self.rpath .. name .. '.json'
|
||||
fbody = self:read_file_body(f)
|
||||
if fbody == nil then
|
||||
return {}
|
||||
end
|
||||
return json.decode(fbody)
|
||||
end
|
||||
|
||||
function _M.read_file_table( self, name )
|
||||
return self:select_rule(self:read_file(name))
|
||||
end
|
||||
|
||||
|
||||
local function timer_at_inc_log(premature)
|
||||
local total_path = cpath .. 'total.json'
|
||||
local tbody = ngx.shared.limit:get(total_path)
|
||||
if not tbody then
|
||||
-- 定时异步同步统计信息
|
||||
function _M.timer_stats_total(self)
|
||||
local total_path = self.cpath .. 'total.json'
|
||||
local total = ngx.shared.waf_limit:get(total_path)
|
||||
if not total then
|
||||
return false
|
||||
end
|
||||
return write_file_clear(total_path,tbody)
|
||||
return self:write_file_clear(total_path,total)
|
||||
end
|
||||
|
||||
function _M.inc_log(self, name, rule)
|
||||
|
||||
function _M.stats_total(self, name, rule)
|
||||
local server_name = self.params['server_name']
|
||||
local total_path = self.cpath .. 'total.json'
|
||||
local tbody = ngx.shared.limit:get(total_path)
|
||||
if not tbody then
|
||||
tbody = self:read_file_body(total_path)
|
||||
if not tbody then return false end
|
||||
local total_path = cpath .. 'total.json'
|
||||
local total = ngx.shared.waf_limit:get(total_path)
|
||||
|
||||
if not total then
|
||||
local tbody = self:read_file_body(total_path)
|
||||
total = json.decode(tbody)
|
||||
else
|
||||
total = json.decode(total)
|
||||
end
|
||||
|
||||
local total = json.decode(tbody)
|
||||
if not total then return false end
|
||||
|
||||
-- 开始计算
|
||||
if not total['sites'] then total['sites'] = {} end
|
||||
@@ -332,43 +504,55 @@ function _M.inc_log(self, name, rule)
|
||||
total['sites'][server_name][name] = total['sites'][server_name][name] + 1
|
||||
total['rules'][name] = total['rules'][name] + 1
|
||||
|
||||
local total_log = json.encode(total)
|
||||
if not total_log then return false end
|
||||
|
||||
ngx.shared.limit:set(total_path,total_log)
|
||||
ngx.shared.waf_limit:set(total_path,json.encode(total))
|
||||
|
||||
-- 异步执行
|
||||
ngx.timer.at(1, timer_at_inc_log)
|
||||
|
||||
-- 现在改再init_workder.lua 定时执行
|
||||
-- ngx.timer.every(3, timer_stats_total_log)
|
||||
end
|
||||
|
||||
|
||||
---------------------------------------------------
|
||||
-- 获取配置域名
|
||||
function _M.get_sn(self, config_domains)
|
||||
local request_name = ngx.var.server_name
|
||||
local cache_name = ngx.shared.waf_limit:get(request_name)
|
||||
if cache_name then return cache_name end
|
||||
|
||||
function _M.get_server_name(self)
|
||||
local c_name = ngx.var.server_name
|
||||
local my_name = ngx.shared.limit:get(c_name)
|
||||
if my_name then return my_name end
|
||||
local tmp = self:read_file_body(self.cpath .. 'domains.json')
|
||||
if not tmp then return c_name end
|
||||
local domains = json.decode(tmp)
|
||||
for _,v in ipairs(domains)
|
||||
for _,v in ipairs(config_domains)
|
||||
do
|
||||
for _,d_name in ipairs(v['domains'])
|
||||
for _,cd_name in ipairs(v['domains'])
|
||||
do
|
||||
if c_name == d_name then
|
||||
ngx.shared.limit:set(c_name,v['name'],3600)
|
||||
if request_name == cd_name then
|
||||
ngx.shared.waf_limit:set(request_name,v['name'],86400)
|
||||
return v['name']
|
||||
end
|
||||
end
|
||||
end
|
||||
return c_name
|
||||
return "unset"
|
||||
end
|
||||
|
||||
function _M.get_random(self,n)
|
||||
math.randomseed(ngx.time())
|
||||
local t = {
|
||||
"0","1","2","3","4","5","6","7","8","9",
|
||||
"a","b","c","d","e","f","g","h","i","j",
|
||||
"k","l","m","n","o","p","q","r","s","t",
|
||||
"u","v","w","x","y","z",
|
||||
"A","B","C","D","E","F","G","H","I","J",
|
||||
"K","L","M","N","O","P","Q","R","S","T",
|
||||
"U","V","W","X","Y","Z",
|
||||
}
|
||||
local s = ""
|
||||
for i =1, n do
|
||||
s = s .. t[math.random(#t)]
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _M.is_ngx_match_orgin(self,rule,match, sign)
|
||||
if ngx_match(ngx.unescape_uri(match), rule,"isjo") then
|
||||
function _M.is_ngx_match_orgin(self,rule, match, sign)
|
||||
if ngx_match(ngx.unescape_uri(match), rule, "isjo") then
|
||||
error_rule = rule .. ' >> ' .. sign .. ':' .. match
|
||||
return true
|
||||
end
|
||||
@@ -386,13 +570,28 @@ function _M.ngx_match_string(self, rule, content,sign)
|
||||
end
|
||||
|
||||
function _M.ngx_match_list(self, rules, content)
|
||||
local args_type = type(content)
|
||||
for i,rule in ipairs(rules)
|
||||
do
|
||||
if rule[1] == 1 then
|
||||
local t = self:is_ngx_match_orgin(rule[2], content, rule[3])
|
||||
if t then
|
||||
return true
|
||||
if args_type == 'string' then
|
||||
-- self:D("string: "..tostring(rule[2])..":".. tostring(content)..":"..tostring(rule[3]))
|
||||
local t = self:is_ngx_match_orgin(rule[2], content, rule[3])
|
||||
if t then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
if args_type == 'table' then
|
||||
for _,arg_v in pairs(content) do
|
||||
-- self:D("table : "..tostring(rule[2])..":".. tostring(arg_v)..":"..tostring(rule[3]))
|
||||
local t = self:is_ngx_match_orgin(rule[2], arg_v, rule[3])
|
||||
if t then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
return false
|
||||
@@ -428,115 +627,85 @@ function _M.is_ngx_match_post(self, rules, content)
|
||||
end
|
||||
|
||||
|
||||
function _M.is_ngx_match(self, rules, sbody, rule_name)
|
||||
if rules == nil or sbody == nil then return false end
|
||||
if type(sbody) == "string" then
|
||||
sbody = {sbody}
|
||||
end
|
||||
|
||||
if type(rules) == "string" then
|
||||
rules = {rules}
|
||||
end
|
||||
|
||||
for k,body in pairs(sbody)
|
||||
do
|
||||
if self:continue_key(k) then
|
||||
for i,rule in ipairs(rules)
|
||||
do
|
||||
if self.site_config[server_name] and rule_name then
|
||||
local n = i - 1
|
||||
for _,j in ipairs(self.site_config[server_name]['disable_rule'][rule_name])
|
||||
do
|
||||
if n == j then
|
||||
rule = ""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if body and rule ~="" then
|
||||
if type(body) == "string" then
|
||||
if ngx_match(ngx.unescape_uri(body),rule,"isjo") then
|
||||
error_rule = rule .. ' >> ' .. k .. ':' .. body
|
||||
return true
|
||||
end
|
||||
end
|
||||
if type(k) == "string" then
|
||||
if ngx_match(ngx.unescape_uri(k),rule,"isjo") then
|
||||
error_rule = rule .. ' >> ' .. k
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function _M.write_log(self, name, rule)
|
||||
local config = self.config
|
||||
local params = self.params
|
||||
|
||||
local ip = self.params['ip']
|
||||
local retry = self.config['retry']['retry']
|
||||
local retry_time = self.config['retry']['retry_time']
|
||||
local retry_cycle = self.config['retry']['retry_cycle']
|
||||
local ip = params['ip']
|
||||
local ngx_time = ngx.time()
|
||||
|
||||
local count, _ = ngx.shared.drop_ip:get(ip)
|
||||
local retry = config['retry']['retry']
|
||||
local retry_time = config['retry']['retry_time']
|
||||
local retry_cycle = config['retry']['retry_cycle']
|
||||
|
||||
local count = ngx.shared.waf_drop_ip:get(ip)
|
||||
if count then
|
||||
ngx.shared.drop_ip:incr(ip,1)
|
||||
ngx.shared.waf_drop_ip:incr(ip, 1)
|
||||
else
|
||||
ngx.shared.drop_ip:set(ip,1,retry_cycle)
|
||||
ngx.shared.waf_drop_ip:set(ip, 1, retry_cycle)
|
||||
end
|
||||
|
||||
if self.config['log'] ~= true or self:is_site_config('log') ~= true then return false end
|
||||
local method = ngx.req.get_method()
|
||||
if config['log'] ~= true or self:is_site_config('log') ~= true then return false end
|
||||
local method = params['method']
|
||||
if error_rule then
|
||||
rule = error_rule
|
||||
error_rule = nil
|
||||
end
|
||||
|
||||
local logtmp = {ngx.localtime(), ip, method, ngx.var.request_uri, ngx.var.http_user_agent, name, rule}
|
||||
local logstr = json.encode(logtmp) .. "\n"
|
||||
local count,_ = ngx.shared.drop_ip:get(ip)
|
||||
if count > retry and name ~= 'cc' then
|
||||
local safe_count,_ = ngx.shared.drop_sum:get(ip)
|
||||
local count = ngx.shared.waf_drop_ip:get(ip)
|
||||
-- self:D("write_log; count:" ..tostring(count).. ",retry:" .. tostring(retry) )
|
||||
if (count > retry and name ~= 'cc') then
|
||||
local safe_count,_ = ngx.shared.waf_drop_sum:get(ip)
|
||||
if not safe_count then
|
||||
ngx.shared.drop_sum:set(ip,1,86400)
|
||||
ngx.shared.waf_drop_sum:set(ip, 1, 86400)
|
||||
safe_count = 1
|
||||
else
|
||||
ngx.shared.drop_sum:incr(ip,1)
|
||||
ngx.shared.waf_drop_sum:incr(ip, 1)
|
||||
end
|
||||
local lock_time = retry_time * safe_count
|
||||
if lock_time > 86400 then lock_time = 86400 end
|
||||
logtmp = {ngx.localtime(),ip,method,ngx.var.request_uri, ngx.var.http_user_agent,name,retry_cycle .. '秒以内累计超过'..retry..'次以上非法请求,封锁'.. lock_time ..'秒'}
|
||||
logstr = logstr .. json.encode(logtmp) .. "\n"
|
||||
ngx.shared.drop_ip:set(ip,retry+1,lock_time)
|
||||
self:write_drop_ip('inc',lock_time)
|
||||
|
||||
retry_times = retry + 1
|
||||
ngx.shared.waf_drop_ip:set(ip, retry_times, lock_time)
|
||||
|
||||
local reason = retry_cycle .. '秒以内累计超过'..retry..'次以上非法请求,封锁'.. lock_time ..'秒'
|
||||
self:log(params, name, reason)
|
||||
elseif name ~= 'cc' then
|
||||
self:log(params, name, rule)
|
||||
end
|
||||
self:write_to_file(logstr)
|
||||
self:inc_log(name,rule)
|
||||
|
||||
self:stats_total(name, rule)
|
||||
end
|
||||
|
||||
|
||||
function _M.get_client_ip(self)
|
||||
function _M.get_real_ip(self, server_name)
|
||||
local client_ip = "unknown"
|
||||
local server_name = self.params['server_name']
|
||||
-- self:D("fff..."..client_ip..server_name)
|
||||
if self.site_config[server_name] then
|
||||
if self.site_config[server_name]['cdn'] then
|
||||
for _,v in ipairs(self.site_config[server_name]['cdn_header'])
|
||||
local site_config = self.site_config
|
||||
if site_config[server_name] then
|
||||
if site_config[server_name]['cdn'] then
|
||||
local request_header = ngx.req.get_headers()
|
||||
for _,v in ipairs(site_config[server_name]['cdn_header'])
|
||||
do
|
||||
-- C:D("vv:"..v..tostring(request_header[v]))
|
||||
if request_header[v] ~= nil and request_header[v] ~= "" then
|
||||
local header_tmp = request_header[v]
|
||||
if type(header_tmp) == "table" then header_tmp = header_tmp[1] end
|
||||
client_ip = split(header_tmp,',')[1]
|
||||
client_ip = self:split(header_tmp,',')[1]
|
||||
-- return client_ip
|
||||
break;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if string.match(client_ip,"%d+%.%d+%.%d+%.%d+") == nil or not self:is_ipaddr(client_ip) then
|
||||
|
||||
|
||||
-- ipv6
|
||||
if type(client_ip) == 'table' then client_ip = "" end
|
||||
if client_ip ~= "unknown" and ngx.re.match(client_ip,"^([a-fA-F0-9]*):") then
|
||||
return client_ip
|
||||
end
|
||||
|
||||
-- ipv4
|
||||
if not ngx.re.match(client_ip,"\\d+\\.\\d+\\.\\d+\\.\\d+") == nil or not self:is_ipaddr(client_ip) then
|
||||
client_ip = ngx.var.remote_addr
|
||||
if client_ip == nil then
|
||||
client_ip = "unknown"
|
||||
@@ -547,11 +716,12 @@ end
|
||||
|
||||
|
||||
function _M.is_site_config(self,cname)
|
||||
if self.site_config[server_name] ~= nil then
|
||||
local site_config = self.site_config
|
||||
if site_config[server_name] ~= nil then
|
||||
if cname == 'cc' then
|
||||
return self.site_config[server_name][cname]['open']
|
||||
return site_config[server_name][cname]['open']
|
||||
else
|
||||
return self.site_config[server_name][cname]
|
||||
return site_config[server_name][cname]
|
||||
end
|
||||
end
|
||||
return true
|
||||
@@ -572,6 +742,16 @@ function _M.get_boundary(self)
|
||||
end
|
||||
|
||||
|
||||
function _M.is_key(self, arr, key)
|
||||
for _,v in ipairs(arr) do
|
||||
if v == key then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function _M.return_post_data(self)
|
||||
if method ~= "POST" then return false end
|
||||
content_length = tonumber(self.params["request_header"]['content-length'])
|
||||
|
||||
+277
-326
@@ -1,153 +1,169 @@
|
||||
|
||||
local json = require "cjson"
|
||||
local ngx_match = ngx.re.find
|
||||
|
||||
local __C = require "common"
|
||||
local C = __C:new()
|
||||
local __WAF = require "common"
|
||||
|
||||
local waf_root = "{$WAF_ROOT}"
|
||||
-- print(json.encode(__C))
|
||||
local C = __WAF:getInstance()
|
||||
|
||||
local config = require "waf_config"
|
||||
local site_config = require "waf_site"
|
||||
local config_domains = require "waf_domains"
|
||||
|
||||
-- C:D("config:"..C:to_json(config))
|
||||
|
||||
config = C:read_file_body_decode(waf_root.."/waf/"..'config.json')
|
||||
local site_config = C:read_file_body_decode(waf_root.."/waf/"..'site.json')
|
||||
C:setConfData(config, site_config)
|
||||
C:setDebug(true)
|
||||
|
||||
|
||||
local get_html = require "html_get"
|
||||
local post_html = require "html_post"
|
||||
local other_html = require "html_other"
|
||||
local user_agent_html = require "html_user_agent"
|
||||
local cc_safe_js_html = require "html_safe_js"
|
||||
local cookie_html = require "html_cookie"
|
||||
|
||||
local get_html = C:read_file_body(config["reqfile_path"] .. '/' .. config["get"]["reqfile"])
|
||||
local post_html = C:read_file_body(config["reqfile_path"] .. '/' .. config["post"]["reqfile"])
|
||||
local user_agent_html = C:read_file_body(config["reqfile_path"] .. '/' .. config["user-agent"]["reqfile"])
|
||||
local args_rules = C:read_file_table('args')
|
||||
local ip_white_rules = C:read_file('ip_white')
|
||||
local ip_black_rules = C:read_file('ip_black')
|
||||
local scan_black_rules = C:read_file('scan_black')
|
||||
local user_agent_rules = C:read_file('user_agent')
|
||||
local post_rules = C:read_file('post')
|
||||
local cookie_rules = C:read_file('cookie')
|
||||
local args_rules = require "rule_args"
|
||||
local ip_white_rules = require "rule_ip_white"
|
||||
local ip_black_rules = require "rule_ip_black"
|
||||
local ipv6_black_rules = require "rule_ipv6_black"
|
||||
local scan_black_rules = require "rule_scan_black"
|
||||
local user_agent_rules = require "rule_user_agent"
|
||||
local post_rules = require "rule_post"
|
||||
local cookie_rules = require "rule_cookie"
|
||||
local url_rules = require "rule_url"
|
||||
local url_white_rules = require "rule_url_white"
|
||||
|
||||
|
||||
local server_name = string.gsub(C:get_server_name(),'_','.')
|
||||
local server_name = string.gsub(C:get_sn(config_domains),'_','.')
|
||||
|
||||
|
||||
-- C:D("sss:"..C:get_server_name())
|
||||
function initParams()
|
||||
local function initParams()
|
||||
local data = {}
|
||||
data['server_name'] = server_name
|
||||
-- data['ip'] = C:get_client_ip()
|
||||
-- data['ipn'] = C:arrip(data['ip'])
|
||||
data['ip'] = C:get_real_ip(server_name)
|
||||
data['ipn'] = C:arrip(data['ip'])
|
||||
data['request_header'] = ngx.req.get_headers()
|
||||
data['uri'] = ngx.unescape_uri(ngx.var.uri)
|
||||
data['uri'] = tostring(ngx.unescape_uri(ngx.var.uri))
|
||||
data['uri_request_args'] = ngx.req.get_uri_args()
|
||||
data['method'] = ngx.req.get_method()
|
||||
data['request_uri'] = ngx.var.request_uri
|
||||
data['request_uri'] = tostring(ngx.var.request_uri)
|
||||
data['status_code'] = ngx.status
|
||||
data['user_agent'] = data['request_header']['user-agent']
|
||||
data['cookie'] = ngx.var.http_cookie
|
||||
data['time'] = ngx.time()
|
||||
return data
|
||||
end
|
||||
|
||||
local params = initParams()
|
||||
C:setParams(params)
|
||||
C:setDebug(true)
|
||||
|
||||
local server_name = params["server_name"]
|
||||
params['ip'] = C:get_client_ip()
|
||||
params['ipn'] = C:arrip(params['ip'])
|
||||
C:D(server_name)
|
||||
local cpu_percent = ngx.shared.waf_limit:get("cpu_usage")
|
||||
if not cpu_percent then
|
||||
cpu_percent = 0
|
||||
end
|
||||
|
||||
function get_return_state(rstate,rmsg)
|
||||
local function get_return_state(rstate,rmsg)
|
||||
result = {}
|
||||
result['status'] = rstate
|
||||
result['msg'] = rmsg
|
||||
return result
|
||||
end
|
||||
|
||||
function get_waf_drop_ip()
|
||||
local data = ngx.shared.drop_ip:get_keys(0)
|
||||
local function get_waf_drop_ip()
|
||||
local data = ngx.shared.waf_drop_ip:get_keys(0)
|
||||
return data
|
||||
end
|
||||
|
||||
local function return_json(status,msg)
|
||||
ngx.header.content_type = "application/json"
|
||||
result = {}
|
||||
result['status'] = status
|
||||
result['msg'] = msg
|
||||
ngx.say(json.encode(data))
|
||||
ngx.exit(200)
|
||||
end
|
||||
|
||||
function is_chekc_table(data,strings)
|
||||
local function is_chekc_table(data,strings)
|
||||
if type(data) ~= 'table' then return 1 end
|
||||
if not data then return 1 end
|
||||
data=chekc_ip_timeout(data)
|
||||
data = chekc_ip_timeout(data)
|
||||
for k,v in pairs(data)
|
||||
do
|
||||
if strings ==v['ip'] then
|
||||
if strings == v['ip'] then
|
||||
return 3
|
||||
end
|
||||
end
|
||||
return 2
|
||||
end
|
||||
|
||||
function save_ip_on(data)
|
||||
locak_file=read_file_body(cpath2 .. 'stop_ip.lock')
|
||||
if not locak_file then
|
||||
C:write_file(cpath2 .. 'stop_ip.lock','1')
|
||||
local function remove_waf_drop_ip()
|
||||
ngx.header.content_type = "application/json"
|
||||
local ip = params['uri_request_args']['ip']
|
||||
|
||||
if not ip or not C:is_ipaddr(ip) then
|
||||
local data = get_return_state(-1, "格式错误")
|
||||
ngx.say(json.encode(data))
|
||||
ngx.exit(200)
|
||||
return true
|
||||
end
|
||||
name='stop_ip'
|
||||
local extime=18000
|
||||
data=json.encode(data)
|
||||
ngx.shared.btwaf:set(cpath2 .. name,data,extime)
|
||||
if not ngx.shared.btwaf:get(cpath2 .. name .. '_lock') then
|
||||
ngx.shared.btwaf:set(cpath2 .. name .. '_lock',1,0.5)
|
||||
C:write_file(cpath2 .. name .. '.json',data)
|
||||
|
||||
local sign = "remove_waf_drop_ip"
|
||||
if C:is_working(sign) then
|
||||
local data = get_return_state(-1, "fail")
|
||||
ngx.say(json.encode(data))
|
||||
ngx.exit(200)
|
||||
return true
|
||||
end
|
||||
|
||||
C:lock_working(sign)
|
||||
ngx.shared.waf_drop_ip:delete(ip)
|
||||
C:unlock_working(sign)
|
||||
|
||||
local data = get_return_state(0, "ok")
|
||||
ngx.say(json.encode(data))
|
||||
ngx.exit(200)
|
||||
end
|
||||
|
||||
function remove_waf_drop_ip()
|
||||
if not uri_request_args['ip'] or not C:is_ipaddr(uri_request_args['ip']) then return get_return_state(true,'格式错误') end
|
||||
if ngx.shared.btwaf:get(cpath2 .. 'stop_ip') then
|
||||
ret=ngx.shared.btwaf:get(cpath2 .. 'stop_ip')
|
||||
ip_data=json.decode(ret)
|
||||
result = is_chekc_table(ip_data,uri_request_args['ip'])
|
||||
os.execute("sleep " .. 0.6)
|
||||
ret2=ngx.shared.btwaf:get(cpath2 .. 'stop_ip')
|
||||
ip_data2 = json.decode(ret2)
|
||||
if result == 3 then
|
||||
for k,v in pairs(ip_data2)
|
||||
do
|
||||
if uri_request_args['ip'] == v['ip'] then
|
||||
v['time'] = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
save_ip_on(ip_data2)
|
||||
local function clean_waf_drop_ip()
|
||||
ngx.header.content_type = "application/json"
|
||||
|
||||
local sign = "clean_waf_drop_ip"
|
||||
if C:is_working(sign) then
|
||||
local data = get_return_state(-1, "fail")
|
||||
ngx.say(json.encode(data))
|
||||
ngx.exit(200)
|
||||
return true
|
||||
end
|
||||
ngx.shared.drop_ip:delete(uri_request_args['ip'])
|
||||
return get_return_state(true,uri_request_args['ip'] .. '已解封')
|
||||
|
||||
C:lock_working(sign)
|
||||
ngx.shared.waf_drop_ip:flush_all()
|
||||
C:unlock_working(sign)
|
||||
|
||||
local data = get_return_state(0, "ok")
|
||||
ngx.say(json.encode(data))
|
||||
ngx.exit(200)
|
||||
end
|
||||
|
||||
function clean_waf_drop_ip()
|
||||
if ngx.shared.btwaf:get(cpath2 .. 'stop_ip') then
|
||||
ret2=ngx.shared.btwaf:get(cpath2 .. 'stop_ip')
|
||||
ip_data2=json.decode(ret2)
|
||||
for k,v in pairs(ip_data2)
|
||||
do
|
||||
v['time']=0
|
||||
end
|
||||
save_ip_on(ip_data2)
|
||||
os.execute("sleep " .. 2)
|
||||
end
|
||||
local data = get_btwaf_drop_ip()
|
||||
for _,value in ipairs(data)
|
||||
do
|
||||
ngx.shared.drop_ip:delete(value)
|
||||
end
|
||||
return get_return_state(true,'已解封所有封锁IP')
|
||||
end
|
||||
|
||||
function min_route()
|
||||
local function min_route()
|
||||
if ngx.var.remote_addr ~= '127.0.0.1' then return false end
|
||||
local uri = params['uri']
|
||||
if uri == '/get_waf_drop_ip' then
|
||||
return_message(200,get_waf_drop_ip())
|
||||
ngx.header.content_type = "application/json"
|
||||
local data = get_return_state(0, get_waf_drop_ip())
|
||||
ngx.say(json.encode(data))
|
||||
ngx.exit(200)
|
||||
elseif uri == '/remove_waf_drop_ip' then
|
||||
return_message(200,remove_waf_drop_ip())
|
||||
remove_waf_drop_ip()
|
||||
elseif uri == '/clean_waf_drop_ip' then
|
||||
return_message(200,clean_waf_drop_ip())
|
||||
clean_waf_drop_ip()
|
||||
end
|
||||
end
|
||||
|
||||
function waf_get_args()
|
||||
local function waf_get_args()
|
||||
if not config['get']['open'] or not C:is_site_config('get') then return false end
|
||||
if C:is_ngx_match(args_rules, params['uri_request_args'],'args') then
|
||||
-- C:D("waf_get_args:"..C:to_json(args_rules)..":"..json.encode(params['uri_request_args']))
|
||||
if C:ngx_match_list(args_rules, params['uri_request_args']) then
|
||||
C:write_log('args','regular')
|
||||
C:return_html(config['get']['status'], get_html)
|
||||
return true
|
||||
@@ -156,7 +172,7 @@ function waf_get_args()
|
||||
end
|
||||
|
||||
|
||||
function waf_ip_white()
|
||||
local function waf_ip_white()
|
||||
for _,rule in ipairs(ip_white_rules)
|
||||
do
|
||||
if C:compare_ip(rule) then
|
||||
@@ -166,7 +182,15 @@ function waf_ip_white()
|
||||
return false
|
||||
end
|
||||
|
||||
function waf_ip_black()
|
||||
local function waf_url_white()
|
||||
if C:ngx_match_list(url_white_rules, params['uri']) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function waf_ip_black()
|
||||
-- ipv4 ip black
|
||||
for _,rule in ipairs(ip_black_rules)
|
||||
do
|
||||
if C:compare_ip(rule) then
|
||||
@@ -174,117 +198,178 @@ function waf_ip_black()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- ipv6 ip black
|
||||
for _,rule in ipairs(ipv6_black_rules)
|
||||
do
|
||||
if rule == params['ip'] then
|
||||
ngx.exit(config['cc']['status'])
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function waf_user_agent()
|
||||
local function waf_user_agent()
|
||||
-- user_agent 过滤
|
||||
if not config['user-agent']['open'] or not C:is_site_config('user-agent') then return false end
|
||||
if C:is_ngx_match_ua(user_agent_rules,params['request_header']['user-agent']) then
|
||||
-- if not config['user-agent']['open'] or not C:is_site_config('user-agent') then return false end
|
||||
|
||||
-- C:D("waf_user_agent;user_agent_rules:"..json.encode(user_agent_rules)..",ua:"..tostring(params['request_header']['user-agent']))
|
||||
if C:ngx_match_list(user_agent_rules, params['request_header']['user-agent']) then
|
||||
-- C:D("waf_user_agent........... true")
|
||||
C:write_log('user_agent','regular')
|
||||
C:return_html(config['user-agent']['status'],user_agent_html)
|
||||
C:return_html(config['user-agent']['status'], user_agent_html)
|
||||
return true
|
||||
end
|
||||
|
||||
-- C:D("waf_user_agent........... false")
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function waf_drop()
|
||||
local count , _ = ngx.shared.drop_ip:get(ip)
|
||||
local function waf_drop_ip()
|
||||
local ip = params['ip']
|
||||
local count = ngx.shared.waf_drop_ip:get(ip)
|
||||
if not count then return false end
|
||||
if count > config['retry'] then
|
||||
|
||||
local retry = config['retry']['retry']
|
||||
-- C:D("waf_drop;count:"..tostring(count)..",retry:"..tostring(retry))
|
||||
-- C:D("waf_drop;count > retry:"..tostring(count > retry))
|
||||
if count > retry then
|
||||
-- C:D("waf_drop_ip........... true")
|
||||
ngx.exit(config['cc']['status'])
|
||||
return true
|
||||
end
|
||||
-- C:D("waf_drop_ip........... false")
|
||||
return false
|
||||
end
|
||||
|
||||
function waf_cc()
|
||||
local ip = params['ip']
|
||||
|
||||
local ip_lock = ngx.shared.drop_ip:get(ip)
|
||||
if ip_lock then
|
||||
if ip_lock > 0 then
|
||||
ngx.exit(config['cc']['status'])
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local function waf_cc()
|
||||
if not config['cc']['open'] or not C:is_site_config('cc') then return false end
|
||||
|
||||
local ip = params['ip']
|
||||
|
||||
-- 多次cc,才封禁。
|
||||
-- local ip_lock = ngx.shared.waf_drop_ip:get(ip)
|
||||
-- if ip_lock then
|
||||
-- if ip_lock > 0 then
|
||||
-- ngx.exit(config['cc']['status'])
|
||||
-- return true
|
||||
-- end
|
||||
-- end
|
||||
|
||||
local request_uri = params['request_uri']
|
||||
local endtime = config['cc']['endtime']
|
||||
|
||||
local token = ngx.md5(ip .. '_' .. request_uri)
|
||||
local count = ngx.shared.limit:get(token)
|
||||
local count = ngx.shared.waf_limit:get(token)
|
||||
|
||||
local limit = config['cc']['limit']
|
||||
local endtime = config['cc']['endtime']
|
||||
local waf_limit = config['cc']['limit']
|
||||
local cycle = config['cc']['cycle']
|
||||
|
||||
if count then
|
||||
if count > limit then
|
||||
if count > waf_limit then
|
||||
|
||||
local safe_count, _ = ngx.shared.drop_sum:get(ip)
|
||||
local safe_count, _ = ngx.shared.waf_drop_sum:get(ip)
|
||||
if not safe_count then
|
||||
ngx.shared.drop_sum:set(ip,1,86400)
|
||||
ngx.shared.waf_drop_sum:set(ip, 1, 86400)
|
||||
safe_count = 1
|
||||
else
|
||||
ngx.shared.drop_sum:incr(ip,1)
|
||||
ngx.shared.waf_drop_sum:incr(ip, 1)
|
||||
end
|
||||
local lock_time = (endtime * safe_count)
|
||||
if lock_time > 86400 then lock_time = 86400 end
|
||||
|
||||
-- lock_time = 10
|
||||
ngx.shared.drop_ip:set(ip,1,lock_time)
|
||||
|
||||
C:write_log('cc',cycle..'秒内累计超过'..limit..'次请求,封锁' .. lock_time .. '秒')
|
||||
C:write_drop_ip('cc',lock_time)
|
||||
ngx.shared.waf_drop_ip:set(ip, 1, lock_time)
|
||||
local reason = cycle..'秒内累计超过'..waf_limit..'次请求,封锁' .. lock_time .. '秒'
|
||||
C:write_log('cc', reason)
|
||||
C:log(params, 'cc',reason)
|
||||
ngx.exit(config['cc']['status'])
|
||||
return true
|
||||
else
|
||||
ngx.shared.limit:incr(token,1)
|
||||
ngx.shared.waf_limit:incr(token, 1)
|
||||
end
|
||||
else
|
||||
ngx.shared.drop_sum:set(ip,1,86400)
|
||||
ngx.shared.limit:set(token, 1, cycle)
|
||||
ngx.shared.waf_drop_sum:set(ip, 1, 86400)
|
||||
ngx.shared.waf_limit:set(token, 1, cycle)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--强制验证是否使用正常浏览器访问网站
|
||||
function waf_cc_increase()
|
||||
|
||||
if not config['cc']['open'] or not site_cc then return false end
|
||||
if not site_config[server_name] then return false end
|
||||
if not site_config[server_name]['cc']['increase'] then return false end
|
||||
local cache_token = ngx.md5(ip .. '_' .. server_name)
|
||||
--判断是否已经通过验证
|
||||
if ngx.shared.btwaf:get(cache_token) then return false end
|
||||
if cc_uri_white() then
|
||||
ngx.shared.btwaf:delete(cache_token .. '_key')
|
||||
ngx.shared.btwaf:set(cache_token,1,60)
|
||||
return false
|
||||
-- 是否符合开强制验证条件
|
||||
local function is_open_waf_cc_increase()
|
||||
|
||||
if config['safe_verify']['open'] then
|
||||
return true
|
||||
end
|
||||
if security_verification() then return false end
|
||||
send_check_heml(cache_token)
|
||||
|
||||
-- C:D("waf config:"..json.encode(config))
|
||||
if cpu_percent >= config['safe_verify']['cpu'] then
|
||||
return true
|
||||
end
|
||||
|
||||
if site_config[server_name] and site_config[server_name]['safe_verify']['open'] then
|
||||
if cpu_percent >= site_config[server_name]['safe_verify']['cpu'] then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function waf_url()
|
||||
--强制验证是否使用正常浏览器访问网站
|
||||
local function waf_cc_increase()
|
||||
if not is_open_waf_cc_increase() then return false end
|
||||
|
||||
local ip = params['ip']
|
||||
local uri = params['uri']
|
||||
local cache_token = ngx.md5(ip .. '_' .. server_name)
|
||||
|
||||
--判断是否已经通过验证
|
||||
if ngx.shared.waf_limit:get(cache_token) then return false end
|
||||
|
||||
local cache_rand_key = ip..':rand'
|
||||
local cache_rand = ngx.shared.waf_limit:get(cache_rand_key)
|
||||
if not cache_rand then
|
||||
cache_rand = C:get_random(8)
|
||||
ngx.shared.waf_limit:set(cache_rand_key,cache_rand,30)
|
||||
end
|
||||
|
||||
local make_token = "waf_unbind_"..cache_rand.."_"..cache_token
|
||||
local make_uri_str = "?token="..make_token
|
||||
local make_uri = "/"..make_uri_str
|
||||
|
||||
if params['uri_request_args']['token'] then
|
||||
local args_token = params['uri_request_args']['token']
|
||||
if args_token == make_token then
|
||||
ngx.shared.waf_limit:set(cache_token, 1, config['safe_verify']['time'])
|
||||
local data = get_return_state(0, "ok")
|
||||
ngx.say(json.encode(data))
|
||||
ngx.exit(200)
|
||||
end
|
||||
end
|
||||
|
||||
local cc_html = ngx.re.gsub(cc_safe_js_html, "{uri}", make_uri_str)
|
||||
C:return_html(200, cc_html)
|
||||
end
|
||||
|
||||
|
||||
local function waf_url()
|
||||
if not config['get']['open'] or not C:is_site_config('get') then return false end
|
||||
--正则--
|
||||
if C:is_ngx_match(url_rules,params["uri"],'url') then
|
||||
-- C:D("waf_url:"..json.encode(url_rules)..":uri:"..params["uri"])
|
||||
if C:ngx_match_list(url_rules, params["uri"]) then
|
||||
C:write_log('url','regular')
|
||||
C:return_html(config['get']['status'],get_html)
|
||||
C:return_html(config['get']['status'], get_html)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function waf_scan_black()
|
||||
local function waf_scan_black()
|
||||
-- 扫描软件禁止
|
||||
if not config['scan']['open'] or not C:is_site_config('scan') then return false end
|
||||
if not params["cookie"] then
|
||||
@@ -312,18 +397,17 @@ function waf_scan_black()
|
||||
return false
|
||||
end
|
||||
|
||||
function waf_post()
|
||||
local function waf_post()
|
||||
if not config['post']['open'] or not C:is_site_config('post') then return false end
|
||||
if params['method'] ~= "POST" then return false end
|
||||
content_length = tonumber(params["request_header"]['content-length'])
|
||||
max_len = 640 * 1020000
|
||||
local content_length = tonumber(params["request_header"]['content-length'])
|
||||
local max_len = 640 * 1020000
|
||||
if content_length > max_len then return false end
|
||||
if C:get_boundary() then return false end
|
||||
ngx.req.read_body()
|
||||
request_args = ngx.req.get_post_args()
|
||||
if not request_args then
|
||||
return false
|
||||
end
|
||||
|
||||
local request_args = params['uri_request_args']
|
||||
if not request_args then return false end
|
||||
|
||||
for key, val in pairs(request_args) do
|
||||
if type(val) == "table" then
|
||||
@@ -334,124 +418,54 @@ function waf_post()
|
||||
else
|
||||
data = val
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if C:is_ngx_match_post(post_rules,data) then
|
||||
-- C:D("post:"..json.encode(data))
|
||||
if C:ngx_match_list(post_rules, data) then
|
||||
C:write_log('post','regular')
|
||||
C:return_html(config['post']['status'],post_html)
|
||||
C:return_html(config['post']['status'], post_html)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function X_Forwarded()
|
||||
|
||||
function post_data_chekc()
|
||||
if params['method'] =="POST" then
|
||||
if C:return_post_data() then return false end
|
||||
ngx.req.read_body()
|
||||
request_args = ngx.req.get_post_args()
|
||||
if not request_args then return false end
|
||||
|
||||
if request_header then
|
||||
if not request_header['Content-Type'] then return false end
|
||||
av = string.match(request_header['Content-Type'],"=.+")
|
||||
end
|
||||
|
||||
if not av then return false end
|
||||
ac = split(av,'=')
|
||||
|
||||
if not ac then return false end
|
||||
|
||||
list_list=nil
|
||||
for i,v in ipairs(ac)
|
||||
do
|
||||
list_list='--'..v
|
||||
end
|
||||
|
||||
if not list_list then return false end
|
||||
|
||||
aaa = nil
|
||||
for k,v in pairs(request_args)
|
||||
do
|
||||
aaa = v
|
||||
end
|
||||
|
||||
if not aaa then return false end
|
||||
if tostring(aaa) == 'true' then return false end
|
||||
if type(aaa) ~= "string" then return false end
|
||||
data_len=split(aaa,list_list)
|
||||
|
||||
--return return_message(200,data_len)
|
||||
if not data_len then return false end
|
||||
if arrlen(data_len) ==0 then return false end
|
||||
|
||||
if C:is_ngx_match_post(post_rules , data_len) then
|
||||
C:write_log('post','regular')
|
||||
C:return_html(config['post']['status'],post_html)
|
||||
return true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function X_Forwarded()
|
||||
if params['method'] ~= "GET" then return false end
|
||||
if not config['get']['open'] or not C:is_site_config('get') then return false end
|
||||
if C:is_ngx_match(args_rules,params["request_header"]['X-forwarded-For'],'args') then
|
||||
if not params["request_header"]['X-forwarded-For'] then return false end
|
||||
|
||||
if C:ngx_match_list(args_rules, params["request_header"]['X-forwarded-For']) then
|
||||
C:write_log('args','regular')
|
||||
C:return_html(config['get']['status'],get_html)
|
||||
C:return_html(config['get']['status'], get_html)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function post_X_Forwarded()
|
||||
local function post_X_Forwarded()
|
||||
if not config['post']['open'] or not C:is_site_config('post') then return false end
|
||||
if params['method'] ~= "POST" then return false end
|
||||
if C:is_ngx_match_post(post_rules,params["request_header"]['X-forwarded-For']) then
|
||||
if not params["request_header"]['X-forwarded-For'] then return false end
|
||||
if C:ngx_match_list(post_rules, params["request_header"]['X-forwarded-For']) then
|
||||
C:write_log('post','regular')
|
||||
C:return_html(config['post']['status'],post_html)
|
||||
C:return_html(config['post']['status'], post_html)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
-- function php_path()
|
||||
-- if site_config[server_name] == nil then return false end
|
||||
-- for _,rule in ipairs(site_config[server_name]['disable_php_path'])
|
||||
-- do
|
||||
-- if C:ngx_match_string(params['uri'],rule .. "/?.*\\.php$","isjo") then
|
||||
-- C:write_log('php_path','regular')
|
||||
-- C:return_html(config['other']['status'],other_html)
|
||||
-- return C:return_message(200,uri)
|
||||
-- end
|
||||
-- end
|
||||
-- return false
|
||||
-- end
|
||||
|
||||
-- function url_path()
|
||||
-- if site_config[server_name] == nil then return false end
|
||||
-- for _,rule in ipairs(site_config[server_name]['disable_path'])
|
||||
-- do
|
||||
-- if ngx_match(uri,rule,"isjo") then
|
||||
-- C:write_log('path','regular')
|
||||
-- C:return_html(config['other']['status'],other_html)
|
||||
-- return true
|
||||
-- end
|
||||
-- end
|
||||
-- return false
|
||||
-- end
|
||||
|
||||
function url_ext()
|
||||
local function url_ext()
|
||||
if site_config[server_name] == nil then return false end
|
||||
for _,rule in ipairs(site_config[server_name]['disable_ext'])
|
||||
do
|
||||
if C:ngx_match_string("\\."..rule.."$", params['uri'],'url_ext') then
|
||||
C:write_log('url_ext','regular')
|
||||
if rule == "php" then
|
||||
C:write_log('php_path','regular')
|
||||
else
|
||||
C:write_log('path','regular')
|
||||
end
|
||||
C:return_html(config['other']['status'], other_html)
|
||||
return true
|
||||
end
|
||||
@@ -459,103 +473,39 @@ function url_ext()
|
||||
return false
|
||||
end
|
||||
|
||||
function url_rule_ex()
|
||||
if site_config[server_name] == nil then return false end
|
||||
if method == "POST" and not request_args then
|
||||
content_length=tonumber(request_header['content-length'])
|
||||
max_len = 640 * 102400000
|
||||
request_args = nil
|
||||
if content_length < max_len then
|
||||
ngx.req.read_body()
|
||||
request_args = ngx.req.get_post_args()
|
||||
end
|
||||
end
|
||||
for _,rule in ipairs(site_config[server_name]['url_rule'])
|
||||
do
|
||||
if ngx_match(uri,rule[1],"isjo") then
|
||||
if C:is_ngx_match(rule[2],uri_request_args,false) then
|
||||
C:write_log('url_rule','regular')
|
||||
C:return_html(config['other']['status'],other_html)
|
||||
return true
|
||||
end
|
||||
|
||||
if params['method'] == "POST" and request_args ~= nil then
|
||||
if C:is_ngx_match(rule[2],request_args,'post') then
|
||||
C:write_log('post','regular')
|
||||
C:return_html(config['other']['status'],other_html)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function url_tell()
|
||||
if site_config[server_name] == nil then return false end
|
||||
for _,rule in ipairs(site_config[server_name]['url_tell'])
|
||||
do
|
||||
if ngx_match(uri,rule[1],"isjo") then
|
||||
if uri_request_args[rule[2]] ~= rule[3] then
|
||||
C:write_log('url_tell','regular')
|
||||
C:return_html(config['other']['status'],other_html)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function disable_upload_ext(ext)
|
||||
local function disable_upload_ext(ext)
|
||||
if not ext then return false end
|
||||
ext = string.lower(ext)
|
||||
if is_key(site_config[server_name]['disable_upload_ext'],ext) then
|
||||
C:write_log('upload_ext','上传扩展名黑名单')
|
||||
local ext = string.lower(ext)
|
||||
if C:is_key(site_config[server_name]['disable_upload_ext'], ext) then
|
||||
C:write_log('upload_ext', '上传扩展名黑名单')
|
||||
C:return_html(config['other']['status'],other_html)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function data_in_php(data)
|
||||
if not data then
|
||||
return false
|
||||
else
|
||||
if C:is_ngx_match('php',data,'post') then
|
||||
C:write_log('upload_ext','上传扩展名黑名单')
|
||||
C:return_html(config['other']['status'],other_html)
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function post_data()
|
||||
local function post_data()
|
||||
if params["method"] ~= "POST" then return false end
|
||||
content_length = tonumber(params["request_header"]['content-length'])
|
||||
-- C:D("content-length:"..params["request_header"]['content-length'])
|
||||
local content_length = tonumber(params["request_header"]['content-length'])
|
||||
if not content_length then return false end
|
||||
max_len = 2560 * 1024000
|
||||
local max_len = 2560 * 1024000
|
||||
if content_length > max_len then return false end
|
||||
local boundary = C:get_boundary()
|
||||
-- C:D("boundary:".. tostring( boundary) )
|
||||
if boundary then
|
||||
ngx.req.read_body()
|
||||
local data = ngx.req.get_body_data()
|
||||
if not data then return false end
|
||||
local tmp = ngx.re.match(data,[[filename=\"(.+)\.(.*)\"]])
|
||||
if not tmp then return false end
|
||||
if not tmp[2] then return false end
|
||||
local tmp2=ngx.re.match(ngx.req.get_body_data(),[[Content-Type:[^\+]{45}]])
|
||||
--return return_message(200,tmp2[0])
|
||||
if not tmp or not tmp[2] then return false end
|
||||
-- C:D("upload_ext:".. tostring(tmp[2]) )
|
||||
disable_upload_ext(tmp[2])
|
||||
if tmp2 == nil then return false end
|
||||
data_in_php(tmp2[0])
|
||||
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function waf_cookie()
|
||||
local function waf_cookie()
|
||||
if not config['cookie']['open'] or not C:is_site_config('cookie') then return false end
|
||||
if not params["request_header"]['cookie'] then return false end
|
||||
if type(params["request_header"]['cookie']) ~= "string" then return false end
|
||||
@@ -575,18 +525,23 @@ function waf()
|
||||
-- white ip
|
||||
if waf_ip_white() then return true end
|
||||
|
||||
-- url white
|
||||
if waf_url_white() then return true end
|
||||
|
||||
-- black ip
|
||||
if waf_ip_black() then return true end
|
||||
|
||||
|
||||
-- cc setting
|
||||
if waf_drop() then return true end
|
||||
if waf_cc() then return true end
|
||||
-- 封禁ip返回
|
||||
if waf_drop_ip() then return true end
|
||||
|
||||
-- ua check
|
||||
if waf_user_agent() then return true end
|
||||
if waf_url() then return true end
|
||||
|
||||
-- cc setting
|
||||
if waf_cc_increase() then return true end
|
||||
if waf_cc() then return true end
|
||||
|
||||
-- cookie检查
|
||||
if waf_cookie() then return true end
|
||||
|
||||
@@ -597,16 +552,12 @@ function waf()
|
||||
if waf_scan_black() then return true end
|
||||
|
||||
if waf_post() then return true end
|
||||
if post_data_chekc() then return true end
|
||||
|
||||
if site_config[server_name]['open'] then
|
||||
if site_config[server_name] and site_config[server_name]['open'] then
|
||||
if X_Forwarded() then return true end
|
||||
if post_X_Forwarded() then return true end
|
||||
-- url_path()
|
||||
if url_ext() then return true end
|
||||
-- url_rule_ex()
|
||||
-- url_tell()
|
||||
-- post_data()
|
||||
if post_data() then return true end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
local json = require "cjson"
|
||||
|
||||
local waf_root = "{$WAF_ROOT}"
|
||||
local cpath = waf_root.."/waf/"
|
||||
|
||||
local __C = require "common"
|
||||
local C = __C:getInstance()
|
||||
|
||||
|
||||
local function timer_stats_total_log(premature)
|
||||
C:timer_stats_total()
|
||||
end
|
||||
|
||||
|
||||
ngx.shared.waf_limit:set("cpu_usage", 0, 10)
|
||||
function timer_every_get_cpu(premature)
|
||||
local cpu_percent = C:read_file_body(waf_root.."/cpu.info")
|
||||
if cpu_percent then
|
||||
ngx.shared.waf_limit:set("cpu_usage", tonumber(cpu_percent), 10)
|
||||
else
|
||||
ngx.shared.waf_limit:set("cpu_usage", 0, 10)
|
||||
end
|
||||
end
|
||||
|
||||
if 0 == ngx.worker.id() then
|
||||
ngx.timer.every(5, timer_every_get_cpu)
|
||||
|
||||
-- 异步执行
|
||||
ngx.timer.every(3, timer_stats_total_log)
|
||||
end
|
||||
@@ -1 +0,0 @@
|
||||
waf()
|
||||
@@ -1 +1 @@
|
||||
[[[127, 0, 0, 2], [127, 0, 0, 255]]]
|
||||
[[[127, 0, 0, 1], [127, 0, 0, 255]]]
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
[[1,"^/(phpmyadmin)","MySQL[phpMyAdmin]", 0]]
|
||||
@@ -1 +1 @@
|
||||
{"rules":{"url_ext":0,"user_agent":0,"scan":0,"cookie":0,"post":0,"args":0,"url":0,"cc":0},"sites":{},"total":0}
|
||||
{"rules":{"path":0,"php_path":0,"upload_ext":0,"user_agent":0,"scan":0,"cookie":0,"post":0,"args":0,"url":0,"cc":0},"sites":{},"total":0}
|
||||
@@ -1,24 +0,0 @@
|
||||
\.\./
|
||||
\:\$
|
||||
\$\{
|
||||
/\*|--
|
||||
\b(or|xor|and)\b.*(=|<|>|'|")
|
||||
select.+(from|limit)
|
||||
(?:(union(.*?)select))
|
||||
having|load_file
|
||||
sleep\((\s*)(\d*)(\s*)\)
|
||||
benchmark\((.*)\,(.*)\)
|
||||
base64_decode\(
|
||||
(?:from\W+information_schema\W)
|
||||
(?:(?:current_)user|database|schema|connection_id)\s*\(
|
||||
(?:etc\/\W*passwd)
|
||||
into(\s+)+(?:dump|out)file\s*
|
||||
group\s+by.+\(
|
||||
xwork.MethodAccessor
|
||||
(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\(
|
||||
xwork\.MethodAccessor
|
||||
(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/
|
||||
java\.lang
|
||||
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
|
||||
\<(iframe|script|body|img|layer|div|meta|style|base|object|input)
|
||||
(onmouseover|onerror|onload)\=
|
||||
@@ -1 +0,0 @@
|
||||
10.0.68.75
|
||||
@@ -1,20 +0,0 @@
|
||||
\.\./
|
||||
\:\$
|
||||
\$\{
|
||||
select.+(from|limit)
|
||||
(?:(union(.*?)select))
|
||||
having|rongjitest
|
||||
sleep\((\s*)(\d*)(\s*)\)
|
||||
benchmark\((.*)\,(.*)\)
|
||||
base64_decode\(
|
||||
(?:from\W+information_schema\W)
|
||||
(?:(?:current_)user|database|schema|connection_id)\s*\(
|
||||
(?:etc\/\W*passwd)
|
||||
into(\s+)+(?:dump|out)file\s*
|
||||
group\s+by.+\(
|
||||
xwork.MethodAccessor
|
||||
(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\(
|
||||
xwork\.MethodAccessor
|
||||
(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/
|
||||
java\.lang
|
||||
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
|
||||
@@ -1,7 +0,0 @@
|
||||
#ip 60/60 1800
|
||||
#ip+uri 60/60 1800
|
||||
#ip+domain+CookieParam:sessionid 60/60 1800
|
||||
#ip+GetParam:userid 60/60 1800
|
||||
#ip+PostParam:userid 60/60 1800
|
||||
#$ip+header:imei 30/60 1800
|
||||
ip+uri 60/60 3600
|
||||
@@ -1,18 +0,0 @@
|
||||
select.+(from|limit)
|
||||
(?:(union(.*?)select))
|
||||
\b(or|xor|and)\b.*(=|<|>|'|")
|
||||
having|load_file
|
||||
sleep\((\s*)(\d*)(\s*)\)
|
||||
benchmark\((.*)\,(.*)\)
|
||||
base64_decode\(
|
||||
(?:from\W+information_schema\W)
|
||||
into(\s+)+(?:dump|out)file\s*
|
||||
group\s+by.+\(
|
||||
xwork.MethodAccessor
|
||||
(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\(
|
||||
xwork\.MethodAccessor
|
||||
(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/
|
||||
java\.lang
|
||||
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
|
||||
\<(iframe|script|body|img|layer|div|meta|style|base|object|input)
|
||||
(onmouseover|onerror|onload)\=
|
||||
@@ -1,39 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>网站防火墙</title>
|
||||
<style>
|
||||
*{margin:0;padding:0;color:#444}
|
||||
body{font-size:14px;font-family:"宋体"}
|
||||
.main{width:600px;margin:10% auto;}
|
||||
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;padding-left: 20px;}
|
||||
.content{background-color:#f3f7f9; height:280px;border:1px dashed #c6d9b6;padding:20px}
|
||||
.t1{border-bottom: 1px dashed #c6d9b6;color: #ff4000;font-weight: bold; margin: 0 0 20px; padding-bottom: 18px;}
|
||||
.t2{margin-bottom:8px; font-weight:bold}
|
||||
ol{margin:0 0 20px 22px;padding:0;}
|
||||
ol li{line-height:30px}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="main">
|
||||
<div class="title">网站防火墙</div>
|
||||
<div class="content">
|
||||
<p class="t1">您的请求带有不合法参数,已被网站管理员设置拦截!</p>
|
||||
<p class="t2">可能原因:</p>
|
||||
<ol>
|
||||
<li>您提交的内容包含危险的攻击请求</li>
|
||||
</ol>
|
||||
<p class="t2">如何解决:</p>
|
||||
<ol>
|
||||
<li>检查提交内容;</li>
|
||||
<li>如网站托管,请联系空间提供商;</li>
|
||||
<li>普通网站访客,请联系网站管理员;</li>
|
||||
<li>这是误报,请联系网站管理员;</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
\.(svn|htaccess|mysql_history|bash_history|git|DS_Store|idea|user\.ini)
|
||||
\.(bak|inc|old|mdb|sh|sql|php~|swp|java|class)$
|
||||
(vhost|bbs|host|wwwroot|www|site|root|backup|data|ftp|db|admin|website|web).*\.(rar|sql|zip|tar\.gz|tar)
|
||||
(elastic|jmx-console|jmxinvokerservlet)
|
||||
java\.lang
|
||||
/CSV/
|
||||
/(hack|shell|spy|phpspy)\.php$
|
||||
(manager|host-manager)/html$
|
||||
/(attachments|upimg|images|css|uploadfiles|html|uploads|templets|static|template|data|forumdata|upload|includes|cache|avatar)/(\\w+).(php|jsp)
|
||||
@@ -1 +0,0 @@
|
||||
(HTTrack|Apache-HttpClient|harvest|audit|dirbuster|pangolin|nmap|sqln|hydra|Parser|libwww|BBBike|sqlmap|w3af|owasp|Nikto|fimap|havij|zmeu|BabyKrokodil|netsparker|httperf|bench| SF/)
|
||||
@@ -1,2 +0,0 @@
|
||||
127.0.0.1
|
||||
^192\.168\.
|
||||
@@ -1 +0,0 @@
|
||||
^/phpmyadmin_
|
||||
@@ -64,6 +64,7 @@ http
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name 127.0.0.1;
|
||||
allow 127.0.0.1;
|
||||
location /nginx_status {
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
<p class="bgw" onclick="orPluginService('openresty');">服务</p>
|
||||
<p onclick="pluginInitD('openresty');">自启动</p>
|
||||
<p onclick="pluginConfig('openresty');">配置修改</p>
|
||||
<p onclick="getOpenrestyStatus();">负载状态</p>
|
||||
<p onclick="getOpStatus();">负载状态</p>
|
||||
<p onclick="setOpCfg();">性能调整</p>
|
||||
<p onclick="pluginLogs('openresty');">错误日志</p>
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
@@ -14,9 +15,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
<!-- <script type="text/javascript" src="/plugins/file?name=openresty&f=js/openresty.js"></script> -->
|
||||
<script type="text/javascript">
|
||||
|
||||
$.getScript( "/plugins/file?name=openresty&f=js/openresty.js", function(){
|
||||
orPluginService('openresty');
|
||||
});
|
||||
|
||||
+121
-3
@@ -6,6 +6,7 @@ import os
|
||||
import time
|
||||
import threading
|
||||
import subprocess
|
||||
import re
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
@@ -52,6 +53,13 @@ def getArgs():
|
||||
return tmp
|
||||
|
||||
|
||||
def checkArgs(data, ck=[]):
|
||||
for i in range(len(ck)):
|
||||
if not ck[i] in data:
|
||||
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
|
||||
return (True, mw.returnJson(True, 'ok'))
|
||||
|
||||
|
||||
def clearTemp():
|
||||
path_bin = getServerDir() + "/nginx"
|
||||
mw.execShell('rm -rf ' + path_bin + '/client_body_temp')
|
||||
@@ -232,7 +240,7 @@ def restyOp_restart():
|
||||
check = getServerDir() + "/bin/openresty -t"
|
||||
check_data = mw.execShell(check)
|
||||
if not check_data[1].find('test is successful') > -1:
|
||||
return check_data[1]
|
||||
return 'ERROR: 配置出错<br><a style="color:red;">' + check_data[1].replace("\n", '<br>') + '</a>'
|
||||
|
||||
if not mw.isAppleSystem():
|
||||
threading.Timer(2, op_submit_systemctl_restart, args=()).start()
|
||||
@@ -291,7 +299,7 @@ def initdUinstall():
|
||||
def runInfo():
|
||||
# 取Openresty负载状态
|
||||
try:
|
||||
url = 'http://' + mw.getHostAddr() + '/nginx_status'
|
||||
url = 'http://127.0.0.1/nginx_status'
|
||||
result = mw.httpGet(url)
|
||||
tmp = result.split()
|
||||
data = {}
|
||||
@@ -304,7 +312,8 @@ def runInfo():
|
||||
data['Waiting'] = tmp[15]
|
||||
return mw.getJson(data)
|
||||
except Exception as e:
|
||||
url = 'http://127.0.0.1/nginx_status'
|
||||
|
||||
url = 'http://' + mw.getHostAddr() + '/nginx_status'
|
||||
result = mw.httpGet(url)
|
||||
tmp = result.split()
|
||||
data = {}
|
||||
@@ -324,6 +333,111 @@ def errorLogPath():
|
||||
return getServerDir() + '/nginx/logs/error.log'
|
||||
|
||||
|
||||
def getCfg():
|
||||
cfg = getConf()
|
||||
content = mw.readFile(cfg)
|
||||
|
||||
unitrep = "[kmgKMG]"
|
||||
cfg_args = [
|
||||
{"name": "worker_processes", "ps": "处理进程,auto表示自动,数字表示进程数", 'type': 2},
|
||||
{"name": "worker_connections", "ps": "最大并发链接数", 'type': 2},
|
||||
{"name": "keepalive_timeout", "ps": "连接超时时间", 'type': 2},
|
||||
{"name": "gzip", "ps": "是否开启压缩传输", 'type': 1},
|
||||
{"name": "gzip_min_length", "ps": "最小压缩文件", 'type': 2},
|
||||
{"name": "gzip_comp_level", "ps": "压缩率", 'type': 2},
|
||||
{"name": "client_max_body_size", "ps": "最大上传文件", 'type': 2},
|
||||
{"name": "server_names_hash_bucket_size",
|
||||
"ps": "服务器名字的hash表大小", 'type': 2},
|
||||
{"name": "client_header_buffer_size", "ps": "客户端请求头buffer大小", 'type': 2},
|
||||
]
|
||||
|
||||
# {"name": "client_body_buffer_size", "ps": "请求主体缓冲区"}
|
||||
rdata = []
|
||||
for i in cfg_args:
|
||||
rep = "(%s)\s+(\w+)" % i["name"]
|
||||
k = re.search(rep, content)
|
||||
if not k:
|
||||
return mw.returnJson(False, "获取 key {} 失败".format(k))
|
||||
k = k.group(1)
|
||||
v = re.search(rep, content)
|
||||
if not v:
|
||||
return mw.returnJson(False, "获取 value {} 失败".format(v))
|
||||
v = v.group(2)
|
||||
|
||||
if re.search(unitrep, v):
|
||||
u = str.upper(v[-1])
|
||||
v = v[:-1]
|
||||
if len(u) == 1:
|
||||
psstr = u + "B," + i["ps"]
|
||||
else:
|
||||
psstr = u + "," + i["ps"]
|
||||
else:
|
||||
u = ""
|
||||
|
||||
kv = {"name": k, "value": v, "unit": u,
|
||||
"ps": i["ps"], "type": i["type"]}
|
||||
rdata.append(kv)
|
||||
|
||||
return mw.returnJson(True, "ok", rdata)
|
||||
|
||||
|
||||
def setCfg():
|
||||
|
||||
args = getArgs()
|
||||
data = checkArgs(args, [
|
||||
'worker_processes', 'worker_connections', 'keepalive_timeout',
|
||||
'gzip', 'gzip_min_length', 'gzip_comp_level', 'client_max_body_size',
|
||||
'server_names_hash_bucket_size', 'client_header_buffer_size'
|
||||
])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
cfg = getConf()
|
||||
mw.backFile(cfg)
|
||||
content = mw.readFile(cfg)
|
||||
|
||||
unitrep = "[kmgKMG]"
|
||||
cfg_args = [
|
||||
{"name": "worker_processes", "ps": "处理进程,auto表示自动,数字表示进程数", 'type': 2},
|
||||
{"name": "worker_connections", "ps": "最大并发链接数", 'type': 2},
|
||||
{"name": "keepalive_timeout", "ps": "连接超时时间", 'type': 2},
|
||||
{"name": "gzip", "ps": "是否开启压缩传输", 'type': 1},
|
||||
{"name": "gzip_min_length", "ps": "最小压缩文件", 'type': 2},
|
||||
{"name": "gzip_comp_level", "ps": "压缩率", 'type': 2},
|
||||
{"name": "client_max_body_size", "ps": "最大上传文件", 'type': 2},
|
||||
{"name": "server_names_hash_bucket_size",
|
||||
"ps": "服务器名字的hash表大小", 'type': 2},
|
||||
{"name": "client_header_buffer_size", "ps": "客户端请求头buffer大小", 'type': 2},
|
||||
]
|
||||
|
||||
# print(args)
|
||||
for k, v in args.items():
|
||||
# print(k, v)
|
||||
rep = "%s\s+[^kKmMgG\;\n]+" % k
|
||||
if k == "worker_processes" or k == "gzip":
|
||||
if not re.search("auto|on|off|\d+", v):
|
||||
return mw.returnJson(False, '参数值错误')
|
||||
else:
|
||||
if not re.search("\d+", v):
|
||||
return mw.returnJson(False, '参数值错误,请输入数字整数')
|
||||
|
||||
if re.search(rep, content):
|
||||
newconf = "%s %s" % (k, v)
|
||||
content = re.sub(rep, newconf, content)
|
||||
elif re.search(rep, content):
|
||||
newconf = "%s %s" % (k, v)
|
||||
content = re.sub(rep, newconf, content)
|
||||
|
||||
mw.writeFile(cfg, content)
|
||||
isError = mw.checkWebConfig()
|
||||
if (isError != True):
|
||||
mw.restoreFile(cfg)
|
||||
return mw.returnJson(False, 'ERROR: 配置出错<br><a style="color:red;">' + isError.replace("\n", '<br>') + '</a>')
|
||||
|
||||
mw.restartWeb()
|
||||
return mw.returnJson(True, '设置成功')
|
||||
|
||||
|
||||
def installPreInspection():
|
||||
return 'ok'
|
||||
|
||||
@@ -356,5 +470,9 @@ if __name__ == "__main__":
|
||||
print(runInfo())
|
||||
elif func == 'error_log':
|
||||
print(errorLogPath())
|
||||
elif func == 'get_cfg':
|
||||
print(getCfg())
|
||||
elif func == 'set_cfg':
|
||||
print(setCfg())
|
||||
else:
|
||||
print('error')
|
||||
|
||||
@@ -59,11 +59,15 @@ Install_openresty()
|
||||
cd ${openrestyDir}/openresty-${VERSION} && ./configure \
|
||||
--prefix=$serverPath/openresty \
|
||||
--with-ipv6 \
|
||||
--with-stream \
|
||||
--with-http_v2_module \
|
||||
--with-http_ssl_module \
|
||||
--with-http_slice_module \
|
||||
--with-http_stub_status_module \
|
||||
--with-http_realip_module
|
||||
# --without-luajit-gc64
|
||||
# --with-debug
|
||||
# 用于调式
|
||||
|
||||
make -j${cpuCore} && make install && make clean
|
||||
|
||||
|
||||
@@ -111,8 +111,10 @@ function orPluginOpServiceOp(a,b,c,d,a,v,request_callback){
|
||||
|
||||
|
||||
//查看Nginx负载状态
|
||||
function getOpenrestyStatus() {
|
||||
function getOpStatus() {
|
||||
var loadT = layer.msg('正在处理,请稍后...', { icon: 16, time: 0, shade: 0.3 });
|
||||
$.post('/plugins/run', {name:'openresty', func:'run_info'}, function(data) {
|
||||
layer.close(loadT);
|
||||
if (!data.status){
|
||||
showMsg(data.msg, function(){}, null,3000);
|
||||
return;
|
||||
@@ -134,3 +136,78 @@ function getOpenrestyStatus() {
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
|
||||
|
||||
function setOpCfg(){
|
||||
orPost('get_cfg', {}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
var rdata = rdata.data;
|
||||
console.log(rdata);
|
||||
|
||||
var mlist = '';
|
||||
for (var i = 0; i < rdata.length; i++) {
|
||||
var w = '70'
|
||||
var ibody = '<input style="width: ' + w + 'px;" class="bt-input-text mr5" name="' + rdata[i].name + '" value="' + rdata[i].value + '" type="text" >';
|
||||
switch (rdata[i].type) {
|
||||
case 0:
|
||||
var selected_1 = (rdata[i].value == 1) ? 'selected' : '';
|
||||
var selected_0 = (rdata[i].value == 0) ? 'selected' : '';
|
||||
ibody = '<select class="bt-input-text mr5" name="' + rdata[i].name + '" style="width: ' + w + 'px;">\
|
||||
<option value="1" ' + selected_1 + '>开启</option>\
|
||||
<option value="0" ' + selected_0 + '>关闭</option>\
|
||||
</select>';
|
||||
break;
|
||||
case 1:
|
||||
var selected_1 = (rdata[i].value == 'on') ? 'selected' : '';
|
||||
var selected_0 = (rdata[i].value == 'off') ? 'selected' : '';
|
||||
ibody = '<select class="bt-input-text mr5" name="' + rdata[i].name + '" style="width: ' + w + 'px;">\
|
||||
<option value="on" ' + selected_1 + '>开启</option>\
|
||||
<option value="off" ' + selected_0 + '>关闭</option>\
|
||||
</select>';
|
||||
break;
|
||||
}
|
||||
mlist += '<p style="margin-top:15px;"><span>' + rdata[i].name + '</span>' + ibody + "<b class='unit c9'>"+rdata[i].unit+"</b>" +', <font class="c9">' + rdata[i].ps + '</font></p>';
|
||||
}
|
||||
var con = '<style>.conf_p p{margin-bottom: 2px}</style><div class="conf_p" style="margin-bottom:0">\
|
||||
' + mlist + '\
|
||||
<div style="margin-top:10px; padding-right:15px" class="text-right">\
|
||||
<button class="btn btn-success btn-sm mr5" onclick="setOpCfg()">刷新</button>\
|
||||
<button class="btn btn-success btn-sm" onclick="submitConf()">保存</button>\
|
||||
</div>\
|
||||
</div>'
|
||||
$(".soft-man-con").html(con);
|
||||
});
|
||||
}
|
||||
|
||||
function submitConf() {
|
||||
var data = {
|
||||
worker_processes: $("input[name='worker_processes']").val(),
|
||||
worker_connections: $("input[name='worker_connections']").val(),
|
||||
keepalive_timeout: $("input[name='keepalive_timeout']").val(),
|
||||
gzip: $("select[name='gzip']").val() || 'on',
|
||||
gzip_min_length: $("input[name='gzip_min_length']").val(),
|
||||
gzip_comp_level: $("input[name='gzip_comp_level']").val(),
|
||||
client_max_body_size: $("input[name='client_max_body_size']").val(),
|
||||
server_names_hash_bucket_size: $("input[name='server_names_hash_bucket_size']").val(),
|
||||
client_header_buffer_size: $("input[name='client_header_buffer_size']").val(),
|
||||
};
|
||||
|
||||
// console.log(data);
|
||||
orPost('set_cfg', data, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
console.log(rdata);
|
||||
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ group = {$PHP_GROUP}
|
||||
listen = /run/php/php{$PHP_VERSION}-fpm.sock
|
||||
listen.owner = {$PHP_USER}
|
||||
listen.group = {$PHP_GROUP}
|
||||
listen.backlog = 4096
|
||||
pm = dynamic
|
||||
pm.max_children = 50
|
||||
pm.start_servers = 5
|
||||
|
||||
@@ -537,7 +537,7 @@ def setSessionConf(version):
|
||||
passwd = args['passwd']
|
||||
save_handler = args['save_handler']
|
||||
|
||||
if save_handler != "file":
|
||||
if save_handler != "files":
|
||||
iprep = r"(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})"
|
||||
if not re.search(iprep, ip):
|
||||
return mw.returnJson(False, '请输入正确的IP地址')
|
||||
@@ -605,7 +605,7 @@ def setSessionConf(version):
|
||||
phpini = re.sub('\n;session.save_path = "' + "/var/lib/php/sessions" + '"',
|
||||
'\n;session.save_path = "' + "/var/lib/php/sessions" + '"' + val, phpini)
|
||||
|
||||
if save_handler == "file":
|
||||
if save_handler == "files":
|
||||
rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
|
||||
val = r'\nsession.save_path = "' + session_tmp + '"\n'
|
||||
if re.search(rep, phpini):
|
||||
|
||||
@@ -380,7 +380,7 @@ function getSessionConfig(version){
|
||||
}
|
||||
var rdata = rdata.data;
|
||||
|
||||
var cacheList = "<option value='file' " + (rdata.save_handler == "file" ? 'selected' : '') + ">file</option>" +
|
||||
var cacheList = "<option value='files' " + (rdata.save_handler == "files" ? 'selected' : '') + ">files</option>" +
|
||||
"<option value='redis' " + (rdata.save_handler == "redis" ? 'selected' : '') + ">redis</option>" +
|
||||
"<option value='memcache' " + (rdata.save_handler == "memcache" ? 'selected' : '') + ">memcache</option>" +
|
||||
"<option value='memcached' " + (rdata.save_handler == "memcached" ? 'selected' : '') + ">memcached</option>";
|
||||
@@ -405,7 +405,7 @@ function getSessionConfig(version){
|
||||
|
||||
$(".soft-man-con").html(con);
|
||||
|
||||
if (rdata.save_handler == 'file'){
|
||||
if (rdata.save_handler == 'files'){
|
||||
$('input[name="ip"]').attr('disabled','disabled');
|
||||
$('input[name="port"]').attr('disabled','disabled');
|
||||
$('input[name="passwd"]').attr('placeholder','如果没有密码留空');
|
||||
@@ -436,7 +436,7 @@ function getSessionConfig(version){
|
||||
$('input[name="port"]').removeAttr('disabled');
|
||||
$('input[name="passwd"]').removeAttr('disabled');
|
||||
break;
|
||||
case 'file':
|
||||
case 'files':
|
||||
$('input[name="ip"]').val("").attr('disabled','disabled');
|
||||
$('input[name="port"]').val("").attr('disabled','disabled');
|
||||
$('input[name="passwd"]').val("").attr('disabled','disabled');
|
||||
|
||||
@@ -5,6 +5,8 @@ group = {$PHP_GROUP}
|
||||
listen = /var/opt/remi/php{$PHP_VERSION}/run/php-fpm/www.sock
|
||||
listen.owner = {$PHP_USER}
|
||||
listen.group = {$PHP_GROUP}
|
||||
listen.backlog = 4096
|
||||
|
||||
pm = dynamic
|
||||
pm.max_children = 50
|
||||
pm.start_servers = 5
|
||||
|
||||
@@ -539,7 +539,7 @@ def setSessionConf(version):
|
||||
passwd = args['passwd']
|
||||
save_handler = args['save_handler']
|
||||
|
||||
if save_handler != "file":
|
||||
if save_handler != "files":
|
||||
iprep = r"(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})"
|
||||
if not re.search(iprep, ip):
|
||||
return mw.returnJson(False, '请输入正确的IP地址')
|
||||
@@ -607,7 +607,7 @@ def setSessionConf(version):
|
||||
phpini = re.sub('\n;session.save_path = "/tmp"',
|
||||
'\n;session.save_path = "/tmp"' + val, phpini)
|
||||
|
||||
if save_handler == "file":
|
||||
if save_handler == "files":
|
||||
rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
|
||||
val = r'\nsession.save_path = "' + session_tmp + '"\n'
|
||||
if re.search(rep, phpini):
|
||||
|
||||
@@ -349,7 +349,7 @@ function getSessionConfig(version){
|
||||
}
|
||||
var rdata = rdata.data;
|
||||
|
||||
var cacheList = "<option value='file' " + (rdata.save_handler == "file" ? 'selected' : '') + ">file</option>" +
|
||||
var cacheList = "<option value='files' " + (rdata.save_handler == "files" ? 'selected' : '') + ">files</option>" +
|
||||
"<option value='redis' " + (rdata.save_handler == "redis" ? 'selected' : '') + ">redis</option>" +
|
||||
"<option value='memcache' " + (rdata.save_handler == "memcache" ? 'selected' : '') + ">memcache</option>" +
|
||||
"<option value='memcached' " + (rdata.save_handler == "memcached" ? 'selected' : '') + ">memcached</option>";
|
||||
@@ -374,7 +374,7 @@ function getSessionConfig(version){
|
||||
|
||||
$(".soft-man-con").html(con);
|
||||
|
||||
if (rdata.save_handler == 'file'){
|
||||
if (rdata.save_handler == 'files'){
|
||||
$('input[name="ip"]').attr('disabled','disabled');
|
||||
$('input[name="port"]').attr('disabled','disabled');
|
||||
$('input[name="passwd"]').attr('placeholder','如果没有密码留空');
|
||||
@@ -405,7 +405,7 @@ function getSessionConfig(version){
|
||||
$('input[name="port"]').removeAttr('disabled');
|
||||
$('input[name="passwd"]').removeAttr('disabled');
|
||||
break;
|
||||
case 'file':
|
||||
case 'files':
|
||||
$('input[name="ip"]').val("").attr('disabled','disabled');
|
||||
$('input[name="port"]').val("").attr('disabled','disabled');
|
||||
$('input[name="passwd"]').val("").attr('disabled','disabled');
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
[www]
|
||||
user = {$PHP_USER}
|
||||
group = {$PHP_GROUP}
|
||||
|
||||
listen = /tmp/php-cgi-{$PHP_VERSION}.sock
|
||||
listen.owner = {$PHP_USER}
|
||||
listen.group = {$PHP_GROUP}
|
||||
listen.backlog = 4096
|
||||
|
||||
pm = dynamic
|
||||
pm.max_children = 50
|
||||
pm.start_servers = 5
|
||||
|
||||
@@ -679,7 +679,7 @@ def setSessionConf(version):
|
||||
passwd = args['passwd']
|
||||
save_handler = args['save_handler']
|
||||
|
||||
if save_handler != "file":
|
||||
if save_handler != "files":
|
||||
iprep = r"(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})"
|
||||
if not re.search(iprep, ip):
|
||||
return mw.returnJson(False, '请输入正确的IP地址')
|
||||
@@ -743,7 +743,7 @@ def setSessionConf(version):
|
||||
phpini = re.sub('\n;session.save_path = "' + session_tmp + '"',
|
||||
'\n;session.save_path = "' + session_tmp + '"' + val, phpini)
|
||||
|
||||
if save_handler == "file":
|
||||
if save_handler == "files":
|
||||
rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
|
||||
val = r'\nsession.save_path = "' + session_tmp + '"\n'
|
||||
if re.search(rep, phpini):
|
||||
|
||||
@@ -81,7 +81,10 @@ function phpSetConfig(version) {
|
||||
}
|
||||
var phpCon = '<style>.conf_p p{margin-bottom: 2px}</style><div class="conf_p" style="margin-bottom:0">\
|
||||
' + mlist + '\
|
||||
<div style="margin-top:10px; padding-right:15px" class="text-right"><button class="btn btn-success btn-sm mr5" onclick="phpSetConfig(' + version + ')">刷新</button><button class="btn btn-success btn-sm" onclick="submitConf(' + version + ')">保存</button></div>\
|
||||
<div style="margin-top:10px; padding-right:15px" class="text-right">\
|
||||
<button class="btn btn-success btn-sm mr5" onclick="phpSetConfig(' + version + ')">刷新</button>\
|
||||
<button class="btn btn-success btn-sm" onclick="submitConf(' + version + ')">保存</button>\
|
||||
</div>\
|
||||
</div>'
|
||||
$(".soft-man-con").html(phpCon);
|
||||
});
|
||||
@@ -339,7 +342,7 @@ function getSessionConfig(version){
|
||||
}
|
||||
var rdata = rdata.data;
|
||||
|
||||
var cacheList = "<option value='file' " + (rdata.save_handler == "file" ? 'selected' : '') + ">file</option>" +
|
||||
var cacheList = "<option value='files' " + (rdata.save_handler == "files" ? 'selected' : '') + ">files</option>" +
|
||||
"<option value='redis' " + (rdata.save_handler == "redis" ? 'selected' : '') + ">redis</option>" +
|
||||
"<option value='memcache' " + (rdata.save_handler == "memcache" ? 'selected' : '') + ">memcache</option>" +
|
||||
"<option value='memcached' " + (rdata.save_handler == "memcached" ? 'selected' : '') + ">memcached</option>";
|
||||
@@ -364,7 +367,7 @@ function getSessionConfig(version){
|
||||
|
||||
$(".soft-man-con").html(con);
|
||||
|
||||
if (rdata.save_handler == 'file'){
|
||||
if (rdata.save_handler == 'files'){
|
||||
$('input[name="ip"]').attr('disabled','disabled');
|
||||
$('input[name="port"]').attr('disabled','disabled');
|
||||
$('input[name="passwd"]').attr('placeholder','如果没有密码留空');
|
||||
@@ -395,7 +398,7 @@ function getSessionConfig(version){
|
||||
$('input[name="port"]').removeAttr('disabled');
|
||||
$('input[name="passwd"]').removeAttr('disabled');
|
||||
break;
|
||||
case 'file':
|
||||
case 'files':
|
||||
$('input[name="ip"]').val("").attr('disabled','disabled');
|
||||
$('input[name="port"]').val("").attr('disabled','disabled');
|
||||
$('input[name="passwd"]').val("").attr('disabled','disabled');
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$.getScript( "/plugins/file?name=phpmyadmin&f=js/phpmyadmin.js");
|
||||
pluginService('phpmyadmin');
|
||||
$.getScript( "/plugins/file?name=phpmyadmin&f=js/phpmyadmin.js", function(){
|
||||
pluginService('phpmyadmin');
|
||||
});
|
||||
</script>
|
||||
@@ -57,7 +57,7 @@ def getConf():
|
||||
|
||||
|
||||
def getConfInc():
|
||||
return getServerDir() + '/phpmyadmin/config.inc.php'
|
||||
return getServerDir() + "/" + getCfg()['path'] + '/config.inc.php'
|
||||
|
||||
|
||||
def getPort():
|
||||
@@ -74,7 +74,8 @@ def getHomePage():
|
||||
ip = '127.0.0.1'
|
||||
if not mw.isAppleSystem():
|
||||
ip = mw.getLocalIp()
|
||||
url = 'http://' + ip + ':' + port + '/phpmyadmin/index.php'
|
||||
url = 'http://' + ip + ':' + port + \
|
||||
'/' + getCfg()['path'] + '/index.php'
|
||||
return mw.returnJson(True, 'OK', url)
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, '插件未启动!')
|
||||
@@ -124,6 +125,12 @@ def contentReplace(content):
|
||||
content = content.replace('{$CHOOSE_DB}', 'MariaDB')
|
||||
content = content.replace('{$CHOOSE_DB_DIR}', 'mariadb')
|
||||
|
||||
content = content.replace('{$PMA_PATH}', cfg['path'])
|
||||
|
||||
port = cfg["port"]
|
||||
rep = 'listen\s*(.*);'
|
||||
content = re.sub(rep, "listen " + port + ';', content)
|
||||
|
||||
return content
|
||||
|
||||
|
||||
@@ -133,6 +140,7 @@ def initCfg():
|
||||
data = {}
|
||||
data['port'] = '888'
|
||||
data['choose'] = ''
|
||||
data['path'] = ''
|
||||
data['username'] = 'admin'
|
||||
data['password'] = 'admin'
|
||||
mw.writeFile(cfg, json.dumps(data))
|
||||
@@ -161,7 +169,7 @@ def returnCfg():
|
||||
|
||||
def status():
|
||||
conf = getConf()
|
||||
conf_inc = getServerDir() + '/phpmyadmin/config.inc.php'
|
||||
conf_inc = getServerDir() + "/" + getCfg()["path"] + '/config.inc.php'
|
||||
# 两个文件都在,才算启动成功
|
||||
if os.path.exists(conf) and os.path.exists(conf_inc):
|
||||
return 'start'
|
||||
@@ -171,9 +179,16 @@ def status():
|
||||
def start():
|
||||
initCfg()
|
||||
|
||||
pma_dir = getServerDir() + "/phpmyadmin"
|
||||
if os.path.exists(pma_dir):
|
||||
rand_str = mw.getRandomString(6)
|
||||
rand_str = rand_str.lower()
|
||||
pma_dir_dst = pma_dir + "_" + rand_str
|
||||
mw.execShell("mv " + pma_dir + " " + pma_dir_dst)
|
||||
setCfg('path', 'phpmyadmin_' + rand_str)
|
||||
|
||||
file_tpl = getPluginDir() + '/conf/phpmyadmin.conf'
|
||||
file_run = getConf()
|
||||
|
||||
if not os.path.exists(file_run):
|
||||
centent = mw.readFile(file_tpl)
|
||||
centent = contentReplace(centent)
|
||||
@@ -187,11 +202,12 @@ def start():
|
||||
setCfg('password', username)
|
||||
mw.writeFile(pma_path, pass_cmd)
|
||||
|
||||
tmp = getServerDir() + '/phpmyadmin/tmp'
|
||||
tmp = getServerDir() + "/" + getCfg()["path"] + '/tmp'
|
||||
if not os.path.exists(tmp):
|
||||
os.mkdir(tmp)
|
||||
mw.execShell("chown -R www:www " + tmp)
|
||||
|
||||
conf_run = getServerDir() + '/phpmyadmin/config.inc.php'
|
||||
conf_run = getServerDir() + "/" + getCfg()["path"] + '/config.inc.php'
|
||||
if not os.path.exists(conf_run):
|
||||
conf_tpl = getPluginDir() + '/conf/config.inc.php'
|
||||
centent = mw.readFile(conf_tpl)
|
||||
@@ -223,6 +239,12 @@ def restart():
|
||||
|
||||
|
||||
def reload():
|
||||
file_tpl = getPluginDir() + '/conf/phpmyadmin.conf'
|
||||
file_run = getConf()
|
||||
if os.path.exists(file_run):
|
||||
centent = mw.readFile(file_tpl)
|
||||
centent = contentReplace(centent)
|
||||
mw.writeFile(file_run, centent)
|
||||
return start()
|
||||
|
||||
|
||||
@@ -284,6 +306,8 @@ def setPmaPort():
|
||||
rep = 'listen\s*(.*);'
|
||||
content = re.sub(rep, "listen " + port + ';', content)
|
||||
mw.writeFile(file, content)
|
||||
|
||||
setCfg("port", port)
|
||||
mw.restartWeb()
|
||||
return mw.returnJson(True, '修改成功!')
|
||||
|
||||
@@ -345,6 +369,25 @@ def setPmaPassword():
|
||||
return mw.returnJson(True, '修改成功!')
|
||||
|
||||
|
||||
def setPmaPath():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['path'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
path = args['path']
|
||||
|
||||
if len(path) < 5:
|
||||
return mw.returnJson(False, '不能小于5位!')
|
||||
|
||||
old_path = getServerDir() + "/" + getCfg()['path']
|
||||
new_path = getServerDir() + "/" + path
|
||||
|
||||
mw.execShell("mv " + old_path + " " + new_path)
|
||||
setCfg('path', path)
|
||||
return mw.returnJson(True, '修改成功!')
|
||||
|
||||
|
||||
def accessLog():
|
||||
return getServerDir() + '/access.log'
|
||||
|
||||
@@ -395,6 +438,8 @@ if __name__ == "__main__":
|
||||
print(setPmaUsername())
|
||||
elif func == 'set_pma_password':
|
||||
print(setPmaPassword())
|
||||
elif func == 'set_pma_path':
|
||||
print(setPmaPath())
|
||||
elif func == 'access_log':
|
||||
print(accessLog())
|
||||
elif func == 'error_log':
|
||||
|
||||
@@ -10,10 +10,20 @@ serverPath=$(dirname "$rootPath")
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
|
||||
|
||||
if [ -f ${rootPath}/bin/activate ];then
|
||||
source ${rootPath}/bin/activate
|
||||
fi
|
||||
|
||||
if [ "$sys_os" == "Darwin" ];then
|
||||
BAK='_bak'
|
||||
else
|
||||
BAK=''
|
||||
fi
|
||||
|
||||
sysName=`uname`
|
||||
echo "use system: ${sysName}"
|
||||
|
||||
if [ ${sysName} == "Darwin" ]; then
|
||||
if [ "${sysName}" == "Darwin" ]; then
|
||||
OSNAME='macos'
|
||||
elif grep -Eqi "CentOS" /etc/issue || grep -Eq "CentOS" /etc/*-release; then
|
||||
OSNAME='centos'
|
||||
@@ -51,13 +61,7 @@ Install_phpmyadmin()
|
||||
|
||||
cp -r $serverPath/source/phpmyadmin/$FDIR $serverPath/phpmyadmin/
|
||||
cd $serverPath/phpmyadmin/ && mv $FDIR phpmyadmin
|
||||
|
||||
mkdir -p $serverPath/phpmyadmin/tmp
|
||||
chown -R www:www $serverPath/phpmyadmin/tmp
|
||||
|
||||
if [ "$OSNAME" != 'macos' ];then
|
||||
chown -R www:www $serverPath/phpmyadmin/tmp
|
||||
fi
|
||||
|
||||
echo "${1}" > ${serverPath}/phpmyadmin/version.pl
|
||||
echo '安装完成' > $install_tmp
|
||||
|
||||
@@ -120,6 +120,12 @@ function safeConf() {
|
||||
<span class="tname">密码</span>\
|
||||
<input style="width:110px" class="bt-input-text mr20" name="password" id="pmport" value="' + cfg['password'] + '" placeholder="密码" type="text">\
|
||||
<button class="btn btn-success btn-sm" onclick="setPmaPassword()">保存</button>\
|
||||
</div>\
|
||||
<hr/>\
|
||||
<div class="ver line">\
|
||||
<span class="tname">路径名</span>\
|
||||
<input style="width:180px" class="bt-input-text mr20" name="path" id="pmport" value="' + cfg['path'] + '" placeholder="" type="text">\
|
||||
<button class="btn btn-success btn-sm" onclick="setPmaPath()">保存</button>\
|
||||
</div>';
|
||||
$(".soft-man-con").html(con);
|
||||
});
|
||||
@@ -150,6 +156,14 @@ function setPmaPassword(){
|
||||
});
|
||||
}
|
||||
|
||||
function setPmaPath(){
|
||||
var path = $("input[name=path]").val();
|
||||
pmaPost('set_pma_path',{'path':path}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
|
||||
});
|
||||
}
|
||||
|
||||
//修改phpmyadmin端口
|
||||
function setPamPort() {
|
||||
var pmport = $("#pmport").val();
|
||||
|
||||
@@ -25,5 +25,8 @@ AutoRename no
|
||||
AnonymousCantUpload no
|
||||
MaxDiskUsage 99
|
||||
CustomerProof yes
|
||||
PIDFile /var/run/pure-ftpd.pid
|
||||
PassivePortRange 48000 50000
|
||||
PIDFile {$SERVER_PATH}/pureftp/etc/pure-ftpd.pid
|
||||
PureDB {$SERVER_PATH}/pureftp/etc/pureftpd.pdb
|
||||
|
||||
VerboseLog yes
|
||||
@@ -110,8 +110,9 @@ def initDreplace():
|
||||
pureFtpdConfigBak = getServerDir() + "/etc/pure-ftpd.bak.conf"
|
||||
pureFtpdConfigTpl = getPluginDir() + "/conf/pure-ftpd.conf"
|
||||
|
||||
if not os.path.exists(pureFtpdConfigBak):
|
||||
shutil.copyfile(pureFtpdConfig, pureFtpdConfigBak)
|
||||
if not os.path.exists(pureFtpdConfigBak) or not os.path.exists(pureFtpdConfig):
|
||||
if os.path.exists(pureFtpdConfig):
|
||||
shutil.copyfile(pureFtpdConfig, pureFtpdConfigBak)
|
||||
content = mw.readFile(pureFtpdConfigTpl)
|
||||
content = contentReplace(content)
|
||||
mw.writeFile(pureFtpdConfig, content)
|
||||
|
||||
@@ -10,7 +10,7 @@ my ($conffile, @flg) = @ARGV;
|
||||
my $PUREFTPD;
|
||||
-x && ($PUREFTPD=$_, last) for qw(
|
||||
{$SERVER_PATH}/pureftp/sbin/pure-ftpd
|
||||
/www/server/pure-ftpd/sbin/pure-ftpd
|
||||
/www/server/pureftp/sbin/pure-ftpd
|
||||
/www/server/pureftpd/sbin/pure-ftpd
|
||||
/www/server/sbin/pure-ftpd
|
||||
/usr/sbin/pure-ftpd
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# Pure-FTPd Settings
|
||||
PURE_PERL="{$SERVER_PATH}/pureftp/sbin/pure-config.pl"
|
||||
PURE_CONF="{$SERVER_PATH}/pureftp/etc/pure-ftpd.conf"
|
||||
PURE_PID="/var/run/pure-ftpd.pid"
|
||||
PURE_PID="{$SERVER_PATH}/pureftp/etc/pure-ftpd.pid"
|
||||
RETVAL=0
|
||||
prog="Pure-FTPd"
|
||||
|
||||
|
||||
@@ -53,8 +53,8 @@ Install_pureftp()
|
||||
|
||||
# curl -sSLo pure-ftpd-1.0.49.tar.gz https://download.pureftpd.org/pub/pure-ftpd/releases/pure-ftpd-1.0.49.tar.gz
|
||||
if [ ! -f $serverPath/source/pureftp/pure-ftpd-${VER}.tar.gz ];then
|
||||
# wget --no-check-certificate -O $serverPath/source/pureftp/pure-ftpd-${VER}.tar.gz $DOWNLOAD
|
||||
curl -sSLo $serverPath/source/pureftp/pure-ftpd-${VER}.tar.gz $DOWNLOAD
|
||||
wget --no-check-certificate -O $serverPath/source/pureftp/pure-ftpd-${VER}.tar.gz $DOWNLOAD
|
||||
# curl -sSLo $serverPath/source/pureftp/pure-ftpd-${VER}.tar.gz $DOWNLOAD
|
||||
fi
|
||||
|
||||
#检测文件是否损坏.
|
||||
@@ -66,7 +66,8 @@ Install_pureftp()
|
||||
else
|
||||
# 重新下载
|
||||
rm -rf $serverPath/source/pureftp/pure-ftpd-${VER}
|
||||
curl -sSLo $serverPath/source/pureftp/pure-ftpd-${VER}.tar.gz $DOWNLOAD
|
||||
wget --no-check-certificate -O $serverPath/source/pureftp/pure-ftpd-${VER}.tar.gz $DOWNLOAD
|
||||
# curl -sSLo $serverPath/source/pureftp/pure-ftpd-${VER}.tar.gz $DOWNLOAD
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -75,7 +76,24 @@ Install_pureftp()
|
||||
fi
|
||||
|
||||
cd $serverPath/source/pureftp/pure-ftpd-${VER} && ./configure --prefix=${serverPath}/pureftp \
|
||||
--with-everything && make && make install && make clean
|
||||
CFLAGS=-O2 \
|
||||
--with-puredb \
|
||||
--with-quotas \
|
||||
--with-cookie \
|
||||
--with-virtualhosts \
|
||||
--with-diraliases \
|
||||
--with-sysquotas \
|
||||
--with-ratios \
|
||||
--with-altlog \
|
||||
--with-paranoidmsg \
|
||||
--with-shadow \
|
||||
--with-welcomemsg \
|
||||
--with-throttling \
|
||||
--with-uploadscript \
|
||||
--with-language=english \
|
||||
--with-rfc2640 \
|
||||
--with-ftpwho \
|
||||
--with-tls && make && make install && make clean
|
||||
|
||||
if [ -d ${serverPath}/pureftp ];then
|
||||
echo "${1}" > ${serverPath}/pureftp/version.pl
|
||||
|
||||
@@ -1,18 +1,8 @@
|
||||
function str2Obj(str){
|
||||
var data = {};
|
||||
kv = str.split('&');
|
||||
for(i in kv){
|
||||
v = kv[i].split('=');
|
||||
data[v[0]] = v[1];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function ftpPost(method,args,callback){
|
||||
|
||||
var _args = null;
|
||||
if (typeof(args) == 'string'){
|
||||
_args = JSON.stringify(str2Obj(args));
|
||||
_args = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
_args = JSON.stringify(args);
|
||||
}
|
||||
|
||||
@@ -1,18 +1,35 @@
|
||||
net.core.default_qdisc = fq
|
||||
net.ipv4.tcp_congestion_control = bbr
|
||||
net.ipv4.icmp_echo_ignore_all=0
|
||||
|
||||
net.ipv4.tcp_fin_timeout = 6
|
||||
net.ipv4.tcp_keepalive_time = 30
|
||||
net.ipv4.tcp_max_tw_buckets = 8000
|
||||
net.ipv4.tcp_tw_reuse = 1
|
||||
net.ipv4.tcp_tw_recycle = 1
|
||||
net.ipv4.ip_forward = 0
|
||||
net.ipv4.conf.default.rp_filter = 1
|
||||
net.ipv4.conf.default.accept_source_route = 0
|
||||
kernel.sysrq = 0
|
||||
kernel.core_uses_pid = 1
|
||||
net.ipv4.tcp_syncookies = 1
|
||||
net.ipv4.tcp_max_syn_backlog = 30000
|
||||
net.ipv4.tcp_syn_retries = 2
|
||||
net.ipv4.tcp_synack_retries = 2
|
||||
net.ipv4.ip_local_port_range = 1025 61000
|
||||
net.ipv4.tcp_keepalive_intvl = 3
|
||||
net.ipv4.tcp_keepalive_probes = 2
|
||||
kernel.msgmnb = 65536
|
||||
kernel.msgmax = 65536
|
||||
kernel.shmmax = 68719476736
|
||||
kernel.shmall = 4294967296
|
||||
net.ipv4.tcp_max_tw_buckets = 6000
|
||||
net.ipv4.tcp_sack = 1
|
||||
net.ipv4.tcp_window_scaling = 1
|
||||
net.ipv4.tcp_rmem = 4096 87380 4194304
|
||||
net.ipv4.tcp_wmem = 4096 16384 4194304
|
||||
net.core.wmem_default = 8388608
|
||||
net.core.rmem_default = 8388608
|
||||
net.core.rmem_max = 16777216
|
||||
net.core.wmem_max = 16777216
|
||||
net.core.netdev_max_backlog = 262144
|
||||
net.core.somaxconn = 262144
|
||||
net.ipv4.tcp_max_orphans = 3276800
|
||||
net.ipv4.tcp_max_syn_backlog = 262144
|
||||
net.ipv4.tcp_timestamps = 0
|
||||
net.ipv4.tcp_synack_retries = 1
|
||||
net.ipv4.tcp_syn_retries = 1
|
||||
net.ipv4.tcp_tw_recycle = 1
|
||||
net.ipv4.tcp_tw_reuse = 1
|
||||
net.ipv4.tcp_mem = 94500000 915000000 927000000
|
||||
net.ipv4.tcp_fin_timeout = 1
|
||||
net.ipv4.tcp_keepalive_time = 30
|
||||
net.ipv4.ip_local_port_range = 1024 65000
|
||||
|
||||
vm.overcommit_memory=1
|
||||
@@ -1,2 +1,2 @@
|
||||
lua_shared_dict mw_total 50m;
|
||||
lua_shared_dict mw_total 100m;
|
||||
include {$SERVER_APP}/lua/webstats_log.lua;
|
||||
+35
-15
@@ -77,11 +77,11 @@ def status():
|
||||
return 'start'
|
||||
|
||||
|
||||
def loadLuaLogFile():
|
||||
def loadLuaFile(name):
|
||||
lua_dir = getServerDir() + "/lua"
|
||||
lua_dst = lua_dir + "/webstats_log.lua"
|
||||
lua_dst = lua_dir + "/" + name
|
||||
|
||||
lua_tpl = getPluginDir() + '/lua/webstats_log.lua'
|
||||
lua_tpl = getPluginDir() + '/lua/' + name
|
||||
content = mw.readFile(lua_tpl)
|
||||
content = content.replace('{$SERVER_APP}', getServerDir())
|
||||
content = content.replace('{$ROOT_PATH}', mw.getServerDir())
|
||||
@@ -98,7 +98,7 @@ def loadConfigFile():
|
||||
dst_conf_json = getServerDir() + "/lua/config.json"
|
||||
mw.writeFile(dst_conf_json, json.dumps(content))
|
||||
|
||||
dst_conf_lua = getServerDir() + "/lua/config.lua"
|
||||
dst_conf_lua = getServerDir() + "/lua/webstats_config.lua"
|
||||
listToLuaFile(dst_conf_lua, content)
|
||||
|
||||
|
||||
@@ -125,9 +125,16 @@ def loadLuaSiteFile():
|
||||
ddata["default"] = "unset"
|
||||
else:
|
||||
ddata["default"] = dlist[0]
|
||||
|
||||
mw.writeFile(default_json, json.dumps(ddata))
|
||||
|
||||
lua_site = lua_dir + "/sites.lua"
|
||||
lua_site = lua_dir + "/webstats_sites.lua"
|
||||
|
||||
tmp = {
|
||||
"name": "unset",
|
||||
"domains": [],
|
||||
}
|
||||
content.append(tmp)
|
||||
listToLuaFile(lua_site, content)
|
||||
|
||||
|
||||
@@ -205,7 +212,14 @@ def initDreplace():
|
||||
if not os.path.exists(log_path):
|
||||
mw.execShell('mkdir -p ' + log_path)
|
||||
|
||||
loadLuaLogFile()
|
||||
file_list = [
|
||||
'webstats_common.lua',
|
||||
'webstats_log.lua',
|
||||
]
|
||||
|
||||
for fl in file_list:
|
||||
loadLuaFile(fl)
|
||||
|
||||
loadConfigFile()
|
||||
loadLuaSiteFile()
|
||||
loadDebugLogFile()
|
||||
@@ -222,28 +236,35 @@ def start():
|
||||
if not mw.isAppleSystem():
|
||||
mw.execShell("chown -R www:www " + getServerDir())
|
||||
|
||||
mw.restartWeb()
|
||||
mw.opWeb("reload")
|
||||
return 'ok'
|
||||
|
||||
|
||||
def stop():
|
||||
path = luaConf()
|
||||
os.remove(path)
|
||||
mw.restartWeb()
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
|
||||
import tool_task
|
||||
tool_task.removeBgTask()
|
||||
|
||||
mw.opWeb("restart")
|
||||
return 'ok'
|
||||
|
||||
|
||||
def restart():
|
||||
initDreplace()
|
||||
|
||||
mw.opWeb("reload")
|
||||
return 'ok'
|
||||
|
||||
|
||||
def reload():
|
||||
initDreplace()
|
||||
|
||||
loadLuaLogFile()
|
||||
loadDebugLogFile()
|
||||
mw.restartWeb()
|
||||
|
||||
mw.opWeb("reload")
|
||||
return 'ok'
|
||||
|
||||
|
||||
@@ -294,7 +315,7 @@ def setGlobalConf():
|
||||
content['global']['exclude_url'] = exclude_url_val
|
||||
|
||||
mw.writeFile(conf, json.dumps(content))
|
||||
conf_lua = getServerDir() + "/lua/config.lua"
|
||||
conf_lua = getServerDir() + "/lua/webstats_config.lua"
|
||||
listToLuaFile(conf_lua, content)
|
||||
mw.restartWeb()
|
||||
return mw.returnJson(True, '设置成功')
|
||||
@@ -387,7 +408,7 @@ def setSiteConf():
|
||||
content[domain] = site_conf
|
||||
|
||||
mw.writeFile(conf, json.dumps(content))
|
||||
conf_lua = getServerDir() + "/lua/config.lua"
|
||||
conf_lua = getServerDir() + "/lua/webstats_config.lua"
|
||||
listToLuaFile(conf_lua, content)
|
||||
mw.restartWeb()
|
||||
return mw.returnJson(True, '设置成功')
|
||||
@@ -622,7 +643,7 @@ def getLogsList():
|
||||
limit = str(page_size) + ' offset ' + str(page_size * (page - 1))
|
||||
conn = pSqliteDb('web_logs', domain)
|
||||
|
||||
field = 'time,ip,domain,server_name,method,protocol,status_code,request_headers,ip_list,client_port,body_length,user_agent,referer,request_time,uri,body_length'
|
||||
field = 'time,ip,domain,server_name,method,is_spider,protocol,status_code,request_headers,ip_list,client_port,body_length,user_agent,referer,request_time,uri,body_length'
|
||||
condition = ''
|
||||
conn = conn.field(field)
|
||||
conn = conn.where("1=1", ())
|
||||
@@ -1101,7 +1122,6 @@ def getUriStatList():
|
||||
conn = conn.where("day>? and flow>?", (0, 0,))
|
||||
|
||||
clist = conn.order("flow desc").limit("50").inquiry(origin_field)
|
||||
# print(clist)
|
||||
|
||||
total_req = 0
|
||||
total_flow = 0
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"sort": 7,
|
||||
"ps": "[DEV]网站统计报表[此插件-需要小白鼠反馈问题,慎用!]",
|
||||
"ps": "网站统计报表",
|
||||
"name": "webstats",
|
||||
"title": "网站统计",
|
||||
"shell": "install.sh",
|
||||
"versions":["0.2.0"],
|
||||
"versions":["0.2.2"],
|
||||
"tip": "soft",
|
||||
"install_pre_inspection":true,
|
||||
"checks": "server/webstats",
|
||||
|
||||
+18
-14
@@ -24,12 +24,14 @@ if [ -f ${rootPath}/bin/activate ];then
|
||||
source ${rootPath}/bin/activate
|
||||
fi
|
||||
|
||||
get_latest_release() {
|
||||
curl -sL "https://api.github.com/repos/$1/releases/latest" | grep '"tag_name":' | cut -d'"' -f4
|
||||
}
|
||||
|
||||
Install_App()
|
||||
{
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
mkdir -p $serverPath/source/webstats
|
||||
|
||||
|
||||
mkdir -p $serverPath/webstats
|
||||
|
||||
# 下载源码安装包
|
||||
@@ -88,29 +90,31 @@ Install_App()
|
||||
|
||||
# https://github.com/P3TERX/GeoLite.mmdb
|
||||
pip install geoip2
|
||||
if [ ! -f $serverPath/webstats/GeoLite2-City.mmdb ];then
|
||||
# pip install geoip2
|
||||
wget --no-check-certificate -O $serverPath/webstats/GeoLite2-City.mmdb https://git.io/GeoLite2-City.mmdb
|
||||
# if [ ! -f $serverPath/webstats/GeoLite2-City.mmdb ];then
|
||||
# wget --no-check-certificate -O $serverPath/webstats/GeoLite2-City.mmdb https://github.com/P3TERX/GeoLite.mmdb/releases/download/2022.10.16/GeoLite2-City.mmdb
|
||||
# fi
|
||||
|
||||
# 缓存数据
|
||||
GEO_VERSION=$(get_latest_release "P3TERX/GeoLite.mmdb")
|
||||
if [ ! -f $serverPath/source/webstats/GeoLite2-City.mmdb ];then
|
||||
wget --no-check-certificate -O $serverPath/source/webstats/GeoLite2-City.mmdb https://github.com/P3TERX/GeoLite.mmdb/releases/download/${GEO_VERSION}/GeoLite2-City.mmdb
|
||||
fi
|
||||
|
||||
# GeoLite2-Country.mmdb
|
||||
if [ -f $serverPath/source/webstats/GeoLite2-City.mmdb ];then
|
||||
cp -rf $serverPath/source/webstats/GeoLite2-City.mmdb $serverPath/webstats/GeoLite2-City.mmdb
|
||||
fi
|
||||
|
||||
echo "${VERSION}" > $serverPath/webstats/version.pl
|
||||
echo '安装完成' > $install_tmp
|
||||
|
||||
if [ "$sys_os" != "Darwin" ];then
|
||||
cd $rootPath && python3 ${rootPath}/plugins/webstats/index.py start
|
||||
fi
|
||||
cd $rootPath && python3 ${rootPath}/plugins/webstats/index.py start
|
||||
}
|
||||
|
||||
Uninstall_App()
|
||||
{
|
||||
if [ "$sys_os" != "Darwin" ];then
|
||||
cd $rootPath && python3 ${rootPath}/plugins/webstats/index.py stop
|
||||
fi
|
||||
|
||||
cd $rootPath && python3 ${rootPath}/plugins/webstats/index.py stop
|
||||
rm -rf $serverPath/webstats
|
||||
echo "Uninstall_redis" > $install_tmp
|
||||
echo "卸载完成" > $install_tmp
|
||||
}
|
||||
|
||||
action=$1
|
||||
|
||||
@@ -247,7 +247,7 @@ wsPost('get_global_conf', '' ,{}, function(rdata){
|
||||
|
||||
$('#setAll').click(function(){
|
||||
var args = "name=webstats&func=reload";
|
||||
layer.confirm('您真的要同步所有站点吗?', {icon:3,closeBtn: 2}, function() {
|
||||
layer.confirm('您真的要同步所有站点吗?', {icon:3,closeBtn: 1}, function() {
|
||||
var e = layer.msg('正在同步,请稍候...', {icon: 16,time: 0});
|
||||
$.post("/plugins/run", args, function(g) {
|
||||
layer.close(e);
|
||||
|
||||
@@ -2032,7 +2032,7 @@ function wsTableErrorLogRequest(page){
|
||||
type: 1,
|
||||
title: "【"+res.domain + "】详情信息",
|
||||
area: '600px',
|
||||
closeBtn: 2,
|
||||
closeBtn: 1,
|
||||
shadeClose: false,
|
||||
content: '<div class="pd15 lib-box">\
|
||||
<div style="height:80px;"><table class="table" style="border:#ddd 1px solid; margin-bottom:10px">\
|
||||
@@ -2110,7 +2110,7 @@ laydate.render({
|
||||
$(this).removeClass('cur');
|
||||
});
|
||||
|
||||
var timeA = value.split('-')
|
||||
var timeA = value.split('-');
|
||||
var start = $.trim(timeA[0]+'-'+timeA[1]+'-'+timeA[2])
|
||||
var end = $.trim(timeA[3]+'-'+timeA[4]+'-'+timeA[5])
|
||||
query_txt = toUnixTime(start + " 00:00:00") + "-"+ toUnixTime(end + " 00:00:00")
|
||||
@@ -2193,12 +2193,37 @@ function wsTableLogRequest(page){
|
||||
args['search_uri'] = search_uri;
|
||||
|
||||
args['tojs'] = 'wsTableLogRequest';
|
||||
|
||||
var spider_table = {
|
||||
"1":"百度",
|
||||
"2":"必应",
|
||||
"3":"奇虎360",
|
||||
"4":"Google",
|
||||
"5":"头条",
|
||||
"6":"搜狗",
|
||||
"7":"有道",
|
||||
"8":"搜搜",
|
||||
"9":"Dnspod",
|
||||
"10":"Yandex",
|
||||
"11":"一搜",
|
||||
"12":"其他",
|
||||
}
|
||||
|
||||
|
||||
wsPost('get_logs_list', '' ,args, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
var list = '';
|
||||
var data = rdata.data.data;
|
||||
|
||||
if (data.length > 0){
|
||||
for(i in data){
|
||||
|
||||
var spider_tip = '';
|
||||
if (data[i]['is_spider']>0){
|
||||
spider_tip_name = spider_table[data[i]['is_spider']]
|
||||
spider_tip = '<div data-toggle="tooltip" title="'+spider_tip_name+'爬虫" style="cursor:pointer;margin:3px;float:left;width:8px;height:8px;line-height:40px;border-radius:50%;background-color:#ccc;"></div>';
|
||||
}
|
||||
|
||||
list += '<tr>';
|
||||
list += '<td>' + getLocalTime(data[i]['time'])+'</td>';
|
||||
list += '<td><span class="overflow_hide" style="width:100px;">' + data[i]['domain'] +'</span></td>';
|
||||
@@ -2206,7 +2231,7 @@ function wsTableLogRequest(page){
|
||||
list += '<td>' + toSize(data[i]['body_length']) +'</td>';
|
||||
list += '<td>' + toSecond(data[i]['request_time']) +'</td>';
|
||||
list += '<td><span class="overflow_hide" style="width:130px;">' + data[i]['uri'] +'</span></td>';
|
||||
list += '<td><span class="overflow_hide" style="width:60px;">' + data[i]['status_code']+'/' + data[i]['method'] +'</span></td>';
|
||||
list += '<td>'+spider_tip+'<span class="overflow_hide" style="width:60px;">' + data[i]['status_code']+'/' + data[i]['method'] +'</span></td>';
|
||||
list += '<td><a data-id="'+i+'" href="javascript:;" class="btlink details" title="详情">详情</a></td>';
|
||||
list += '</tr>';
|
||||
}
|
||||
@@ -2241,7 +2266,7 @@ function wsTableLogRequest(page){
|
||||
type: 1,
|
||||
title: "【"+res.domain + "】详情信息",
|
||||
area: '600px',
|
||||
closeBtn: 2,
|
||||
closeBtn: 1,
|
||||
shadeClose: false,
|
||||
content: '<div class="pd15 lib-box">\
|
||||
<div style="height:80px;"><table class="table" style="border:#ddd 1px solid; margin-bottom:10px">\
|
||||
@@ -2264,6 +2289,8 @@ function wsTableLogRequest(page){
|
||||
</div>',
|
||||
});
|
||||
});
|
||||
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2322,7 +2349,7 @@ var html = '<div>\
|
||||
<option value="8">搜搜</option>\
|
||||
<option value="9">Dnspod</option>\
|
||||
<option value="10">Yandex</option>\
|
||||
<option value="12">神马</option>\
|
||||
<option value="11">一搜</option>\
|
||||
<option value="12">其他</option>\
|
||||
</select>\
|
||||
<span style="margin-left:10px;">URL过滤: </span>\
|
||||
@@ -2420,11 +2447,3 @@ wsPost('get_default_site','',{},function(rdata){
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user