mirror of
https://github.com/midoks/mdserver-web.git
synced 2026-10-11 04:59:26 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2438717c79 | ||
|
|
f952f88d9a | ||
|
|
019594cee7 | ||
|
|
d7980147d6 | ||
|
|
2e45194b34 | ||
|
|
8d21448edb | ||
|
|
1d986a2b16 | ||
|
|
c291cc57e7 | ||
|
|
0c9fe565e4 | ||
|
|
c04e52d3df | ||
|
|
966506bb8d | ||
|
|
11f42d5d2c | ||
|
|
ebf474aefb | ||
|
|
1ab3718fe5 | ||
|
|
aad35bb73b | ||
|
|
1c72e5b664 | ||
|
|
028307d1fc | ||
|
|
d0fc6a4c08 | ||
|
|
7507de7ed2 | ||
|
|
eb3f78ef4a | ||
|
|
a015c32e42 | ||
|
|
e5e106e3bc | ||
|
|
bc85a6003b | ||
|
|
e7bf5ef8b9 | ||
|
|
2337ea901b | ||
|
|
3a17126ac0 | ||
|
|
164bfa780c | ||
|
|
cb0375d9f7 | ||
|
|
1d15747753 | ||
|
|
af7c38a8c2 | ||
|
|
57bbf07432 | ||
|
|
fe1bc268d5 | ||
|
|
ea2cf0b691 | ||
|
|
a593e2b8e0 | ||
|
|
5394dd329a | ||
|
|
b121d08503 | ||
|
|
97800e3424 | ||
|
|
bb1068a03c | ||
|
|
f2443d9473 | ||
|
|
f7c9e6636a | ||
|
|
feb3e0220e | ||
|
|
c9951f870d | ||
|
|
c876c59e4f | ||
|
|
0e75844fd3 | ||
|
|
515a8c4272 | ||
|
|
d026385370 | ||
|
|
95ff8c66f6 | ||
|
|
6d90935784 | ||
|
|
94d45b1b07 | ||
|
|
dc1458fb2a | ||
|
|
ae74121229 | ||
|
|
f5b0ce7788 | ||
|
|
5757627a12 | ||
|
|
28f8f8945d | ||
|
|
e5386ab01c | ||
|
|
8ad9153012 | ||
|
|
2790a3890b | ||
|
|
a978c494c4 | ||
|
|
e1dd781b73 | ||
|
|
13a7c20764 | ||
|
|
7812c4983f | ||
|
|
a35ae6df9e | ||
|
|
32eefbba10 | ||
|
|
81de116417 | ||
|
|
37ace1226b | ||
|
|
7c780b32b8 | ||
|
|
eba923aa5f | ||
|
|
d97e265035 | ||
|
|
86014afedb | ||
|
|
b3626022bf | ||
|
|
e5bf49bca4 | ||
|
|
d988ce55b1 | ||
|
|
2804d0ed24 | ||
|
|
730797dcde | ||
|
|
476a4e9d88 | ||
|
|
665710f912 | ||
|
|
890a1ee864 | ||
|
|
5d7872200d | ||
|
|
ccdfde3186 | ||
|
|
f74c1ab784 | ||
|
|
82efc1a3e5 | ||
|
|
b6f87e16ac | ||
|
|
e1014a72bd | ||
|
|
218991d8d0 | ||
|
|
7937747a05 | ||
|
|
649ea30cb4 | ||
|
|
b92cfdeade | ||
|
|
76199a20a4 | ||
|
|
c42b92bb95 | ||
|
|
ce2affb119 | ||
|
|
d3e228bcd6 | ||
|
|
baac8e84ec | ||
|
|
3d0a55a383 | ||
|
|
d8c822de9d | ||
|
|
ee8a928357 | ||
|
|
785fb9698b | ||
|
|
14c3ccbfa5 | ||
|
|
41edac3e3a | ||
|
|
36173cdd0a | ||
|
|
ee59bd31e6 | ||
|
|
63004db963 | ||
|
|
93b3c5ba3c | ||
|
|
613063ce24 | ||
|
|
2e7a147fd3 | ||
|
|
894c0bff1f | ||
|
|
3ad999db00 | ||
|
|
1e5e1afeeb | ||
|
|
463d5c1b23 | ||
|
|
a24b98cbea | ||
|
|
94034125f7 | ||
|
|
17d446161b | ||
|
|
fb8c1d124e | ||
|
|
5033692886 | ||
|
|
e5ba11ae79 | ||
|
|
0be032041a | ||
|
|
3bf3e83442 | ||
|
|
bd7aefb6cc | ||
|
|
7009dfc3c4 | ||
|
|
21c30c6e99 | ||
|
|
63a0d2205d | ||
|
|
2e2e48e440 | ||
|
|
2f125383bf | ||
|
|
71877f7403 | ||
|
|
3d9d528694 | ||
|
|
39e8b98287 | ||
|
|
fe960a32ee | ||
|
|
645450f886 | ||
|
|
77b4917d3a | ||
|
|
893797b5e4 | ||
|
|
019543b790 | ||
|
|
c85fb94bc2 | ||
|
|
60f3dbf6fc | ||
|
|
b1846342d7 | ||
|
|
2f583d2e97 | ||
|
|
551bb1c3f7 | ||
|
|
36cf6c87cc | ||
|
|
66bea6a943 | ||
|
|
212d3e4ee8 | ||
|
|
422060b929 | ||
|
|
2b4f755244 | ||
|
|
67c477af14 | ||
|
|
a8502e30b3 | ||
|
|
82db6d14e0 | ||
|
|
c529d18ad8 | ||
|
|
cf54ee1736 | ||
|
|
8e8c4c47ec | ||
|
|
a6c981355c | ||
|
|
69755363ca | ||
|
|
eaa5a4d4ed | ||
|
|
4dcae9f877 | ||
|
|
424830729f | ||
|
|
a678d28a12 | ||
|
|
b9b5ecbac9 | ||
|
|
199716e1fd | ||
|
|
c95efcdd04 | ||
|
|
02f14b29ee | ||
|
|
97789d0796 | ||
|
|
ea5af1ac5b | ||
|
|
6e279a67e2 | ||
|
|
9758becc46 | ||
|
|
da2d0fd2ce | ||
|
|
6e0d580f6b | ||
|
|
34481c12e1 | ||
|
|
bc27feab00 | ||
|
|
1e48b32170 | ||
|
|
b9cbf63945 | ||
|
|
8437e236db | ||
|
|
838043a9dd | ||
|
|
8debe50f1b | ||
|
|
8a97577b61 | ||
|
|
cb9b6b2816 | ||
|
|
92d5126230 | ||
|
|
50c6f9fce5 | ||
|
|
cbb1403f80 | ||
|
|
21f995f8ac | ||
|
|
185e0dae22 | ||
|
|
e555829f1b | ||
|
|
2f50a2ffa0 | ||
|
|
069ececfe1 | ||
|
|
1ea1ad5ae0 | ||
|
|
3787913a12 | ||
|
|
45f51954f9 | ||
|
|
0c7773c6d4 | ||
|
|
81e1940b8f | ||
|
|
2e24a715ba | ||
|
|
a05be24ed1 | ||
|
|
f09017fe6e | ||
|
|
1aedb66132 | ||
|
|
2e3aef3776 | ||
|
|
0d3cf64e9a | ||
|
|
66220c1963 | ||
|
|
1ed52a1033 | ||
|
|
1a4ac13f8b | ||
|
|
e2e94015a0 | ||
|
|
dee7abc850 | ||
|
|
a1464006db | ||
|
|
b4c6bcec6e | ||
|
|
1d55ef3d0a | ||
|
|
24dab4775c | ||
|
|
7a7b77887c | ||
|
|
c39d21b300 | ||
|
|
3f7bce197f | ||
|
|
e706ff17c1 | ||
|
|
5a80422b77 | ||
|
|
d3fb392f28 | ||
|
|
6817043007 | ||
|
|
3106c101d8 | ||
|
|
e25c7f424d | ||
|
|
156459b6a4 | ||
|
|
c73fe892b7 | ||
|
|
491ad84103 | ||
|
|
cdb27c5d83 | ||
|
|
7d35f9d129 | ||
|
|
b34d1e7caa | ||
|
|
055a52da03 | ||
|
|
2c3746c596 | ||
|
|
96a0ca9b2f | ||
|
|
1cd436bc5d | ||
|
|
3834a9b0b8 | ||
|
|
30454e3b4a | ||
|
|
020354f5bc | ||
|
|
6e5dbeda72 | ||
|
|
804922a707 | ||
|
|
23081f4487 | ||
|
|
2f75f57365 | ||
|
|
f4f7ffe5dd | ||
|
|
0de23a3914 | ||
|
|
d1f47ca406 | ||
|
|
8d16fe1d46 | ||
|
|
d1bffd74ae | ||
|
|
23de77d951 | ||
|
|
172fe65df4 | ||
|
|
4cd96252f1 | ||
|
|
a88f4c35bd | ||
|
|
19ffeb7e8e | ||
|
|
004e1ce03c | ||
|
|
485efb0c88 | ||
|
|
227107719b | ||
|
|
d683f18bd0 | ||
|
|
78446b5a68 | ||
|
|
3fe638d16c | ||
|
|
f71973b10a | ||
|
|
0ab0a918c3 | ||
|
|
c694688220 | ||
|
|
f979fd32e3 | ||
|
|
7e11e8138e | ||
|
|
590575f5b1 | ||
|
|
b76c525106 | ||
|
|
56a276f019 | ||
|
|
62050fcff1 | ||
|
|
d4989bb762 | ||
|
|
dff54109a4 | ||
|
|
5850d69c10 | ||
|
|
908507f64e | ||
|
|
ecd455ab21 | ||
|
|
c4ebfff55e | ||
|
|
6adf5f472d | ||
|
|
ee6b5c304a | ||
|
|
03327a549f | ||
|
|
f6e245e77d | ||
|
|
4dcf9d9a40 | ||
|
|
a6ef4e12ad | ||
|
|
2e751bb3fb | ||
|
|
5ab15341e4 | ||
|
|
d6b027e969 | ||
|
|
76a4b3b3e6 | ||
|
|
3062aee5cb | ||
|
|
dbf0d95329 | ||
|
|
c42b0d5fda | ||
|
|
59f2688399 | ||
|
|
395bf3aa5a | ||
|
|
bd85e418bc | ||
|
|
091ac05920 | ||
|
|
127d175e5c | ||
|
|
744a7f83df | ||
|
|
5f61a7af17 | ||
|
|
c4ceaddcca | ||
|
|
12729092d8 | ||
|
|
94830659e9 | ||
|
|
aef307c312 | ||
|
|
2b15c77cdc | ||
|
|
78acddb043 | ||
|
|
9106f3d2f5 | ||
|
|
2df8355a33 | ||
|
|
c5610aae05 | ||
|
|
f1f3a42557 | ||
|
|
63072120fc | ||
|
|
0be966646b | ||
|
|
c3201118bd | ||
|
|
12896574c7 | ||
|
|
5bf877647f | ||
|
|
697e692c92 | ||
|
|
7b620a294b | ||
|
|
8c1e4d7c4d | ||
|
|
468c64df40 | ||
|
|
c560bc666f | ||
|
|
8c4ab4a60d | ||
|
|
1a0b7895d9 | ||
|
|
26a29fea96 | ||
|
|
5c9a12a7b2 | ||
|
|
7d103e8f4a | ||
|
|
4f4dfd0ee1 | ||
|
|
c02e95bc49 | ||
|
|
e77bfb055a | ||
|
|
712814515c | ||
|
|
512213df15 | ||
|
|
e07c5ab7f9 | ||
|
|
83471a37b0 | ||
|
|
f82944a043 | ||
|
|
6eb5dec1f6 | ||
|
|
f7ec845a7e | ||
|
|
0e7ed65e04 | ||
|
|
60910c9d87 | ||
|
|
f4b4b3c3a6 | ||
|
|
ce363b0319 | ||
|
|
42b0a4067b | ||
|
|
1e6f755045 | ||
|
|
c7570e84a0 | ||
|
|
34b7a5f7ba | ||
|
|
ff2146a49d | ||
|
|
5038d8b07f | ||
|
|
aacc87c190 | ||
|
|
e68a21ccb7 | ||
|
|
435f0a0c84 | ||
|
|
d4269dc886 | ||
|
|
079ae529ee | ||
|
|
f8d3e23025 | ||
|
|
efa168a4b1 | ||
|
|
ebfc32be74 | ||
|
|
79a2f6d7a4 | ||
|
|
edd218b139 | ||
|
|
d3645425f6 | ||
|
|
2f34c689d0 | ||
|
|
548e5fbde1 | ||
|
|
f0b3d7f151 | ||
|
|
c85a6fd462 | ||
|
|
ddbc7988b2 | ||
|
|
83b1e3b8af | ||
|
|
8fd4f83793 | ||
|
|
32321c822f | ||
|
|
bb8e8b7367 | ||
|
|
224417e2bd | ||
|
|
afb2a39f8c | ||
|
|
f240f167ff | ||
|
|
69273f9cf9 | ||
|
|
e30079bd2c | ||
|
|
d882de1582 | ||
|
|
2e14dc22ff | ||
|
|
6839e387c2 | ||
|
|
bde2bc0b2b | ||
|
|
e6fe0885a5 | ||
|
|
f95440da99 | ||
|
|
cbfff99f89 | ||
|
|
ee119ea3cc | ||
|
|
ebefee67bc | ||
|
|
60fc2e5803 | ||
|
|
b766a6eb6a | ||
|
|
f67342fd7a | ||
|
|
2f98228310 | ||
|
|
b07739a66a | ||
|
|
3b293e3163 | ||
|
|
cec5fc594f | ||
|
|
ed10a050bc | ||
|
|
cfc3dc73c4 | ||
|
|
7c23c16280 | ||
|
|
0f27552817 | ||
|
|
7464789c8c | ||
|
|
a1f9c023c7 | ||
|
|
9e8cdc2c49 | ||
|
|
dc9b44f5f9 | ||
|
|
b7ea4bd6f1 | ||
|
|
65dddb798c | ||
|
|
2451f0b593 | ||
|
|
418734eb31 | ||
|
|
fce7fe4fe3 | ||
|
|
e31407527f | ||
|
|
9250e81059 | ||
|
|
f54f9c6736 | ||
|
|
54135a88f9 | ||
|
|
5b219708db | ||
|
|
b62a5e457b | ||
|
|
3af325f0c4 | ||
|
|
514ced2cc6 | ||
|
|
55cdf6c0cf | ||
|
|
00cd6e4309 | ||
|
|
03012d8296 | ||
|
|
b4952dbb20 | ||
|
|
9123cedf4c | ||
|
|
1c9fbfc2eb | ||
|
|
d6e182b94f | ||
|
|
e48e56f36a | ||
|
|
adde6acf4d | ||
|
|
e929aa0875 | ||
|
|
f784376486 | ||
|
|
7c0d0f4a07 | ||
|
|
e25804998d | ||
|
|
6e69f843a0 | ||
|
|
978d2878a4 | ||
|
|
675ea86b83 | ||
|
|
c2be36b8b3 | ||
|
|
938e204691 | ||
|
|
70eb911e58 | ||
|
|
0440d0f286 | ||
|
|
9651a88d67 | ||
|
|
6b8d2622b4 | ||
|
|
e743499825 | ||
|
|
127535c7d4 | ||
|
|
0a322c9fed | ||
|
|
db36c34332 | ||
|
|
6c00e8c350 | ||
|
|
4e21b136d7 | ||
|
|
407b317f01 | ||
|
|
eb55ff7c30 | ||
|
|
3729146b80 | ||
|
|
48636eae43 | ||
|
|
ae62bee78d | ||
|
|
d0f33a0813 | ||
|
|
6627b67692 | ||
|
|
32f58e6323 | ||
|
|
4c82688f7d | ||
|
|
479ed7ac1e | ||
|
|
1320a8aad1 | ||
|
|
ed1b1322fa | ||
|
|
b9b61d1462 | ||
|
|
fc982674f8 |
+6
-1
@@ -180,4 +180,9 @@ plugins/frp
|
||||
plugins/file_search
|
||||
plugins/proxysql
|
||||
plugins/tidb
|
||||
plugins/gorse
|
||||
plugins/goedge-admin
|
||||
plugins/goedge-node
|
||||
plugins/goedge-happy
|
||||
plugins/dztasks
|
||||
|
||||
data/default_new.pl
|
||||
|
||||
@@ -110,11 +110,11 @@ docker run -itd --name mw-server --privileged=true -p 7200:7200 -p 80:80 -p 443:
|
||||
```
|
||||
|
||||
|
||||
### 版本更新 0.17.2
|
||||
### 版本更新 0.17.3
|
||||
|
||||
- MySQL9.0。
|
||||
- zabbix,zabbix-agent测试。
|
||||
- 正则匹配修复(兼容)。
|
||||
- 新增pgadmin插件。
|
||||
- 新增acme_pandominassl_apply插件。
|
||||
- 新增快捷指令:mw pgdb。
|
||||
- 常规更新。
|
||||
|
||||
### JSDelivr安装地址
|
||||
@@ -182,6 +182,11 @@ curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev
|
||||
|
||||
curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/dev/scripts/install_dev.sh | bash
|
||||
curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/dev/scripts/update_dev.sh | bash
|
||||
|
||||
|
||||
|
||||
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/install_new.sh | bash
|
||||
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/install_new.sh | bash
|
||||
```
|
||||
|
||||
### 捐赠地址 USDT(TRC20)
|
||||
|
||||
+31
-6
@@ -225,8 +225,7 @@ fi
|
||||
86400 # 24小时后过期
|
||||
self.saveConfig()
|
||||
except Exception as e:
|
||||
raise Exception(
|
||||
'服务因维护而关闭或发生内部错误,查看 <a href="https://letsencrypt.status.io/" target="_blank" class="btlink">https://letsencrypt.status.io/</a> 了解更多详细信息。')
|
||||
raise Exception('服务因维护而关闭或发生内部错误,查看 <a href="https://letsencrypt.status.io/" target="_blank" class="btlink">https://letsencrypt.status.io/</a> 了解更多详细信息。')
|
||||
return self.__apis
|
||||
|
||||
# 系列化payload
|
||||
@@ -1297,9 +1296,9 @@ fullchain.pem 粘贴到证书输入框
|
||||
site_sql = mw.M('sites')
|
||||
siteName = None
|
||||
for domain in domains:
|
||||
pid = sql.where('name=?', domain).getField('pid')
|
||||
pid = sql.where('name=?', (domain,)).getField('pid')
|
||||
if pid:
|
||||
siteName = site_sql.where('id=?', pid).getField('name')
|
||||
siteName = site_sql.where('id=?', (pid,)).getField('name')
|
||||
break
|
||||
return siteName
|
||||
|
||||
@@ -1325,6 +1324,8 @@ fullchain.pem 粘贴到证书输入框
|
||||
else:
|
||||
site_name = self.getSiteNameByDomains(domains)
|
||||
is_rep = api.httpToHttps(site_name)
|
||||
api.operateProxyConf(site_name,'stop')
|
||||
mw.restartWeb()
|
||||
try:
|
||||
index = self.createOrder(
|
||||
domains,
|
||||
@@ -1376,9 +1377,23 @@ fullchain.pem 粘贴到证书输入框
|
||||
is_rep_decode = json.loads(is_rep)
|
||||
if is_rep_decode['status']:
|
||||
api.closeToHttps(site_name)
|
||||
|
||||
api.operateProxyConf(site_name,'start')
|
||||
mw.restartWeb()
|
||||
writeLog("-" * 70)
|
||||
return cert
|
||||
|
||||
def checkDomainIsExsits(self, domain):
|
||||
if mw.M('domain').where("name=?", (domain,)).count() > 0:
|
||||
return True
|
||||
|
||||
if mw.M('sites').where("name=?", (domain,)).count() > 0:
|
||||
return True
|
||||
|
||||
if mw.M('binding').where("name=?", (domain,)).count() > 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
def renewCert(self, index):
|
||||
writeLog("", "wb+")
|
||||
# self.D('renew_cert', index)
|
||||
@@ -1425,6 +1440,8 @@ fullchain.pem 粘贴到证书输入框
|
||||
for domain in self.__config['orders'][i]['domains']:
|
||||
if domain.find('*') != -1:
|
||||
break
|
||||
|
||||
|
||||
if not mw.M('domain').where("name=?", (domain,)).count() and not mw.M('binding').where("domain=?", domain).count():
|
||||
auth_to = None
|
||||
msg = "|-跳过被删除的域名: {}".format(
|
||||
@@ -1435,6 +1452,14 @@ fullchain.pem 粘贴到证书输入框
|
||||
|
||||
self.__config['orders'][i]['auth_to'] = auth_to
|
||||
|
||||
auth_to = True
|
||||
for domain in self.__config['orders'][i]['domains']:
|
||||
if not self.checkDomainIsExsits(domain):
|
||||
auth_to = False
|
||||
msg = "|-跳过被删除的域名: {}!".format(self.__config['orders'][i]['domains'])
|
||||
writeLog(msg)
|
||||
if not auth_to:
|
||||
continue
|
||||
# 是否到了允许重试的时间
|
||||
if 'next_retry_time' in self.__config['orders'][i]:
|
||||
timeout = self.__config['orders'][i][
|
||||
@@ -1447,8 +1472,8 @@ fullchain.pem 粘贴到证书输入框
|
||||
|
||||
# 是否到了最大重试次数
|
||||
if 'retry_count' in self.__config['orders'][i]:
|
||||
if self.__config['orders'][i]['retry_count'] >= 5:
|
||||
msg = '|-本次跳过域名:{},因连续5次续签失败,不再续签此证书(可尝试手动续签此证书,成功后错误次数将被重置)'.format(
|
||||
if self.__config['orders'][i]['retry_count'] >= 100:
|
||||
msg = '|-本次跳过域名:{},因连续100次续签失败,不再续签此证书(可尝试手动续签此证书,成功后错误次数将被重置)'.format(
|
||||
self.__config['orders'][i]['domains'])
|
||||
writeLog(msg)
|
||||
continue
|
||||
|
||||
@@ -28,7 +28,7 @@ from flask import request
|
||||
|
||||
class config_api:
|
||||
|
||||
__version = '0.17.2'
|
||||
__version = '0.17.4'
|
||||
__api_addr = 'data/api.json'
|
||||
|
||||
# 统一默认配置文件
|
||||
@@ -42,7 +42,7 @@ class config_api:
|
||||
'bind_domain' : 'data/bind_domain.pl', # 面板域名绑定
|
||||
'unauth_status' : 'data/unauthorized_status.pl', # URL路径未成功显示状态
|
||||
'auth_secret': 'data/auth_secret.pl', # 二次验证密钥
|
||||
'ssl':'ssl/choose.pl', # ssl设置
|
||||
'ssl':'ssl/choose.pl', # ssl设置
|
||||
'hook_database' : 'data/hook_database.json', # 数据库钩子
|
||||
'hook_menu' : 'data/hook_menu.json', # 菜单钩子
|
||||
'hook_global_static' : 'data/hook_global_static.json', # 静态文件钩子
|
||||
|
||||
@@ -1074,9 +1074,9 @@ class files_api:
|
||||
|
||||
order_arr = order.split(' ')
|
||||
if len(order_arr) < 2:
|
||||
plist = mw.sortFileList(path, order_arr[0],'')
|
||||
plist = mw.sortFileList(path, order_arr[0], '')
|
||||
else:
|
||||
plist = mw.sortFileList(path, order_arr[0],order_arr[1])
|
||||
plist = mw.sortFileList(path, order_arr[0], order_arr[1])
|
||||
|
||||
for filename in plist:
|
||||
if search:
|
||||
|
||||
@@ -173,14 +173,12 @@ class logs_api:
|
||||
|
||||
def __to_date2(self, date_str):
|
||||
tmp = date_str.split()
|
||||
s_date = str(tmp[-1]) + '-' + self.__months.get(tmp[1],
|
||||
tmp[1]) + '-' + tmp[2] + ' ' + tmp[3]
|
||||
s_date = str(tmp[-1]) + '-' + self.__months.get(tmp[1], tmp[1]) + '-' + tmp[2] + ' ' + tmp[3]
|
||||
return s_date
|
||||
|
||||
def __to_date3(self, date_str):
|
||||
tmp = date_str.split()
|
||||
s_date = str(datetime.now().year) + '-' + \
|
||||
self.__months.get(tmp[1], tmp[1]) + '-' + tmp[2] + ' ' + tmp[3]
|
||||
s_date = str(datetime.now().year) + '-' + self.__months.get(tmp[1], tmp[1]) + '-' + tmp[2] + ' ' + tmp[3]
|
||||
return s_date
|
||||
|
||||
def __to_date4(self, date_str):
|
||||
|
||||
+19
-7
@@ -472,6 +472,9 @@ def getJson(data):
|
||||
import json
|
||||
return json.dumps(data)
|
||||
|
||||
def getObjectByJson(data):
|
||||
import json
|
||||
return json.loads(data)
|
||||
|
||||
def returnData(status, msg, data=None):
|
||||
return {'status': status, 'msg': msg, 'data': data}
|
||||
@@ -590,8 +593,11 @@ def writeLog(stype, msg, args=()):
|
||||
if 'uid' in session:
|
||||
uid = session['uid']
|
||||
except Exception as e:
|
||||
pass
|
||||
print('writeL:',e)
|
||||
# pass
|
||||
# writeFileLog(getTracebackInfo())
|
||||
|
||||
print(stype, msg)
|
||||
return writeDbLog(stype, msg, args, uid)
|
||||
|
||||
|
||||
@@ -687,6 +693,15 @@ def restoreFile(file, act=None):
|
||||
file_type = "_def"
|
||||
execShell("cp -p {1} {0}".format(file, file + file_type))
|
||||
|
||||
def base64StrEncode(content):
|
||||
content = bytes(content,'utf-8')
|
||||
content = base64.b64encode(content)
|
||||
return content.decode('utf8')
|
||||
|
||||
def base64StrDecode(content):
|
||||
content = bytes(content,'utf-8')
|
||||
content = base64.urlsafe_b64decode(content)
|
||||
return content.decode('utf8')
|
||||
|
||||
def enPunycode(domain):
|
||||
if sys.version_info[0] == 2:
|
||||
@@ -704,11 +719,9 @@ def enPunycode(domain):
|
||||
newdomain += dkey + '.'
|
||||
else:
|
||||
if sys.version_info[0] == 2:
|
||||
newdomain += 'xn--' + \
|
||||
dkey.decode('utf-8').encode('punycode') + '.'
|
||||
newdomain += 'xn--' + dkey.decode('utf-8').encode('punycode') + '.'
|
||||
else:
|
||||
newdomain += 'xn--' + \
|
||||
dkey.encode('punycode').decode('utf-8') + '.'
|
||||
newdomain += 'xn--' + dkey.encode('punycode').decode('utf-8') + '.'
|
||||
if tmp[0] == '*':
|
||||
newdomain = "*." + newdomain
|
||||
return newdomain[0:-1]
|
||||
@@ -720,8 +733,7 @@ def dePunycode(domain):
|
||||
newdomain = ''
|
||||
for dkey in tmp:
|
||||
if dkey.find('xn--') >= 0:
|
||||
newdomain += dkey.replace('xn--',
|
||||
'').encode('utf-8').decode('punycode') + '.'
|
||||
newdomain += dkey.replace('xn--','').encode('utf-8').decode('punycode') + '.'
|
||||
else:
|
||||
newdomain += dkey + '.'
|
||||
return newdomain[0:-1]
|
||||
|
||||
@@ -148,7 +148,7 @@ class plugins_api:
|
||||
def initApi(self):
|
||||
|
||||
plugin_names = {
|
||||
'openresty': '1.25.3.1',
|
||||
'openresty': '1.25.3',
|
||||
'php': '56',
|
||||
'swap': '1.1',
|
||||
'mysql': '5.7',
|
||||
@@ -663,7 +663,7 @@ class plugins_api:
|
||||
return mw.readFile(version_f).strip()
|
||||
return ''
|
||||
|
||||
# 构造本地插件信息
|
||||
# 构造本地插件信息
|
||||
def getPluginInfo(self, info):
|
||||
checks = ''
|
||||
path = ''
|
||||
|
||||
+62
-62
@@ -727,43 +727,43 @@ class site_api:
|
||||
conf = mw.readFile(file)
|
||||
|
||||
if conf:
|
||||
rep = "\n\s*#HTTP_TO_HTTPS_START(.|\n){1,300}#HTTP_TO_HTTPS_END"
|
||||
rep = "\n\\s*#HTTP_TO_HTTPS_START(.|\n){1,300}#HTTP_TO_HTTPS_END"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+ssl_certificate\s+.+;\s+ssl_certificate_key\s+.+;"
|
||||
rep = "\\s+ssl_certificate\\s+.+;\\s+ssl_certificate_key\\s+.+;"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+ssl_protocols\s+.+;\n"
|
||||
rep = "\\s+ssl_protocols\\s+.+;\n"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+ssl_ciphers\s+.+;\n"
|
||||
rep = "\\s+ssl_ciphers\\s+.+;\n"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+ssl_prefer_server_ciphers\s+.+;\n"
|
||||
rep = "\\s+ssl_prefer_server_ciphers\\s+.+;\n"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+ssl_session_cache\s+.+;\n"
|
||||
rep = "\\s+ssl_session_cache\\s+.+;\n"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+ssl_session_timeout\s+.+;\n"
|
||||
rep = r"\s+ssl_session_timeout\s+.+;\n"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+ssl_ecdh_curve\s+.+;\n"
|
||||
rep = r"\s+ssl_ecdh_curve\s+.+;\n"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+ssl_session_tickets\s+.+;\n"
|
||||
rep = r"\s+ssl_session_tickets\s+.+;\n"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+ssl_stapling\s+.+;\n"
|
||||
rep = r"\s+ssl_stapling\s+.+;\n"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+ssl_stapling_verify\s+.+;\n"
|
||||
rep = r"\s+ssl_stapling_verify\s+.+;\n"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+add_header\s+.+;\n"
|
||||
rep = r"\s+add_header\s+.+;\n"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+add_header\s+.+;\n"
|
||||
rep = r"\s+add_header\s+.+;\n"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+ssl\s+on;"
|
||||
rep = r"\s+ssl\s+on;"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+error_page\s497.+;"
|
||||
rep = r"\s+error_page\s497.+;"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+if.+server_port.+\n.+\n\s+\s*}"
|
||||
rep = r"\s+if.+server_port.+\n.+\n\s+\s*}"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+listen\s+443.*;"
|
||||
rep = r"\s+listen\s+443.*;"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+listen\s+\[\:\:\]\:443.*;"
|
||||
rep = r"\s+listen\s+\[\:\:\]\:443.*;"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+http2\s+on;"
|
||||
rep = r"\s+http2\s+on;"
|
||||
conf = re.sub(rep, '', conf)
|
||||
mw.writeFile(file, conf)
|
||||
|
||||
@@ -888,7 +888,7 @@ class site_api:
|
||||
# fix binddir domain ssl apply question
|
||||
mw.backFile(host_conf_file)
|
||||
auth_to = self.getSitePath(siteName)
|
||||
rep = "\s*root\s*(.+);"
|
||||
rep = r"\s*root\s*(.+);"
|
||||
replace_root = "\n\troot " + auth_to + ";"
|
||||
siteConf = re.sub(rep, replace_root, siteConf)
|
||||
mw.writeFile(host_conf_file, siteConf)
|
||||
@@ -1043,7 +1043,7 @@ class site_api:
|
||||
src_path = mw.getAcmeDomainDir(domains[0])
|
||||
src_cert = src_path + '/fullchain.cer'
|
||||
src_key = src_path + '/' + domains[0] + '.key'
|
||||
src_cert.replace("\*", "*")
|
||||
src_cert.replace("\\*", "*")
|
||||
|
||||
msg = '签发失败,您尝试申请证书的失败次数已达上限!<p>1、检查域名是否绑定到对应站点</p>\
|
||||
<p>2、检查域名是否正确解析到本服务器,或解析还未完全生效</p>\
|
||||
@@ -1115,9 +1115,9 @@ class site_api:
|
||||
file = self.getHostConf(site_name)
|
||||
conf = mw.readFile(file)
|
||||
if conf:
|
||||
rep = "\n\s*#HTTP_TO_HTTPS_START(.|\n){1,300}#HTTP_TO_HTTPS_END"
|
||||
rep = r"\n\s*#HTTP_TO_HTTPS_START(.|\n){1,300}#HTTP_TO_HTTPS_END"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+if.+server_port.+\n.+\n\s+\s*}"
|
||||
rep = r"\s+if.+server_port.+\n.+\n\s+\s*}"
|
||||
conf = re.sub(rep, '', conf)
|
||||
mw.writeFile(file, conf)
|
||||
|
||||
@@ -1282,7 +1282,7 @@ class site_api:
|
||||
domain_name = self.toPunycode(domain[0])
|
||||
domain_port = '80'
|
||||
|
||||
reg = "^([\w\-\*]{1,100}\.){1,4}([\w\-]{1,24}|[\w\-]{1,24}\.[\w\-]{1,24})$"
|
||||
reg = r"^([\w\-\*]{1,100}\.){1,4}([\w\-]{1,24}|[\w\-]{1,24}\.[\w\-]{1,24})$"
|
||||
if not re.match(reg, domain_name):
|
||||
return mw.returnJson(False, '域名格式不正确!')
|
||||
|
||||
@@ -1339,7 +1339,7 @@ class site_api:
|
||||
if dirName == '':
|
||||
mw.returnJson(False, '目录不能为空!')
|
||||
|
||||
reg = "^([\w\-\*]{1,100}\.){1,4}(\w{1,10}|\w{1,10}\.\w{1,10})$"
|
||||
reg = r"^([\w\-\*]{1,100}\.){1,4}(\w{1,10}|\w{1,10}\.\w{1,10})$"
|
||||
if not re.match(reg, domain):
|
||||
return mw.returnJson(False, '主域名格式不正确!')
|
||||
|
||||
@@ -1355,7 +1355,7 @@ class site_api:
|
||||
filename = self.getHostConf(siteInfo['name'])
|
||||
conf = mw.readFile(filename)
|
||||
if conf:
|
||||
rep = "enable-php-([0-9]{2,3})\.conf"
|
||||
rep = r"enable-php-([0-9]{2,3})\.conf"
|
||||
tmp = re.search(rep, conf).groups()
|
||||
version = tmp[0]
|
||||
|
||||
@@ -1507,7 +1507,7 @@ class site_api:
|
||||
filename = self.getHostConf(siteName)
|
||||
if os.path.exists(filename):
|
||||
conf = mw.readFile(filename)
|
||||
rep = '\s*root\s*(.+);'
|
||||
rep = r'\s*root\s*(.+);'
|
||||
path = re.search(rep, conf).groups()[0]
|
||||
conf = conf.replace(path, newPath)
|
||||
mw.writeFile(filename, conf)
|
||||
@@ -1578,7 +1578,7 @@ class site_api:
|
||||
|
||||
if os.path.exists(configFile):
|
||||
conf = mw.readFile(configFile)
|
||||
rep = "\n\s*#AUTH_START(.|\n){1,200}#AUTH_END"
|
||||
rep = r"\n\s*#AUTH_START(.|\n){1,200}#AUTH_END"
|
||||
conf = re.sub(rep, '', conf)
|
||||
mw.writeFile(configFile, conf)
|
||||
|
||||
@@ -1604,19 +1604,19 @@ class site_api:
|
||||
conf = mw.readFile(file)
|
||||
if conf:
|
||||
# 删除域名
|
||||
rep = "server_name\s+(.+);"
|
||||
rep = r"server_name\s+(.+);"
|
||||
tmp = re.search(rep, conf).group()
|
||||
newServerName = tmp.replace(' ' + domain + ';', ';')
|
||||
newServerName = newServerName.replace(' ' + domain + ' ', ' ')
|
||||
conf = conf.replace(tmp, newServerName)
|
||||
|
||||
# 删除端口
|
||||
rep = "listen\s+([0-9]+);"
|
||||
rep = r"listen\s+([0-9]+);"
|
||||
tmp = re.findall(rep, conf)
|
||||
port_count = mw.M('domain').where(
|
||||
'pid=? AND port=?', (pid, port)).count()
|
||||
if mw.inArray(tmp, port) == True and port_count < 2:
|
||||
rep = "\n*\s+listen\s+" + port + ";"
|
||||
rep = r"\n*\s+listen\s+" + port + ";"
|
||||
conf = re.sub(rep, '', conf)
|
||||
# 保存配置
|
||||
mw.writeFile(file, conf)
|
||||
@@ -1778,7 +1778,7 @@ class site_api:
|
||||
if item["r_from"] == _from:
|
||||
return mw.returnJson(False, "重复的规则!")
|
||||
|
||||
rep = "http(s)?\:\/\/([a-zA-Z0-9][-a-zA-Z0-9]{0,62}\.)+([a-zA-Z0-9][a-zA-Z0-9]{0,62})+.?"
|
||||
rep = r"http(s)?\:\/\/([a-zA-Z0-9][-a-zA-Z0-9]{0,62}\.)+([a-zA-Z0-9][a-zA-Z0-9]{0,62})+.?"
|
||||
if not re.match(rep, _to):
|
||||
return mw.returnJson(False, "错误的目标地址")
|
||||
|
||||
@@ -1786,8 +1786,7 @@ class site_api:
|
||||
data.append({"r_from": _from, "type": _typeCode, "r_type": _rTypeCode,
|
||||
"r_to": _to, 'keep_path': _keepPath, 'id': _id})
|
||||
mw.writeFile(data_path, json.dumps(data))
|
||||
mw.writeFile(
|
||||
"{}/{}.conf".format(self.getRedirectPath(_siteName), _id), file_content)
|
||||
mw.writeFile("{}/{}.conf".format(self.getRedirectPath(_siteName), _id), file_content)
|
||||
|
||||
self.operateRedirectConf(_siteName, 'start')
|
||||
mw.restartWeb()
|
||||
@@ -1943,7 +1942,7 @@ class site_api:
|
||||
if _name == "" or _siteName == "" or _from == "" or _to == "" or _host == "":
|
||||
return mw.returnJson(False, "必填项不能为空")
|
||||
|
||||
rep = "http(s)?\:\/\/([a-zA-Z0-9][-a-zA-Z0-9]{0,62}\.)+([a-zA-Z0-9][a-zA-Z0-9]{0,62})+.?"
|
||||
rep = r"http(s)?\:\/\/([a-zA-Z0-9][-a-zA-Z0-9]{0,62}\.)+([a-zA-Z0-9][a-zA-Z0-9]{0,62})+.?"
|
||||
if not re.match(rep, _to):
|
||||
return mw.returnJson(False, "错误的目标地址!")
|
||||
|
||||
@@ -1977,6 +1976,7 @@ class site_api:
|
||||
location ^~ {from} {\n\
|
||||
proxy_pass {to};\n\
|
||||
proxy_set_header Host {host};\n\
|
||||
proxy_ssl_server_name on;\n\
|
||||
proxy_set_header X-Real-IP $remote_addr;\n\
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n\
|
||||
proxy_set_header REMOTE-HOST $remote_addr;\n\
|
||||
@@ -1990,7 +1990,7 @@ location ^~ {from} {\n\
|
||||
}\n\
|
||||
# PROXY-END"
|
||||
|
||||
tpl_proxy_cache = "\n\
|
||||
tpl_proxy_cache = r"\n\
|
||||
if ( $uri ~* \"\.(gif|png|jpg|css|js|woff|woff2)$\" )\n\
|
||||
{\n\
|
||||
expires {cache_time}m;\n\
|
||||
@@ -2001,7 +2001,7 @@ location ^~ {from} {\n\
|
||||
proxy_cache_valid 200 304 301 302 {cache_time}m;\n\
|
||||
"
|
||||
|
||||
tpl_proxy_nocache = "\n\
|
||||
tpl_proxy_nocache = r"\n\
|
||||
set $static_files_app 0; \n\
|
||||
if ( $uri ~* \"\.(gif|png|jpg|css|js|woff|woff2)$\" )\n\
|
||||
{\n\
|
||||
@@ -2219,7 +2219,7 @@ location ^~ {from} {\n\
|
||||
file = self.getHostConf(siteName)
|
||||
if os.path.exists(file):
|
||||
conf = mw.readFile(file)
|
||||
rep = '\s*root\s*(.+);'
|
||||
rep = r'\s*root\s*(.+);'
|
||||
find_cnf = re.search(rep, conf)
|
||||
if not find_cnf:
|
||||
return ''
|
||||
@@ -2236,7 +2236,7 @@ location ^~ {from} {\n\
|
||||
filename = self.getHostConf(siteName)
|
||||
if os.path.exists(filename):
|
||||
conf = mw.readFile(filename)
|
||||
rep = '\s*root\s*(.+);'
|
||||
rep = r'\s*root\s*(.+);'
|
||||
path = re.search(rep, conf).groups()[0]
|
||||
|
||||
data = {}
|
||||
@@ -2321,7 +2321,7 @@ location ^~ {from} {\n\
|
||||
|
||||
def getSitePhpVersion(self, siteName):
|
||||
conf = mw.readFile(self.getHostConf(siteName))
|
||||
rep = "enable-php-(.*)\.conf"
|
||||
rep = r"enable-php-(.*)\.conf"
|
||||
find_php_cnf = re.search(rep, conf)
|
||||
|
||||
def_pver = '00'
|
||||
@@ -2337,7 +2337,7 @@ location ^~ {from} {\n\
|
||||
siteName = mw.M('sites').where("id=?", (sid,)).getField('name')
|
||||
file = self.getHostConf(siteName)
|
||||
conf = mw.readFile(file)
|
||||
rep = "\s+index\s+(.+);"
|
||||
rep = r"\s+index\s+(.+);"
|
||||
tmp = re.search(rep, conf).groups()
|
||||
return tmp[0].replace(' ', ',')
|
||||
|
||||
@@ -2356,7 +2356,7 @@ location ^~ {from} {\n\
|
||||
file = self.getHostConf(siteName)
|
||||
conf = mw.readFile(file)
|
||||
if conf:
|
||||
rep = "\s+index\s+.+;"
|
||||
rep = r"\s+index\s+.+;"
|
||||
conf = re.sub(rep, "\n\tindex " + index_l + ";", conf)
|
||||
mw.writeFile(file, conf)
|
||||
|
||||
@@ -2370,17 +2370,17 @@ location ^~ {from} {\n\
|
||||
data = {}
|
||||
conf = mw.readFile(filename)
|
||||
try:
|
||||
rep = "\s+limit_conn\s+perserver\s+([0-9]+);"
|
||||
rep = r"\s+limit_conn\s+perserver\s+([0-9]+);"
|
||||
tmp = re.search(rep, conf).groups()
|
||||
data['perserver'] = int(tmp[0])
|
||||
|
||||
# IP并发限制
|
||||
rep = "\s+limit_conn\s+perip\s+([0-9]+);"
|
||||
rep = r"\s+limit_conn\s+perip\s+([0-9]+);"
|
||||
tmp = re.search(rep, conf).groups()
|
||||
data['perip'] = int(tmp[0])
|
||||
|
||||
# 请求并发限制
|
||||
rep = "\s+limit_rate\s+([0-9]+)\w+;"
|
||||
rep = r"\s+limit_rate\s+([0-9]+)\w+;"
|
||||
tmp = re.search(rep, conf).groups()
|
||||
data['limit_rate'] = int(tmp[0])
|
||||
except:
|
||||
@@ -2410,15 +2410,15 @@ location ^~ {from} {\n\
|
||||
conf = mw.readFile(filename)
|
||||
if(conf.find('limit_conn perserver') != -1):
|
||||
# 替换总并发
|
||||
rep = "limit_conn\s+perserver\s+([0-9]+);"
|
||||
rep = r"limit_conn\s+perserver\s+([0-9]+);"
|
||||
conf = re.sub(rep, str_perserver, conf)
|
||||
|
||||
# 替换IP并发限制
|
||||
rep = "limit_conn\s+perip\s+([0-9]+);"
|
||||
rep = r"limit_conn\s+perip\s+([0-9]+);"
|
||||
conf = re.sub(rep, str_perip, conf)
|
||||
|
||||
# 替换请求流量限制
|
||||
rep = "limit_rate\s+([0-9]+)\w+;"
|
||||
rep = r"limit_rate\s+([0-9]+)\w+;"
|
||||
conf = re.sub(rep, str_limit_rate, conf)
|
||||
else:
|
||||
conf = conf.replace('#error_page 404/404.html;', "#error_page 404/404.html;\n " +
|
||||
@@ -2434,15 +2434,15 @@ location ^~ {from} {\n\
|
||||
filename = self.getHostConf(siteName)
|
||||
conf = mw.readFile(filename)
|
||||
# 清理总并发
|
||||
rep = "\s+limit_conn\s+perserver\s+([0-9]+);"
|
||||
rep = r"\s+limit_conn\s+perserver\s+([0-9]+);"
|
||||
conf = re.sub(rep, '', conf)
|
||||
|
||||
# 清理IP并发限制
|
||||
rep = "\s+limit_conn\s+perip\s+([0-9]+);"
|
||||
rep = r"\s+limit_conn\s+perip\s+([0-9]+);"
|
||||
conf = re.sub(rep, '', conf)
|
||||
|
||||
# 清理请求流量限制
|
||||
rep = "\s+limit_rate\s+([0-9]+)\w+;"
|
||||
rep = r"\s+limit_rate\s+([0-9]+)\w+;"
|
||||
conf = re.sub(rep, '', conf)
|
||||
mw.writeFile(filename, conf)
|
||||
mw.restartWeb()
|
||||
@@ -2458,15 +2458,15 @@ location ^~ {from} {\n\
|
||||
rep = "#SECURITY-START(\n|.){1,500}#SECURITY-END"
|
||||
tmp = re.search(rep, conf).group()
|
||||
data['fix'] = re.search(
|
||||
"\(.+\)\$", tmp).group().replace('(', '').replace(')$', '').replace('|', ',')
|
||||
r"\(.+\)\$", tmp).group().replace('(', '').replace(')$', '').replace('|', ',')
|
||||
|
||||
data['status'] = False
|
||||
data['none'] = False
|
||||
|
||||
valid_referers = re.search(
|
||||
"valid_referers\s+(.+);\n", tmp)
|
||||
r"valid_referers\s+(.+);\n", tmp)
|
||||
valid_referers_none = re.search(
|
||||
"valid_referers\s+none\s+blocked\s+(.+);\n", tmp)
|
||||
r"valid_referers\s+none\s+blocked\s+(.+);\n", tmp)
|
||||
|
||||
if valid_referers or valid_referers_none:
|
||||
data['status'] = True
|
||||
@@ -2500,11 +2500,11 @@ location ^~ {from} {\n\
|
||||
if os.path.exists(file):
|
||||
conf = mw.readFile(file)
|
||||
if status == 'false':
|
||||
rep = "\s{0,4}#SECURITY-START(\n|.){1,500}#SECURITY-END\n?"
|
||||
rep = r"\s{0,4}#SECURITY-START(\n|.){1,500}#SECURITY-END\n?"
|
||||
conf = re.sub(rep, '', conf)
|
||||
mw.writeLog('网站管理', '站点[' + name + ']已关闭防盗链设置!')
|
||||
else:
|
||||
rep = "\s{0,4}#SECURITY-START(\n|.){1,500}#SECURITY-END\n?"
|
||||
rep = r"\s{0,4}#SECURITY-START(\n|.){1,500}#SECURITY-END\n?"
|
||||
conf = re.sub(rep, '', conf)
|
||||
|
||||
valid_referers = domains.strip().replace(',', ' ')
|
||||
@@ -2512,8 +2512,8 @@ location ^~ {from} {\n\
|
||||
valid_referers = 'none blocked ' + valid_referers
|
||||
|
||||
pre_path = self.setupPath + "/php/conf"
|
||||
re_path = "include\s+" + pre_path + "/enable-php-"
|
||||
rconf = '''#SECURITY-START 防盗链配置
|
||||
re_path = r"include\s+" + pre_path + "/enable-php-"
|
||||
rconf = r'''#SECURITY-START 防盗链配置
|
||||
location ~ .*\.(%s)$
|
||||
{
|
||||
expires 30d;
|
||||
@@ -2555,7 +2555,7 @@ location ^~ {from} {\n\
|
||||
conf_dir = mw.getServerDir() + "/web_conf/php/conf"
|
||||
conf_list = os.listdir(conf_dir)
|
||||
l = len(conf_list)
|
||||
rep = "enable-php-(.*?)\.conf"
|
||||
rep = r"enable-php-(.*?)\.conf"
|
||||
for name in conf_list:
|
||||
tmp = {}
|
||||
try:
|
||||
@@ -2611,7 +2611,7 @@ location ^~ {from} {\n\
|
||||
return
|
||||
|
||||
# 添加域名
|
||||
rep = "server_name\s*(.*);"
|
||||
rep = r"server_name\s*(.*);"
|
||||
tmp = re.search(rep, conf).group()
|
||||
domains = tmp.split(' ')
|
||||
if not mw.inArray(domains, domain):
|
||||
@@ -2619,7 +2619,7 @@ location ^~ {from} {\n\
|
||||
conf = conf.replace(tmp, newServerName)
|
||||
|
||||
# 添加端口
|
||||
rep = "listen\s+([0-9]+)\s*[default_server]*\s*;"
|
||||
rep = r"listen\s+([0-9]+)\s*[default_server]*\s*;"
|
||||
tmp = re.findall(rep, conf)
|
||||
if not mw.inArray(tmp, port):
|
||||
listen = re.search(rep, conf).group()
|
||||
@@ -2820,7 +2820,7 @@ location ^~ {from} {\n\
|
||||
|
||||
conf = conf.replace('#error_page 404/404.html;', sslStr)
|
||||
|
||||
rep = "listen\s+([0-9]+)\s*[default_server|reuseport]*;"
|
||||
rep = r"listen\s+([0-9]+)\s*[default_server|reuseport]*;"
|
||||
tmp = re.findall(rep, conf)
|
||||
if not mw.inArray(tmp, '443'):
|
||||
listen = re.search(rep, conf).group()
|
||||
|
||||
@@ -717,7 +717,6 @@ class system_api:
|
||||
|
||||
self.cache[iokey] = {'info':diskio_group,'time':mtime}
|
||||
except Exception as e:
|
||||
# print(mw.getTracebackInfo())
|
||||
pass
|
||||
|
||||
return diskInfo
|
||||
@@ -866,6 +865,7 @@ class system_api:
|
||||
return {}
|
||||
|
||||
def updateServer(self, stype, version=''):
|
||||
return mw.returnJson(False, '与后续版本差异太大,不再提供更新')
|
||||
# 更新服务
|
||||
try:
|
||||
if not mw.isRestart():
|
||||
|
||||
@@ -3,5 +3,6 @@ PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/usr/loc
|
||||
|
||||
|
||||
|
||||
find . -name .DS_Store -print0 | xargs -0 git rm -f --ignore-unmatch
|
||||
find . -name .DS_Store | xargs rm -rf
|
||||
find . -type d -name "*.pyc" | xargs rm -rf
|
||||
@@ -4,9 +4,11 @@
|
||||
- 面板相关命令
|
||||
|
||||
```
|
||||
/etc/init.d/mw default | 显示登录信息
|
||||
/etc/init.d/mw db | 快捷连接MySQL
|
||||
/etc/init.d/mw redis | 快捷连接Redis
|
||||
mw default | 显示登录信息
|
||||
mw db | 快捷连接MySQL
|
||||
mw redis | 快捷连接Redis
|
||||
mw mongodb | 快捷连接MongoDB
|
||||
mw pgdb | 快捷连接PostgreSQL
|
||||
----------------------------------------
|
||||
mw open | 开启面板
|
||||
mw close | 关闭面板
|
||||
@@ -16,7 +18,7 @@ mw venv | 进入虚拟环境
|
||||
mw mirror | 切换镜像
|
||||
mw install_app | 快捷安装常用软件
|
||||
mw update | 更新到正式
|
||||
mw update_dev | 更新到开发
|
||||
mw dev/update_dev | 更新到开发
|
||||
|
||||
service mw [start|stop|reload|restart|status]
|
||||
```
|
||||
|
||||
@@ -71,9 +71,14 @@ CREATE TABLE IF NOT EXISTS `sites` (
|
||||
`type_id` INTEGER,
|
||||
`ps` TEXT,
|
||||
`edate` TEXT,
|
||||
`ssl_effective_date` TEXT,
|
||||
`ssl_expiration_date` TEXT,
|
||||
`addtime` TEXT
|
||||
);
|
||||
|
||||
ALTER TABLE `sites` ADD COLUMN `ssl_effective_date` TEXT DEFAULT '';
|
||||
ALTER TABLE `sites` ADD COLUMN `ssl_expiration_date` TEXT DEFAULT '';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `site_types` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`name` TEXT
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ server
|
||||
allow all;
|
||||
}
|
||||
|
||||
location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf|js|css)$
|
||||
location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf|js|css|ttf|woff2)$
|
||||
{
|
||||
expires 30d;
|
||||
error_log /dev/null;
|
||||
|
||||
Executable
+113
@@ -0,0 +1,113 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
DIR=$(cd "$(dirname "$0")"; pwd)
|
||||
MDIR=$(dirname "$DIR")
|
||||
|
||||
# echo $DIR
|
||||
|
||||
PATH=$PATH:$DIR/bin
|
||||
if [ -f ${DIR}/bin/activate ];then
|
||||
source ${DIR}/bin/activate
|
||||
|
||||
if [ "$?" != "0" ];then
|
||||
echo "load local python env fail!"
|
||||
fi
|
||||
fi
|
||||
|
||||
export LC_ALL="en_US.UTF-8"
|
||||
|
||||
|
||||
mw_start_task()
|
||||
{
|
||||
isStart=$(ps aux |grep 'panel_task.py'|grep -v grep|awk '{print $2}')
|
||||
if [ "$isStart" == '' ];then
|
||||
echo -e "starting mw-tasks... \c"
|
||||
cd $DIR && python3 panel_task.py >> ${DIR}/logs/panel_task.log 2>&1 &
|
||||
sleep 0.3
|
||||
isStart=$(ps aux |grep 'panel_task.py'|grep -v grep|awk '{print $2}')
|
||||
if [ "$isStart" == '' ];then
|
||||
echo -e "\033[31mfailed\033[0m"
|
||||
echo '------------------------------------------------------'
|
||||
tail -n 20 $DIR/logs/panel_task.log
|
||||
echo '------------------------------------------------------'
|
||||
echo -e "\033[31mError: mw-tasks service startup failed.\033[0m"
|
||||
return;
|
||||
fi
|
||||
echo -e "\033[32mdone\033[0m"
|
||||
else
|
||||
echo "starting mw-tasks... mw-tasks (pid $(echo $isStart)) already running"
|
||||
fi
|
||||
}
|
||||
|
||||
mw_start(){
|
||||
cd web && gunicorn -c setting.py app:app
|
||||
#安全启动
|
||||
mw_start_task
|
||||
}
|
||||
|
||||
|
||||
mw_start_debug(){
|
||||
if [ ! -f $DIR/logs/panel_task.log ];then
|
||||
echo '' > $DIR/logs/panel_task.log
|
||||
fi
|
||||
|
||||
python3 panel_task.py >> $DIR/logs/panel_task.log 2>&1 &
|
||||
port=7200
|
||||
if [ -f /www/server/mdserver-web/data/port.pl ];then
|
||||
port=$(cat /www/server/mdserver-web/data/port.pl)
|
||||
fi
|
||||
|
||||
if [ -f ${DIR}/data/port.pl ];then
|
||||
port=$(cat ${DIR}/data/port.pl)
|
||||
fi
|
||||
# gunicorn -b :${port} -k gevent -w 1 app:app
|
||||
cd web && gunicorn -b :${port} -w 1 app:app
|
||||
}
|
||||
|
||||
mw_start_debug2(){
|
||||
python3 panel_task.py >> $DIR/logs/panel_task.log 2>&1 &
|
||||
gunicorn -b :7200 -w 1 app:app
|
||||
}
|
||||
|
||||
mw_start_debug3(){
|
||||
gunicorn -c setting.py app:app
|
||||
python3 panel_task.py
|
||||
}
|
||||
|
||||
|
||||
mw_stop()
|
||||
{
|
||||
PLIST=`ps -ef|grep app:app |grep -v grep|awk '{print $2}'`
|
||||
for i in $PLIST
|
||||
do
|
||||
kill -9 $i > /dev/null 2>&1
|
||||
done
|
||||
|
||||
pids=`ps -ef|grep panel_task.py | grep -v grep |awk '{print $2}'`
|
||||
arr=($pids)
|
||||
for p in ${arr[@]}
|
||||
do
|
||||
kill -9 $p > /dev/null 2>&1
|
||||
done
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
'start') mw_start;;
|
||||
'stop') mw_stop;;
|
||||
'restart')
|
||||
mw_stop
|
||||
mw_start
|
||||
;;
|
||||
'debug')
|
||||
mw_stop
|
||||
mw_start_debug
|
||||
;;
|
||||
'debug2')
|
||||
mw_stop
|
||||
mw_start_debug2
|
||||
;;
|
||||
'debug3')
|
||||
mw_stop
|
||||
mw_start_debug3
|
||||
;;
|
||||
esac
|
||||
Executable
+626
@@ -0,0 +1,626 @@
|
||||
# coding: utf-8
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# MW-Linux面板
|
||||
# ---------------------------------------------------------------------------------
|
||||
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
|
||||
# ---------------------------------------------------------------------------------
|
||||
# Author: midoks <midoks@163.com>
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# 计划任务
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
import threading
|
||||
import psutil
|
||||
|
||||
|
||||
web_dir = os.getcwd() + "/web"
|
||||
os.chdir(web_dir)
|
||||
sys.path.append(web_dir)
|
||||
|
||||
from admin import app
|
||||
from admin import model
|
||||
|
||||
import core.mw as mw
|
||||
import core.db as db
|
||||
|
||||
|
||||
# print(mw.getPanelDir())
|
||||
|
||||
# print sys.path
|
||||
|
||||
# cmd = 'ls /usr/local/lib/ | grep python | cut -d \\ -f 1 | awk \'END {print}\''
|
||||
# info = mw.execShell(cmd)
|
||||
# p = "/usr/local/lib/" + info[0].strip() + "/site-packages"
|
||||
# sys.path.append(p)
|
||||
|
||||
|
||||
global pre, timeoutCount, logPath, isTask, oldEdate, isCheck
|
||||
pre = 0
|
||||
timeoutCount = 0
|
||||
isCheck = 0
|
||||
oldEdate = None
|
||||
|
||||
g_log_file = mw.getPanelTaskLog()
|
||||
isTask = mw.getMWLogs() + '/panelTask.pl'
|
||||
|
||||
if not os.path.exists(g_log_file):
|
||||
os.system("touch " + g_log_file)
|
||||
|
||||
def execShell(cmdstring, cwd=None, timeout=None, shell=True):
|
||||
try:
|
||||
global g_log_file
|
||||
import shlex
|
||||
import datetime
|
||||
import subprocess
|
||||
|
||||
if timeout:
|
||||
end_time = datetime.datetime.now() + datetime.timedelta(seconds=timeout)
|
||||
|
||||
cmd = cmdstring + ' > ' + g_log_file + ' 2>&1'
|
||||
sub = subprocess.Popen(cmd, cwd=cwd, stdin=subprocess.PIPE, shell=shell, bufsize=4096)
|
||||
while sub.poll() is None:
|
||||
time.sleep(0.1)
|
||||
|
||||
data = sub.communicate()
|
||||
# python3 fix 返回byte数据
|
||||
if isinstance(data[0], bytes):
|
||||
t1 = str(data[0], encoding='utf-8')
|
||||
|
||||
if isinstance(data[1], bytes):
|
||||
t2 = str(data[1], encoding='utf-8')
|
||||
return (t1, t2)
|
||||
except Exception as e:
|
||||
return (None, None)
|
||||
|
||||
def service_cmd(method):
|
||||
cmd = '/etc/init.d/mw'
|
||||
if os.path.exists(cmd):
|
||||
execShell(cmd + ' ' + method)
|
||||
return
|
||||
|
||||
cmd = mw.getRunDir() + '/scripts/init.d/mw'
|
||||
if os.path.exists(cmd):
|
||||
execShell(cmd + ' ' + method)
|
||||
return
|
||||
|
||||
|
||||
def openresty_cmd(method = 'reload'):
|
||||
# 检查是否安装
|
||||
odir = mw.getServerDir() + '/openresty'
|
||||
if not os.path.exists(odir):
|
||||
return False
|
||||
|
||||
# systemd
|
||||
systemd = mw.systemdCfgDir()+'/openresty.service'
|
||||
if os.path.exists(systemd):
|
||||
execShell('systemctl ' + method + ' openresty')
|
||||
return True
|
||||
|
||||
sys_initd = '/etc/init.d/openresty'
|
||||
if os.path.exists(sys_initd):
|
||||
os.system(sys_initd + ' ' + method)
|
||||
return True
|
||||
|
||||
install_initd = mw.getServerDir()+'/openresty/init.d/openresty'
|
||||
if os.path.exists(install_initd):
|
||||
os.system(install_initd + ' ' + method)
|
||||
return True
|
||||
return False
|
||||
|
||||
def mw_async(f):
|
||||
def wrapper(*args, **kwargs):
|
||||
thr = threading.Thread(target=f, args=args, kwargs=kwargs)
|
||||
thr.start()
|
||||
return wrapper
|
||||
|
||||
|
||||
@mw_async
|
||||
def restartMw():
|
||||
time.sleep(1)
|
||||
cmd = mw.getRunDir() + '/scripts/init.d/mw reload &'
|
||||
mw.execShell(cmd)
|
||||
|
||||
|
||||
|
||||
def downloadFile(url, filename):
|
||||
# 下载文件
|
||||
try:
|
||||
import urllib
|
||||
import socket
|
||||
socket.setdefaulttimeout(300)
|
||||
|
||||
headers = ('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36')
|
||||
opener = urllib.request.build_opener()
|
||||
opener.addheaders = [headers]
|
||||
urllib.request.install_opener(opener)
|
||||
|
||||
urllib.request.urlretrieve(url, filename=filename, reporthook=downloadHook)
|
||||
|
||||
if not mw.isAppleSystem():
|
||||
os.system('chown www.www ' + filename)
|
||||
|
||||
writeLogs('done')
|
||||
except Exception as e:
|
||||
writeLogs(str(e))
|
||||
return True
|
||||
|
||||
|
||||
def downloadHook(count, blockSize, totalSize):
|
||||
# 下载文件进度回调
|
||||
global pre
|
||||
used = count * blockSize
|
||||
pre1 = int((100.0 * used / totalSize))
|
||||
if pre == (100 - pre1):
|
||||
return
|
||||
speed = {'total': totalSize, 'used': used, 'pre': pre1}
|
||||
writeLogs(json.dumps(speed))
|
||||
|
||||
|
||||
def writeLogs(data):
|
||||
# 写输出日志
|
||||
try:
|
||||
fp = open(g_log_file, 'w+')
|
||||
fp.write(data)
|
||||
fp.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def runPanelTask():
|
||||
try:
|
||||
bash_list = model.getTaskList(status=-1)
|
||||
for task in bash_list:
|
||||
model.setTaskStatus(task['id'], 0)
|
||||
|
||||
run_list = model.getTaskList(status=0)
|
||||
for run_task in run_list:
|
||||
start = int(time.time())
|
||||
model.setTaskData(run_task['id'], start=start)
|
||||
model.setTaskStatus(run_task['id'], -1)
|
||||
if run_task['type'] == 'download':
|
||||
argv = run_task['cmd'].split('|mw|')
|
||||
downloadFile(argv[0], argv[1])
|
||||
elif run_task['type'] == 'execshell':
|
||||
execShell(run_task['cmd'])
|
||||
end = int(time.time())
|
||||
model.setTaskData(run_task['id'], end=end)
|
||||
model.setTaskStatus(run_task['id'], 1)
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
|
||||
# 站点过期检查
|
||||
# siteEdate()
|
||||
|
||||
# 任务队列
|
||||
def startPanelTask():
|
||||
try:
|
||||
while True:
|
||||
runPanelTask()
|
||||
time.sleep(1)
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
time.sleep(10)
|
||||
startPanelTask()
|
||||
|
||||
# 网站到期处理
|
||||
def siteEdate():
|
||||
global oldEdate
|
||||
try:
|
||||
if not oldEdate:
|
||||
oldEdate = mw.readFile('data/edate.pl')
|
||||
if not oldEdate:
|
||||
oldEdate = '0000-00-00'
|
||||
mEdate = time.strftime('%Y-%m-%d', time.localtime())
|
||||
if oldEdate == mEdate:
|
||||
return False
|
||||
edateSites = mw.M('sites').where('edate>? AND edate<? AND (status=? OR status=?)',
|
||||
('0000-00-00', mEdate, 1, '正在运行')).field('id,name').select()
|
||||
import site_api
|
||||
for site in edateSites:
|
||||
site_api.site_api().stop(site['id'], site['name'])
|
||||
oldEdate = mEdate
|
||||
mw.writeFile('data/edate.pl', mEdate)
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
|
||||
|
||||
def systemTask():
|
||||
# 系统监控任务
|
||||
try:
|
||||
import system_api
|
||||
import psutil
|
||||
sm = system_api.system_api()
|
||||
filename = 'data/control.conf'
|
||||
|
||||
sql = db.Sql().dbfile('system')
|
||||
csql = mw.readFile('data/sql/system.sql')
|
||||
csql_list = csql.split(';')
|
||||
for index in range(len(csql_list)):
|
||||
sql.execute(csql_list[index], ())
|
||||
|
||||
cpuIo = cpu = {}
|
||||
cpuCount = psutil.cpu_count()
|
||||
used = count = 0
|
||||
reloadNum = 0
|
||||
network_up = network_down = diskio_1 = diskio_2 = networkInfo = cpuInfo = diskInfo = None
|
||||
while True:
|
||||
if not os.path.exists(filename):
|
||||
time.sleep(10)
|
||||
continue
|
||||
|
||||
day = 30
|
||||
try:
|
||||
day = int(mw.readFile(filename))
|
||||
if day < 1:
|
||||
time.sleep(10)
|
||||
continue
|
||||
except:
|
||||
day = 30
|
||||
|
||||
tmp = {}
|
||||
# 取当前CPU Io
|
||||
tmp['used'] = psutil.cpu_percent(interval=1)
|
||||
if tmp['used'] > 80:
|
||||
panel_title = mw.getConfig('title')
|
||||
ip = mw.getHostAddr()
|
||||
now_time = mw.getDateFromNow()
|
||||
msg = now_time + '|节点[' + panel_title + ':' + ip + \
|
||||
']处于高负载[' + str(tmp['used']) + '],请排查原因!'
|
||||
mw.notifyMessage(msg, '面板监控', 600)
|
||||
|
||||
if not cpuInfo:
|
||||
tmp['mem'] = sm.getMemUsed()
|
||||
cpuInfo = tmp
|
||||
|
||||
if cpuInfo['used'] < tmp['used']:
|
||||
tmp['mem'] = sm.getMemUsed()
|
||||
cpuInfo = tmp
|
||||
|
||||
# 取当前网络Io
|
||||
networkIo = sm.psutilNetIoCounters()
|
||||
if not network_up:
|
||||
network_up = networkIo[0]
|
||||
network_down = networkIo[1]
|
||||
tmp = {}
|
||||
tmp['upTotal'] = networkIo[0]
|
||||
tmp['downTotal'] = networkIo[1]
|
||||
tmp['up'] = round(float((networkIo[0] - network_up) / 1024), 2)
|
||||
tmp['down'] = round(float((networkIo[1] - network_down) / 1024), 2)
|
||||
tmp['downPackets'] = networkIo[3]
|
||||
tmp['upPackets'] = networkIo[2]
|
||||
|
||||
network_up = networkIo[0]
|
||||
network_down = networkIo[1]
|
||||
|
||||
if not networkInfo:
|
||||
networkInfo = tmp
|
||||
if (tmp['up'] + tmp['down']) > (networkInfo['up'] + networkInfo['down']):
|
||||
networkInfo = tmp
|
||||
# 取磁盘Io
|
||||
# if os.path.exists('/proc/diskstats'):
|
||||
diskio_2 = psutil.disk_io_counters()
|
||||
if not diskio_1:
|
||||
diskio_1 = diskio_2
|
||||
tmp = {}
|
||||
tmp['read_count'] = diskio_2.read_count - diskio_1.read_count
|
||||
tmp['write_count'] = diskio_2.write_count - diskio_1.write_count
|
||||
tmp['read_bytes'] = diskio_2.read_bytes - diskio_1.read_bytes
|
||||
tmp['write_bytes'] = diskio_2.write_bytes - diskio_1.write_bytes
|
||||
tmp['read_time'] = diskio_2.read_time - diskio_1.read_time
|
||||
tmp['write_time'] = diskio_2.write_time - diskio_1.write_time
|
||||
|
||||
if not diskInfo:
|
||||
diskInfo = tmp
|
||||
else:
|
||||
diskInfo['read_count'] += tmp['read_count']
|
||||
diskInfo['write_count'] += tmp['write_count']
|
||||
diskInfo['read_bytes'] += tmp['read_bytes']
|
||||
diskInfo['write_bytes'] += tmp['write_bytes']
|
||||
diskInfo['read_time'] += tmp['read_time']
|
||||
diskInfo['write_time'] += tmp['write_time']
|
||||
diskio_1 = diskio_2
|
||||
|
||||
# print diskInfo
|
||||
if count >= 12:
|
||||
try:
|
||||
addtime = int(time.time())
|
||||
deltime = addtime - (day * 86400)
|
||||
|
||||
data = (cpuInfo['used'], cpuInfo['mem'], addtime)
|
||||
sql.table('cpuio').add('pro,mem,addtime', data)
|
||||
sql.table('cpuio').where("addtime<?", (deltime,)).delete()
|
||||
|
||||
data = (networkInfo['up'] / 5, networkInfo['down'] / 5, networkInfo['upTotal'], networkInfo[
|
||||
'downTotal'], networkInfo['downPackets'], networkInfo['upPackets'], addtime)
|
||||
sql.table('network').add(
|
||||
'up,down,total_up,total_down,down_packets,up_packets,addtime', data)
|
||||
sql.table('network').where(
|
||||
"addtime<?", (deltime,)).delete()
|
||||
# if os.path.exists('/proc/diskstats'):
|
||||
data = (diskInfo['read_count'], diskInfo['write_count'], diskInfo['read_bytes'], diskInfo[
|
||||
'write_bytes'], diskInfo['read_time'], diskInfo['write_time'], addtime)
|
||||
sql.table('diskio').add(
|
||||
'read_count,write_count,read_bytes,write_bytes,read_time,write_time,addtime', data)
|
||||
sql.table('diskio').where(
|
||||
"addtime<?", (deltime,)).delete()
|
||||
|
||||
# LoadAverage
|
||||
load_average = sm.getLoadAverage()
|
||||
lpro = round(
|
||||
(load_average['one'] / load_average['max']) * 100, 2)
|
||||
if lpro > 100:
|
||||
lpro = 100
|
||||
sql.table('load_average').add('pro,one,five,fifteen,addtime', (lpro, load_average[
|
||||
'one'], load_average['five'], load_average['fifteen'], addtime))
|
||||
|
||||
lpro = None
|
||||
load_average = None
|
||||
cpuInfo = None
|
||||
networkInfo = None
|
||||
diskInfo = None
|
||||
count = 0
|
||||
reloadNum += 1
|
||||
if reloadNum > 1440:
|
||||
reloadNum = 0
|
||||
mw.writeFile('logs/sys_interrupt.pl',
|
||||
"reload num:" + str(reloadNum))
|
||||
restartMw()
|
||||
except Exception as ex:
|
||||
print(str(ex))
|
||||
mw.writeFile('logs/sys_interrupt.pl', str(ex))
|
||||
|
||||
del(tmp)
|
||||
time.sleep(5)
|
||||
count += 1
|
||||
except Exception as ex:
|
||||
print(str(ex))
|
||||
mw.writeFile('logs/sys_interrupt.pl', str(ex))
|
||||
|
||||
restartMw()
|
||||
|
||||
time.sleep(30)
|
||||
systemTask()
|
||||
|
||||
|
||||
# -------------------------------------- PHP监控 start --------------------------------------------- #
|
||||
# 502错误检查线程
|
||||
def check502Task():
|
||||
try:
|
||||
while True:
|
||||
if os.path.exists(mw.getPanelDir() + '/data/502Task.pl'):
|
||||
check502()
|
||||
time.sleep(30)
|
||||
except:
|
||||
time.sleep(30)
|
||||
check502Task()
|
||||
|
||||
|
||||
def check502():
|
||||
try:
|
||||
verlist = [
|
||||
'52', '53', '54', '55', '56', '70',
|
||||
'71', '72', '73', '74', '80', '81',
|
||||
'82', '83', '84'
|
||||
]
|
||||
for ver in verlist:
|
||||
sdir = mw.getServerDir()
|
||||
php_path = sdir + '/php/' + ver + '/sbin/php-fpm'
|
||||
if not os.path.exists(php_path):
|
||||
continue
|
||||
if checkPHPVersion(ver):
|
||||
continue
|
||||
if startPHPVersion(ver):
|
||||
print('检测到PHP-' + ver + '处理异常,已自动修复!')
|
||||
mw.writeLog('PHP守护程序', '检测到PHP-' + ver + '处理异常,已自动修复!')
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
|
||||
|
||||
# 处理指定PHP版本
|
||||
def startPHPVersion(version):
|
||||
sdir = mw.getServerDir()
|
||||
try:
|
||||
# system
|
||||
phpService = mw.systemdCfgDir() + '/php' + version + '.service'
|
||||
if os.path.exists(phpService):
|
||||
mw.execShell("systemctl restart php" + version)
|
||||
if checkPHPVersion(version):
|
||||
return True
|
||||
|
||||
# initd
|
||||
fpm = sdir + '/php/init.d/php' + version
|
||||
php_path = sdir + '/php/' + version + '/sbin/php-fpm'
|
||||
if not os.path.exists(php_path):
|
||||
if os.path.exists(fpm):
|
||||
os.remove(fpm)
|
||||
return False
|
||||
|
||||
if not os.path.exists(fpm):
|
||||
return False
|
||||
|
||||
# 尝试重载服务
|
||||
os.system(fpm + ' reload')
|
||||
if checkPHPVersion(version):
|
||||
return True
|
||||
|
||||
# 尝试重启服务
|
||||
cgi = '/tmp/php-cgi-' + version + '.sock'
|
||||
pid = sdir + '/php/' + version + '/var/run/php-fpm.pid'
|
||||
data = mw.execShell("ps -ef | grep php/" + version +" | grep -v grep|grep -v python |awk '{print $2}'")
|
||||
if data[0] != '':
|
||||
os.system("ps -ef | grep php/" + version + " | grep -v grep|grep -v python |awk '{print $2}' | xargs kill ")
|
||||
time.sleep(0.5)
|
||||
if not os.path.exists(cgi):
|
||||
os.system('rm -f ' + cgi)
|
||||
if not os.path.exists(pid):
|
||||
os.system('rm -f ' + pid)
|
||||
os.system(fpm + ' start')
|
||||
if checkPHPVersion(version):
|
||||
return True
|
||||
|
||||
# 检查是否正确启动
|
||||
if os.path.exists(cgi):
|
||||
return True
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
return True
|
||||
|
||||
|
||||
def getFpmConfFile(version):
|
||||
return mw.getServerDir() + '/php/' + version + '/etc/php-fpm.d/www.conf'
|
||||
|
||||
|
||||
def getFpmAddress(version):
|
||||
fpm_address = '/tmp/php-cgi-{}.sock'.format(version)
|
||||
php_fpm_file = getFpmConfFile(version)
|
||||
try:
|
||||
content = readFile(php_fpm_file)
|
||||
tmp = re.findall(r"listen\s*=\s*(.+)", content)
|
||||
if not tmp:
|
||||
return fpm_address
|
||||
if tmp[0].find('sock') != -1:
|
||||
return fpm_address
|
||||
if tmp[0].find(':') != -1:
|
||||
listen_tmp = tmp[0].split(':')
|
||||
if bind:
|
||||
fpm_address = (listen_tmp[0], int(listen_tmp[1]))
|
||||
else:
|
||||
fpm_address = ('127.0.0.1', int(listen_tmp[1]))
|
||||
else:
|
||||
fpm_address = ('127.0.0.1', int(tmp[0]))
|
||||
return fpm_address
|
||||
except:
|
||||
return fpm_address
|
||||
|
||||
|
||||
def checkPHPVersion(version):
|
||||
# 检查指定PHP版本
|
||||
try:
|
||||
sock = getFpmAddress(version)
|
||||
data = mw.requestFcgiPHP(sock, '/phpfpm_status_' + version + '?json')
|
||||
result = str(data, encoding='utf-8')
|
||||
except Exception as e:
|
||||
result = 'Bad Gateway'
|
||||
|
||||
# print(version,result)
|
||||
# 检查openresty
|
||||
if result.find('Bad Gateway') != -1:
|
||||
return False
|
||||
if result.find('HTTP Error 404: Not Found') != -1:
|
||||
return False
|
||||
|
||||
# 检查Web服务是否启动
|
||||
if result.find('Connection refused') != -1:
|
||||
return False
|
||||
# global isTask
|
||||
# if os.path.exists(isTask):
|
||||
# isStatus = mw.readFile(isTask)
|
||||
# if isStatus == 'True':
|
||||
# return True
|
||||
|
||||
# # systemd
|
||||
# systemd = mw.systemdCfgDir() + '/openresty.service'
|
||||
# if os.path.exists(systemd):
|
||||
# execShell('systemctl reload openresty')
|
||||
# return True
|
||||
# # initd
|
||||
# initd = '/etc/init.d/openresty'
|
||||
# if os.path.exists(initd):
|
||||
# os.system(initd + ' reload')
|
||||
return True
|
||||
|
||||
# --------------------------------------PHP监控 end--------------------------------------------- #
|
||||
|
||||
|
||||
# --------------------------------------OpenResty Auto Restart Start --------------------------------------------- #
|
||||
# 解决acme.sh续签后,未起效。
|
||||
def openrestyAutoRestart():
|
||||
try:
|
||||
while True:
|
||||
# 检查是否安装
|
||||
odir = mw.getServerDir() + '/openresty'
|
||||
if not os.path.exists(odir):
|
||||
time.sleep(86400)
|
||||
continue
|
||||
|
||||
openresty_cmd('reload')
|
||||
time.sleep(86400)
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
time.sleep(86400)
|
||||
|
||||
# --------------------------------------OpenResty Auto Restart End --------------------------------------------- #
|
||||
|
||||
# ------------------------------------ OpenResty Restart At Once Start ------------------------------------------ #
|
||||
|
||||
|
||||
def openrestyRestartAtOnce():
|
||||
restart_nginx_tip = 'data/restart_nginx.pl'
|
||||
while True:
|
||||
if os.path.exists(restart_nginx_tip):
|
||||
os.remove(restart_nginx_tip)
|
||||
openresty_cmd('reload')
|
||||
time.sleep(1)
|
||||
# ----------------------------------- OpenResty Restart At Once End ------------------------------------------ #
|
||||
|
||||
|
||||
# --------------------------------------Panel Restart Start --------------------------------------------- #
|
||||
def restartPanelService():
|
||||
restartTip = 'data/restart.pl'
|
||||
while True:
|
||||
if os.path.exists(restartTip):
|
||||
os.remove(restartTip)
|
||||
service_cmd('restart_panel')
|
||||
time.sleep(1)
|
||||
# --------------------------------------Panel Restart End --------------------------------------------- #
|
||||
|
||||
|
||||
def setDaemon(t):
|
||||
if sys.version_info.major == 3 and sys.version_info.minor >= 10:
|
||||
t.daemon = True
|
||||
else:
|
||||
t.setDaemon(True)
|
||||
return t
|
||||
|
||||
def run():
|
||||
# # 系统监控
|
||||
# sysTask = threading.Thread(target=systemTask)
|
||||
# sysTask = setDaemon(sysTask)
|
||||
# sysTask.start()
|
||||
|
||||
# # PHP 502错误检查线程
|
||||
# php502 = threading.Thread(target=check502Task)
|
||||
# php502 = setDaemon(php502)
|
||||
# php502.start()
|
||||
|
||||
# # OpenResty Restart At Once Start
|
||||
# oraos = threading.Thread(target=openrestyRestartAtOnce)
|
||||
# oraos = setDaemon(oraos)
|
||||
# oraos.start()
|
||||
|
||||
|
||||
# # OpenResty Auto Restart Start
|
||||
# oar = threading.Thread(target=openrestyAutoRestart)
|
||||
# oar = setDaemon(oar)
|
||||
# oar.start()
|
||||
|
||||
|
||||
# # Panel Restart Start
|
||||
# rps = threading.Thread(target=restartPanelService)
|
||||
# rps = setDaemon(rps)
|
||||
# rps.start()
|
||||
|
||||
# 面板后台任务
|
||||
startPanelTask()
|
||||
|
||||
if __name__ == "__main__":
|
||||
with app.app_context():
|
||||
run()
|
||||
|
||||
Executable
+306
@@ -0,0 +1,306 @@
|
||||
# coding=utf-8
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# MW-Linux面板
|
||||
# ---------------------------------------------------------------------------------
|
||||
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
|
||||
# ---------------------------------------------------------------------------------
|
||||
# Author: midoks <midoks@163.com>
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# 工具箱
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
import re
|
||||
|
||||
web_dir = os.getcwd() + "/web"
|
||||
os.chdir(web_dir)
|
||||
sys.path.append(web_dir)
|
||||
|
||||
import core.mw as mw
|
||||
import core.db as db
|
||||
|
||||
# cmd = 'ls /usr/local/lib/ | grep python | cut -d \\ -f 1 | awk \'END {print}\''
|
||||
# info = mw.execShell(cmd)
|
||||
# p = "/usr/local/lib/" + info[0].strip() + "/site-packages"
|
||||
# sys.path.append(p)
|
||||
|
||||
INIT_DIR = "/etc/rc.d/init.d"
|
||||
if mw.isAppleSystem():
|
||||
INIT_DIR = mw.getPanelDir() + "/scripts/init.d"
|
||||
|
||||
INIT_CMD = INIT_DIR + "/mw"
|
||||
|
||||
|
||||
def mw_input_cmd(msg):
|
||||
if sys.version_info[0] == 2:
|
||||
in_val = raw_input(msg)
|
||||
else:
|
||||
in_val = input(msg)
|
||||
return in_val
|
||||
|
||||
|
||||
def mwcli(mw_input=0):
|
||||
raw_tip = "======================================================"
|
||||
if not mw_input:
|
||||
print("===============mdserver-web cli tools=================")
|
||||
print("(1) 重启面板服务")
|
||||
print("(2) 停止面板服务")
|
||||
print("(3) 启动面板服务")
|
||||
print("(4) 重载面板服务")
|
||||
print("(5) 修改面板端口")
|
||||
print("(10) 查看面板默认信息")
|
||||
print("(11) 修改面板密码")
|
||||
print("(12) 修改面板用户名")
|
||||
print("(13) 显示面板错误日志")
|
||||
print("(20) 关闭BasicAuth认证")
|
||||
print("(21) 解除域名绑定")
|
||||
print("(22) 解除面板SSL绑定")
|
||||
print("(23) 开启IPV6支持")
|
||||
print("(24) 关闭IPV6支持")
|
||||
print("(25) 开启防火墙SSH端口")
|
||||
print("(26) 关闭二次验证")
|
||||
print("(27) 查看防火墙信息")
|
||||
print("(100) 开启PHP52显示")
|
||||
print("(101) 关闭PHP52显示")
|
||||
print("(200) 切换Linux系统软件源")
|
||||
print("(201) 简单速度测试")
|
||||
print("(0) 取消")
|
||||
print(raw_tip)
|
||||
try:
|
||||
mw_input = input("请输入命令编号:")
|
||||
if sys.version_info[0] == 3:
|
||||
mw_input = int(mw_input)
|
||||
except:
|
||||
mw_input = 0
|
||||
|
||||
nums = [
|
||||
1, 2, 3, 4, 5, 10, 11, 12, 13,
|
||||
20, 21, 22, 23, 24, 25, 26, 27,
|
||||
100, 101,
|
||||
200, 201
|
||||
]
|
||||
if not mw_input in nums:
|
||||
print(raw_tip)
|
||||
print("已取消!")
|
||||
exit()
|
||||
|
||||
if mw_input == 1:
|
||||
os.system(INIT_CMD + " restart")
|
||||
elif mw_input == 2:
|
||||
os.system(INIT_CMD + " stop")
|
||||
elif mw_input == 3:
|
||||
os.system(INIT_CMD + " start")
|
||||
elif mw_input == 4:
|
||||
os.system(INIT_CMD + " reload")
|
||||
elif mw_input == 5:
|
||||
in_port = mw_input_cmd("请输入新的面板端口:")
|
||||
in_port_int = int(in_port.strip())
|
||||
if in_port_int < 65536 and in_port_int > 0:
|
||||
import firewall_api
|
||||
firewall_api.firewall_api().addAcceptPortArgs(
|
||||
in_port, 'WEB面板[TOOLS修改]', 'port')
|
||||
mw.writeFile('data/port.pl', in_port)
|
||||
os.system(INIT_CMD + " restart_panel")
|
||||
os.system(INIT_CMD + " default")
|
||||
else:
|
||||
print("|-端口范围在0-65536之间")
|
||||
return
|
||||
elif mw_input == 10:
|
||||
os.system(INIT_CMD + " default")
|
||||
elif mw_input == 11:
|
||||
input_pwd = mw_input_cmd("请输入新的面板密码:")
|
||||
if len(input_pwd.strip()) < 5:
|
||||
print("|-错误,密码长度不能小于5位")
|
||||
return
|
||||
set_panel_pwd(input_pwd.strip(), True)
|
||||
elif mw_input == 12:
|
||||
input_user = mw_input_cmd("请输入新的面板用户名(>=5位):")
|
||||
set_panel_username(input_user.strip())
|
||||
elif mw_input == 13:
|
||||
os.system('tail -100 ' + mw.getPanelDir() + '/logs/error.log')
|
||||
elif mw_input == 20:
|
||||
basic_auth = 'data/basic_auth.json'
|
||||
if os.path.exists(basic_auth):
|
||||
os.remove(basic_auth)
|
||||
os.system(INIT_CMD + " restart")
|
||||
print("|-关闭basic_auth成功")
|
||||
elif mw_input == 21:
|
||||
bind_domain = 'data/bind_domain.pl'
|
||||
if os.path.exists(bind_domain):
|
||||
os.remove(bind_domain)
|
||||
os.system(INIT_CMD + " unbind_domain")
|
||||
print("|-解除域名绑定成功")
|
||||
elif mw_input == 22:
|
||||
ssl_choose = 'ssl/choose.pl'
|
||||
if os.path.exists(ssl_choose):
|
||||
os.remove(ssl_choose)
|
||||
os.system(INIT_CMD + " unbind_ssl")
|
||||
print("|-解除面板SSL绑定成功")
|
||||
elif mw_input == 23:
|
||||
listen_ipv6 = 'data/ipv6.pl'
|
||||
if not os.path.exists(listen_ipv6):
|
||||
mw.writeFile(listen_ipv6,'True')
|
||||
os.system(INIT_CMD + " restart")
|
||||
print("|-开启IPv6支持了")
|
||||
else:
|
||||
print("|-已开启IPv6支持!")
|
||||
elif mw_input == 24:
|
||||
listen_ipv6 = 'data/ipv6.pl'
|
||||
if not os.path.exists(listen_ipv6):
|
||||
print("|-已关闭IPv6支持!")
|
||||
else:
|
||||
os.remove(listen_ipv6)
|
||||
os.system(INIT_CMD + " restart")
|
||||
print("|-关闭IPv6支持了")
|
||||
elif mw_input == 25:
|
||||
open_ssh_port()
|
||||
print("|-已开启!")
|
||||
elif mw_input == 26:
|
||||
auth_secret = 'data/auth_secret.pl'
|
||||
if os.path.exists(auth_secret):
|
||||
os.remove(auth_secret)
|
||||
print("|-关闭二次验证成功!")
|
||||
else:
|
||||
print("|-二次验证已关闭!")
|
||||
elif mw_input == 27:
|
||||
cmd = 'which ufw'
|
||||
run_cmd = False
|
||||
find_cmd = mw.execShell(cmd)
|
||||
if find_cmd[0].strip() != '':
|
||||
run_cmd = True
|
||||
os.system('ufw status')
|
||||
|
||||
cmd = 'which firewall-cmd'
|
||||
find_cmd = mw.execShell(cmd)
|
||||
if find_cmd[0].strip() != '':
|
||||
run_cmd = True
|
||||
os.system('firewall-cmd --list-all')
|
||||
if not run_cmd:
|
||||
mw.echoInfo("未检测到防火墙!")
|
||||
elif mw_input == 100:
|
||||
php_conf = 'plugins/php/info.json'
|
||||
if os.path.exists(php_conf):
|
||||
cont = mw.readFile(php_conf)
|
||||
cont = re.sub("\"53\"", "\"52\",\"53\"", cont)
|
||||
cont = re.sub("\"5.3.29\"", "\"5.2.17\",\"5.3.29\"", cont)
|
||||
mw.writeFile(php_conf, cont)
|
||||
print("|-执行PHP52显示成功!")
|
||||
elif mw_input == 101:
|
||||
php_conf = 'plugins/php/info.json'
|
||||
if os.path.exists(php_conf):
|
||||
cont = mw.readFile(php_conf)
|
||||
cont = re.sub("\"52\",", "", cont)
|
||||
cont = re.sub("\"5.2.17\",", cont)
|
||||
mw.writeFile(php_conf, cont)
|
||||
print("|-执行PHP52隐藏成功!")
|
||||
elif mw_input == 200:
|
||||
os.system(INIT_CMD + " mirror")
|
||||
elif mw_input == 201:
|
||||
os.system('curl -Lso- bench.sh | bash')
|
||||
|
||||
|
||||
def open_ssh_port():
|
||||
import firewall_api
|
||||
find_ssh_port_cmd = "cat /etc/ssh/sshd_config | grep '^Port \\d*' | tail -1"
|
||||
cmd_data = mw.execShell(find_ssh_port_cmd)
|
||||
ssh_port = cmd_data[0].replace("Port ", '').strip()
|
||||
if ssh_port == '':
|
||||
ssh_port = '22'
|
||||
|
||||
print("|-SSH端口: "+ str(ssh_port))
|
||||
firewall_api.firewall_api().addAcceptPortArgs(ssh_port, 'SSH远程管理服务', 'port')
|
||||
return True
|
||||
|
||||
|
||||
def set_panel_pwd(password, ncli=False):
|
||||
# 设置面板密码
|
||||
import db
|
||||
sql = db.Sql()
|
||||
result = sql.table('users').where('id=?', (1,)).setField(
|
||||
'password', mw.md5(password))
|
||||
username = sql.table('users').where('id=?', (1,)).getField('username')
|
||||
if ncli:
|
||||
print("|-用户名: " + username)
|
||||
print("|-新密码: " + password)
|
||||
else:
|
||||
print(username)
|
||||
|
||||
|
||||
def show_panel_pwd():
|
||||
# 设置面板密码
|
||||
import db
|
||||
sql = db.Sql()
|
||||
password = sql.table('users').where('id=?', (1,)).getField('password')
|
||||
|
||||
file_pwd = ''
|
||||
if os.path.exists('data/default.pl'):
|
||||
file_pwd = mw.readFile('data/default.pl').strip()
|
||||
|
||||
if mw.md5(file_pwd) == password:
|
||||
print('password: ' + file_pwd)
|
||||
return
|
||||
print("password has been changed!")
|
||||
|
||||
|
||||
def set_panel_username(username=None):
|
||||
# 随机面板用户名
|
||||
import db
|
||||
sql = db.Sql()
|
||||
if username:
|
||||
if len(username) < 5:
|
||||
print("|-错误,用户名长度不能少于5位")
|
||||
return
|
||||
if username in ['admin', 'root']:
|
||||
print("|-错误,不能使用过于简单的用户名")
|
||||
return
|
||||
|
||||
sql.table('users').where('id=?', (1,)).setField('username', username)
|
||||
print("|-新用户名: %s" % username)
|
||||
return
|
||||
|
||||
username = sql.table('users').where('id=?', (1,)).getField('username')
|
||||
if username == 'admin':
|
||||
username = mw.getRandomString(8).lower()
|
||||
sql.table('users').where('id=?', (1,)).setField('username', username)
|
||||
print('username: ' + username)
|
||||
|
||||
|
||||
def getServerIp():
|
||||
version = sys.argv[2]
|
||||
# ip = mw.execShell(
|
||||
# "curl --insecure -{} -sS --connect-timeout 5 -m 60 https://v6r.ipip.net/?format=text".format(version))
|
||||
ip = mw.execShell(
|
||||
"curl --insecure -{} -sS --connect-timeout 5 -m 60 https://ip.cachecha.com/?format=text".format(version))
|
||||
print(ip[0])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
method = sys.argv[1]
|
||||
if method == 'panel':
|
||||
set_panel_pwd(sys.argv[2])
|
||||
elif method == 'username':
|
||||
if len(sys.argv) > 2:
|
||||
set_panel_username(sys.argv[2])
|
||||
else:
|
||||
set_panel_username()
|
||||
elif method == 'password':
|
||||
show_panel_pwd()
|
||||
elif method == 'getServerIp':
|
||||
getServerIp()
|
||||
elif method == "cli":
|
||||
clinum = 0
|
||||
try:
|
||||
if len(sys.argv) > 2:
|
||||
clinum = int(sys.argv[2]) if sys.argv[2][:6] else sys.argv[2]
|
||||
except:
|
||||
clinum = sys.argv[2]
|
||||
mwcli(clinum)
|
||||
else:
|
||||
print('ERROR: Parameter error')
|
||||
@@ -0,0 +1,34 @@
|
||||
CREATE TABLE IF NOT EXISTS `dnsapi` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`name` TEXT,
|
||||
`type` TEXT,
|
||||
`val` TEXT,
|
||||
`remark` TEXT,
|
||||
`addtime` TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `email` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`addr` TEXT,
|
||||
`remark` TEXT,
|
||||
`addtime` TEXT
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `domain` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`domain` TEXT,
|
||||
`dnsapi_id` TEXT,
|
||||
`email` TEXT,
|
||||
`remark` TEXT,
|
||||
`effective_date` TEXT,
|
||||
`expiration_date` TEXT,
|
||||
`error` TEXT,
|
||||
`status` INTEGER default '0',
|
||||
`addtime` TEXT
|
||||
);
|
||||
|
||||
-- ALTER TABLE `domain` ADD COLUMN `effective_date` TEXT DEFAULT '';
|
||||
-- ALTER TABLE `domain` ADD COLUMN `expiration_date` TEXT DEFAULT '';
|
||||
-- ALTER TABLE `domain` ADD COLUMN `error` TEXT DEFAULT '';
|
||||
-- ALTER TABLE `domain` ADD COLUMN `status` INTEGER DEFAULT '0';
|
||||
@@ -0,0 +1,128 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import requests
|
||||
import base64
|
||||
|
||||
|
||||
# 8001 / 7788
|
||||
goedge_addr = 'http://127.0.0.2:8009'
|
||||
access_keyid = "xxx"
|
||||
access_key = "xxx"
|
||||
|
||||
# 指定用户
|
||||
userId = 1
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
domain = sys.argv[1]
|
||||
ssl_path = sys.argv[2]
|
||||
|
||||
|
||||
def getToken():
|
||||
api_url = goedge_addr+'/APIAccessTokenService/getAPIAccessToken'
|
||||
post_data = {
|
||||
"type": "admin",
|
||||
"accessKeyId": access_keyid,
|
||||
"accessKey": access_key
|
||||
}
|
||||
data = requests.post(api_url,json=post_data)
|
||||
data_obj = data.json()
|
||||
|
||||
return data_obj['data']['token']
|
||||
|
||||
token = getToken()
|
||||
|
||||
def commonReq(url, data):
|
||||
headers = {
|
||||
'X-Edge-Access-Token': token
|
||||
}
|
||||
api_url = goedge_addr+url
|
||||
resp_data = requests.post(api_url,json=data, headers=headers)
|
||||
return resp_data.json()
|
||||
|
||||
def listSSLCerts(domain):
|
||||
request_data = {
|
||||
"userId":userId,
|
||||
"isCA":False,
|
||||
"keyword": "ACME泛域名自动上传",
|
||||
"domains":[domain,"*."+domain],
|
||||
"size":1
|
||||
}
|
||||
response_data = commonReq('/SSLCertService/listSSLCerts', request_data)
|
||||
|
||||
data = response_data['data']['sslCertsJSON']
|
||||
data = mw.base64StrDecode(data)
|
||||
data = mw.getObjectByJson(data)
|
||||
# print(data)
|
||||
return data
|
||||
|
||||
|
||||
|
||||
# createSSLCert(domain)
|
||||
def createSSLCert(domain, did=0):
|
||||
|
||||
ssl_cer_file = ssl_path + '/'+domain+'.cer'
|
||||
|
||||
if not os.path.exists(ssl_cer_file):
|
||||
print("没有有效证书!")
|
||||
return ''
|
||||
# print(ssl_cer_file)
|
||||
ssl_info = mw.getCertName(ssl_cer_file)
|
||||
cer_data = mw.readFile(ssl_cer_file)
|
||||
cer_data = mw.base64StrEncode(cer_data)
|
||||
# print('cer',cer_data)
|
||||
|
||||
ssl_key_file = ssl_path + '/'+domain+'.key'
|
||||
key_data = mw.readFile(ssl_key_file)
|
||||
key_data = mw.base64StrEncode(key_data)
|
||||
# print('ssl_info',ssl_info)
|
||||
|
||||
timeBeginAt = int(time.mktime(time.strptime(ssl_info['notBefore'], "%Y-%m-%d")))
|
||||
timeEndAt = int(time.mktime(time.strptime(ssl_info['notAfter'], "%Y-%m-%d")))
|
||||
|
||||
request_data = {
|
||||
"isOn":True,
|
||||
"userId":userId,
|
||||
"name": "ACME泛域名自动上传",
|
||||
"isCA":False,
|
||||
"description":domain,
|
||||
"serverName":domain,
|
||||
"certData":cer_data,
|
||||
"keyData":key_data,
|
||||
"timeBeginAt":timeBeginAt,
|
||||
"timeEndAt": timeEndAt,
|
||||
"dnsNames":[domain,"*."+domain],
|
||||
"commonNames":[ssl_info['issuer']]
|
||||
}
|
||||
|
||||
if did>0:
|
||||
request_data['sslCertId'] = did
|
||||
# print(request_data)
|
||||
response_data = commonReq('/SSLCertService/updateSSLCert', request_data)
|
||||
print('更新成功',domain,response_data)
|
||||
return response_data
|
||||
else:
|
||||
# print(request_data)
|
||||
response_data = commonReq('/SSLCertService/createSSLCert', request_data)
|
||||
print('创建成功',domain,response_data)
|
||||
return response_data
|
||||
return response_data
|
||||
|
||||
def autoSyncDomain(domain):
|
||||
data = listSSLCerts(domain)
|
||||
if len(data) > 0 :
|
||||
did = data[0]['id']
|
||||
createSSLCert(domain,did)
|
||||
else:
|
||||
createSSLCert(domain)
|
||||
print(data)
|
||||
|
||||
|
||||
autoSyncDomain(domain)
|
||||
print(domain,ssl_path)
|
||||
@@ -0,0 +1,12 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
|
||||
domain = sys.argv[1]
|
||||
path = sys.argv[2]
|
||||
|
||||
print(domain,path)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
Executable
+34
@@ -0,0 +1,34 @@
|
||||
<style>
|
||||
.overflow_hide {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="bt-form">
|
||||
<div class='plugin_version'></div>
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<p class="bgw" onclick="pluginService('acme_pandominassl_apply');">服务</p>
|
||||
<p onclick="dnsapiList();">DNSAPI *</p>
|
||||
<p onclick="emailList();">邮件地址 </p>
|
||||
<p onclick="domainList()">域名SSL *</p>
|
||||
<p onclick="pluginConfigTpl('acme_pandominassl_apply',$('.plugin_version').attr('version'));">HOOK</p>
|
||||
<p onclick="pluginLogs('acme_pandominassl_apply','','run_log');">日志</p>
|
||||
<p onclick="apaReadme();">相关说明</p>
|
||||
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
<div class="soft-man-con"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
resetPluginWinWidth(1000);
|
||||
resetPluginWinHeight(550);
|
||||
$.getScript( "/plugins/file?name=acme_pandominassl_apply&f=js/common.js", function(){
|
||||
pluginService('acme_pandominassl_apply', $('.plugin_version').attr('version'));
|
||||
});
|
||||
</script>
|
||||
Executable
+857
@@ -0,0 +1,857 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import requests
|
||||
import json
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'acme_pandominassl_apply'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getInitDFile():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return '/tmp/' + getPluginName()
|
||||
|
||||
if current_os.startswith('freebsd'):
|
||||
return '/etc/rc.d/' + getPluginName()
|
||||
|
||||
return '/etc/init.d/' + getPluginName()
|
||||
|
||||
|
||||
def getConf():
|
||||
path = getServerDir() + "/hook.py"
|
||||
return path
|
||||
|
||||
|
||||
def getInitDTpl():
|
||||
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
|
||||
return path
|
||||
|
||||
def runLog():
|
||||
return getServerDir() + '/hook.log'
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[3:]
|
||||
# print(args)
|
||||
tmp = {}
|
||||
args_len = len(args)
|
||||
|
||||
if args_len == 1:
|
||||
t = args[0].strip('{').strip('}')
|
||||
if t.strip() == '':
|
||||
tmp = []
|
||||
else:
|
||||
t = t.split(':')
|
||||
tmp[t[0]] = t[1]
|
||||
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 getHomeDir():
|
||||
if mw.isAppleSystem():
|
||||
user = mw.execShell(
|
||||
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
|
||||
return '/Users/' + user
|
||||
else:
|
||||
return '/root'
|
||||
|
||||
|
||||
def getRunUser():
|
||||
if mw.isAppleSystem():
|
||||
user = mw.execShell(
|
||||
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
|
||||
return user
|
||||
else:
|
||||
return 'root'
|
||||
|
||||
def configTpl():
|
||||
path = getPluginDir() + '/hooks'
|
||||
pathFile = os.listdir(path)
|
||||
tmp = []
|
||||
for one in pathFile:
|
||||
file = path + '/' + one
|
||||
tmp.append(file)
|
||||
return mw.getJson(tmp)
|
||||
|
||||
|
||||
def readConfigTpl():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
content = mw.readFile(args['file'])
|
||||
content = contentReplace(content)
|
||||
return mw.returnJson(True, 'ok', content)
|
||||
|
||||
def getPidFile():
|
||||
file = getConf()
|
||||
content = mw.readFile(file)
|
||||
rep = r'pidfile\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
return tmp.groups()[0].strip()
|
||||
|
||||
def status():
|
||||
return 'start'
|
||||
|
||||
def contentReplace(content):
|
||||
service_path = mw.getServerDir()
|
||||
content = content.replace('{$ROOT_PATH}', mw.getRootDir())
|
||||
content = content.replace('{$SERVER_PATH}', service_path)
|
||||
content = content.replace('{$SERVER_APP}', service_path + '/redis')
|
||||
content = content.replace('{$REDIS_PASS}', mw.getRandomString(10))
|
||||
return content
|
||||
|
||||
|
||||
def pSqliteDb(dbname='dnsapi'):
|
||||
file = getServerDir() + '/acme.db'
|
||||
name = 'acme'
|
||||
|
||||
import_sql = mw.readFile(getPluginDir() + '/conf/acme.sql')
|
||||
md5_sql = mw.md5(import_sql)
|
||||
|
||||
import_sign = False
|
||||
save_md5_file = getServerDir() + '/acme.md5'
|
||||
if os.path.exists(save_md5_file):
|
||||
save_md5_sql = mw.readFile(save_md5_file)
|
||||
if save_md5_sql != md5_sql:
|
||||
import_sign = True
|
||||
mw.writeFile(save_md5_file, md5_sql)
|
||||
else:
|
||||
mw.writeFile(save_md5_file, md5_sql)
|
||||
|
||||
if not os.path.exists(file) or import_sql:
|
||||
conn = mw.M(dbname).dbPos(getServerDir(), name)
|
||||
csql_list = import_sql.split(';')
|
||||
for index in range(len(csql_list)):
|
||||
conn.execute(csql_list[index], ())
|
||||
|
||||
conn = mw.M(dbname).dbPos(getServerDir(), name)
|
||||
return conn
|
||||
|
||||
def initDreplace():
|
||||
|
||||
file_tpl = getInitDTpl()
|
||||
service_path = os.path.dirname(os.getcwd())
|
||||
|
||||
initD_path = getServerDir() + '/init.d'
|
||||
if not os.path.exists(initD_path):
|
||||
os.mkdir(initD_path)
|
||||
file_bin = initD_path + '/' + getPluginName()
|
||||
|
||||
run_log_file = runLog()
|
||||
if not os.path.exists(run_log_file):
|
||||
mw.writeFile(run_log_file,'')
|
||||
|
||||
hook_file = getConf()
|
||||
if not os.path.exists(hook_file):
|
||||
mw.writeFile(hook_file,'')
|
||||
|
||||
return file_bin
|
||||
|
||||
|
||||
def apaOp(method):
|
||||
file = initDreplace()
|
||||
|
||||
current_os = mw.getOs()
|
||||
if current_os == "darwin":
|
||||
data = mw.execShell(file + ' ' + method)
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
if current_os.startswith("freebsd"):
|
||||
data = mw.execShell('service ' + getPluginName() + ' ' + method)
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
data = mw.execShell('systemctl ' + method + ' ' + getPluginName())
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
|
||||
def start():
|
||||
import tool_cron
|
||||
tool_cron.createBgTask()
|
||||
|
||||
return apaOp('start')
|
||||
|
||||
|
||||
def stop():
|
||||
import tool_cron
|
||||
tool_cron.removeBgTask()
|
||||
return apaOp('stop')
|
||||
|
||||
|
||||
def restart():
|
||||
status = apaOp('restart')
|
||||
return status
|
||||
|
||||
|
||||
def reload():
|
||||
return apaOp('reload')
|
||||
|
||||
|
||||
def dnsapiAdd():
|
||||
conn = pSqliteDb('dnsapi')
|
||||
args = getArgs()
|
||||
data = checkArgs(args,['id','name', 'type', 'remark'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
name = args['name'].strip()
|
||||
remark = args['remark'].strip()
|
||||
stype = args['type'].strip()
|
||||
val = args['val'].strip()
|
||||
sid = args['id'].strip()
|
||||
|
||||
if name == '':
|
||||
return mw.returnJson(False, '名称不能为空!')
|
||||
|
||||
if sid != '0' : #修改操作
|
||||
conn.where("id=?", (sid,)).update({
|
||||
'name':name,
|
||||
'type':stype,
|
||||
'val':val,
|
||||
'remark':remark,
|
||||
})
|
||||
return mw.returnJson(True, '修改成功!')
|
||||
|
||||
if conn.where("name=?", (name,)).count():
|
||||
return mw.returnJson(False, name+'已存在!')
|
||||
|
||||
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
err = conn.add('name,type,val,remark,addtime', (name, stype, val,remark, addTime))
|
||||
# print(err)
|
||||
return mw.returnJson(True, '添加成功!')
|
||||
|
||||
def dnsapiDel():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['id', 'name'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
conn = pSqliteDb('dnsapi')
|
||||
try:
|
||||
sid = args['id']
|
||||
name = args['name']
|
||||
conn.where("id=?", (sid,)).delete()
|
||||
return mw.returnJson(True, '删除成功!')
|
||||
except Exception as ex:
|
||||
return mw.returnJson(False, '删除失败!' + str(ex))
|
||||
|
||||
def dnsapiList():
|
||||
args = getArgs()
|
||||
page = 1
|
||||
page_size = 10
|
||||
search = ''
|
||||
data = {}
|
||||
if 'page' in args:
|
||||
page = int(args['page'])
|
||||
|
||||
if 'page_size' in args:
|
||||
page_size = int(args['page_size'])
|
||||
|
||||
if 'search' in args:
|
||||
search = args['search']
|
||||
|
||||
conn = pSqliteDb('dnsapi')
|
||||
limit = str((page - 1) * page_size) + ',' + str(page_size)
|
||||
condition = ''
|
||||
if not search == '':
|
||||
condition = "name like '%" + search + "%'"
|
||||
field = 'id,name,type,val,remark,addtime'
|
||||
clist = conn.where(condition, ()).field(
|
||||
field).limit(limit).order('id desc').select()
|
||||
|
||||
count = conn.where(condition, ()).count()
|
||||
_page = {}
|
||||
_page['count'] = count
|
||||
_page['p'] = page
|
||||
_page['row'] = page_size
|
||||
_page['tojs'] = 'dbList'
|
||||
data['page'] = mw.getPage(_page)
|
||||
data['data'] = clist
|
||||
|
||||
return mw.getJson(data)
|
||||
|
||||
def dnsapiListAll():
|
||||
conn = pSqliteDb('dnsapi')
|
||||
field = 'id,name,type,val,remark,addtime'
|
||||
data = conn.field(field).limit('1000').select()
|
||||
return mw.getJson(data)
|
||||
|
||||
def emailList():
|
||||
args = getArgs()
|
||||
page = 1
|
||||
page_size = 10
|
||||
search = ''
|
||||
data = {}
|
||||
if 'page' in args:
|
||||
page = int(args['page'])
|
||||
|
||||
if 'page_size' in args:
|
||||
page_size = int(args['page_size'])
|
||||
|
||||
if 'search' in args:
|
||||
search = args['search']
|
||||
|
||||
conn = pSqliteDb('email')
|
||||
limit = str((page - 1) * page_size) + ',' + str(page_size)
|
||||
condition = ''
|
||||
if not search == '':
|
||||
condition = "addr like '%" + search + "%'"
|
||||
field = 'id,addr,remark,addtime'
|
||||
clist = conn.where(condition, ()).field(
|
||||
field).limit(limit).order('id desc').select()
|
||||
|
||||
count = conn.where(condition, ()).count()
|
||||
_page = {}
|
||||
_page['count'] = count
|
||||
_page['p'] = page
|
||||
_page['row'] = page_size
|
||||
_page['tojs'] = 'dbList'
|
||||
data['page'] = mw.getPage(_page)
|
||||
data['data'] = clist
|
||||
|
||||
return mw.getJson(data)
|
||||
|
||||
def emailAdd():
|
||||
args = getArgs()
|
||||
data = checkArgs(args,['addr', 'remark'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
addr = args['addr'].strip()
|
||||
remark = args['remark'].strip()
|
||||
|
||||
if addr == '':
|
||||
return mw.returnJson(False, '邮件地址不能为空!')
|
||||
|
||||
conn = pSqliteDb('email')
|
||||
|
||||
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
conn.add('addr,remark,addtime', (addr, remark, addTime))
|
||||
return mw.returnJson(True, '添加成功!')
|
||||
|
||||
def emailDel():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['id', 'name'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
conn = pSqliteDb('email')
|
||||
try:
|
||||
sid = args['id']
|
||||
name = args['name']
|
||||
conn.where("id=?", (sid,)).delete()
|
||||
return mw.returnJson(True, '删除成功!')
|
||||
except Exception as ex:
|
||||
return mw.returnJson(False, '删除失败!' + str(ex))
|
||||
|
||||
def domainAdd():
|
||||
args = getArgs()
|
||||
data = checkArgs(args,['id','domain', 'dnsapi_id','email','remark'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
sid = args['id'].strip()
|
||||
domain = args['domain'].strip()
|
||||
remark = args['remark'].strip()
|
||||
email = args['email'].strip()
|
||||
dnsapi_id = args['dnsapi_id'].strip()
|
||||
|
||||
if domain == '':
|
||||
return mw.returnJson(False, '域名不能为空!')
|
||||
if email == '':
|
||||
return mw.returnJson(False, '邮件不能为空!')
|
||||
|
||||
conn = pSqliteDb('domain')
|
||||
|
||||
if sid != '0' : #修改操作
|
||||
conn.where("id=?", (sid,)).update({
|
||||
'domain':domain,
|
||||
'dnsapi_id':dnsapi_id,
|
||||
'email':email,
|
||||
'remark':remark,
|
||||
})
|
||||
return mw.returnJson(True, '修改成功!')
|
||||
|
||||
if conn.where("domain=?", (domain,)).count():
|
||||
return mw.returnJson(False, domain+'已存在!')
|
||||
|
||||
|
||||
|
||||
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
conn.add('domain,dnsapi_id,email,remark,addtime', (domain, dnsapi_id,email,remark, addTime))
|
||||
return mw.returnJson(True, '添加成功!')
|
||||
|
||||
def domainDel():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['id', 'name'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
conn = pSqliteDb('domain')
|
||||
try:
|
||||
sid = args['id']
|
||||
name = args['name']
|
||||
conn.where("id=?", (sid,)).delete()
|
||||
return mw.returnJson(True, '删除成功!')
|
||||
except Exception as ex:
|
||||
return mw.returnJson(False, '删除失败!' + str(ex))
|
||||
|
||||
def domainStatusToggle():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['id'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
conn = pSqliteDb('domain')
|
||||
|
||||
field = 'id,status'
|
||||
fdata = conn.field(field).where('id=?',(args['id'],)).find()
|
||||
|
||||
fstatus = fdata['status']
|
||||
if fstatus == 0:
|
||||
fstatus = 1
|
||||
else:
|
||||
fstatus = 0
|
||||
# print(fdata['status'],fstatus)
|
||||
conn.where("id=?", (args['id'],)).update({
|
||||
'status':fstatus,
|
||||
})
|
||||
return mw.returnJson(True, '切换成功!')
|
||||
|
||||
def domainList():
|
||||
args = getArgs()
|
||||
page = 1
|
||||
page_size = 10
|
||||
search = ''
|
||||
data = {}
|
||||
if 'page' in args:
|
||||
page = int(args['page'])
|
||||
|
||||
if 'page_size' in args:
|
||||
page_size = int(args['page_size'])
|
||||
|
||||
if 'search' in args:
|
||||
search = args['search']
|
||||
|
||||
conn = pSqliteDb('domain')
|
||||
conn_dnsapi = pSqliteDb('dnsapi')
|
||||
limit = str((page - 1) * page_size) + ',' + str(page_size)
|
||||
condition = ''
|
||||
if not search == '':
|
||||
condition = "domain like '%" + search + "%'"
|
||||
field = 'id,domain,dnsapi_id,email,status,effective_date,expiration_date,remark,addtime'
|
||||
clist = conn.where(condition, ()).field(
|
||||
field).limit(limit).order('id desc').select()
|
||||
|
||||
for i in range(len(clist)):
|
||||
tdata = conn_dnsapi.field('id,name').where('id=?',(clist[i]['dnsapi_id'],)).select()
|
||||
if len(tdata) > 0:
|
||||
# print(tdata[0]['name'])
|
||||
clist[i]['dnsapi_id_alias'] = clist[i]['dnsapi_id']+'('+ tdata[0]['name'] +')'
|
||||
else:
|
||||
clist[i]['dnsapi_id_alias'] = clist[i]['dnsapi_id']+' (无)'
|
||||
|
||||
count = conn.where(condition, ()).count()
|
||||
_page = {}
|
||||
_page['count'] = count
|
||||
_page['p'] = page
|
||||
_page['row'] = page_size
|
||||
_page['tojs'] = 'dbList'
|
||||
data['page'] = mw.getPage(_page)
|
||||
data['data'] = clist
|
||||
|
||||
return mw.getJson(data)
|
||||
|
||||
def getDnsapiData(dnsapi_id):
|
||||
if dnsapi_id == '0':
|
||||
return {}
|
||||
conn_dnsapi = pSqliteDb('dnsapi')
|
||||
tdata = conn_dnsapi.field('id,name,type,val').where('id=?',(dnsapi_id,)).select()
|
||||
|
||||
if len(tdata)>0:
|
||||
return tdata[0]
|
||||
return {}
|
||||
|
||||
def getDnsapiExportVar(val):
|
||||
cmd_list = val.split('~')
|
||||
def_var = ''
|
||||
for x in range(len(cmd_list)):
|
||||
v = cmd_list[x]
|
||||
vlist = v.split('|')
|
||||
def_var += 'export '+vlist[0]+'="'+vlist[1]+'"\n'
|
||||
return def_var
|
||||
|
||||
def getDnsapiKv(val):
|
||||
cmd_list = val.split('~')
|
||||
def_var = {}
|
||||
for x in range(len(cmd_list)):
|
||||
v = cmd_list[x]
|
||||
vlist = v.split('|')
|
||||
kk = vlist[0]
|
||||
vv = vlist[1]
|
||||
def_var[kk] = vv
|
||||
return def_var
|
||||
|
||||
def domainApplyPathJudge(domain):
|
||||
acme_dir = "/root/.acme.sh"
|
||||
if mw.isAppleSystem():
|
||||
user = getRunUser()
|
||||
acme_dir = "/Users/"+user+"/.acme.sh"
|
||||
|
||||
abs_domain_path = acme_dir+'/'+domain+'_ecc'
|
||||
# print(abs_domain_path)
|
||||
if os.path.exists(abs_domain_path):
|
||||
return True, abs_domain_path
|
||||
|
||||
abs_domain_path = acme_dir+'/'+domain
|
||||
# print(abs_domain_path)
|
||||
if os.path.exists(abs_domain_path):
|
||||
return True, abs_domain_path
|
||||
|
||||
return False,''
|
||||
|
||||
|
||||
def hookWriteLog(line):
|
||||
hook_file = runLog()
|
||||
mdate = time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
log = "["+mdate+"]:"+line
|
||||
print(log)
|
||||
return mw.writeFile(hook_file,log+"\n",'a+')
|
||||
|
||||
def runHookPy(domain,path):
|
||||
# print(domain,path)
|
||||
run_log = runLog()
|
||||
hook_file = getConf()
|
||||
cmd = 'cd '+mw.getRunDir()
|
||||
cmd += ' && python3 '+hook_file + ' ' + domain + ' ' + path
|
||||
cmd += ' >> '+ run_log
|
||||
print(cmd)
|
||||
return mw.execShell(cmd)
|
||||
|
||||
def autoUpdateSslData(domain, path):
|
||||
ssl_cer_file = path + '/'+domain+'.cer'
|
||||
ssl_info = mw.getCertName(ssl_cer_file)
|
||||
|
||||
time_begin = int(time.mktime(time.strptime(ssl_info['notBefore'], "%Y-%m-%d")))
|
||||
time_end = int(time.mktime(time.strptime(ssl_info['notAfter'], "%Y-%m-%d")))
|
||||
# print(ssl_info)
|
||||
# print(time_begin,time_end)
|
||||
conn = pSqliteDb('domain')
|
||||
conn.where('domain=?', (domain,)).update({
|
||||
'effective_date':str(time_begin),
|
||||
'expiration_date':str(time_end),
|
||||
})
|
||||
|
||||
return True
|
||||
|
||||
def runHookDstDomain(row):
|
||||
domain = row['domain']
|
||||
email = str(row['email'])
|
||||
|
||||
if row['effective_date'] != '':
|
||||
effective_date = int(row['effective_date'])
|
||||
now_int = int(time.time())
|
||||
day = (now_int - effective_date)/86400
|
||||
if int(day) < 8:
|
||||
common_log = '【'+domain+'】未过期'
|
||||
hookWriteLog(common_log)
|
||||
return
|
||||
|
||||
hookWriteLog('开始申请【'+domain+'】SSL证书')
|
||||
cmd = "#!/bin/bash\n"
|
||||
|
||||
if mw.isAppleSystem():
|
||||
user = getRunUser()
|
||||
cmd += "source /Users/"+user+"/.zshrc\n"
|
||||
|
||||
cmd_data = getDnsapiData(row['dnsapi_id'])
|
||||
# print(cmd_data)
|
||||
export_val = getDnsapiExportVar(cmd_data['val'])
|
||||
cmd += export_val
|
||||
|
||||
# acme.sh --register-account -m my@example.com
|
||||
cmd_register = 'acme.sh --register-account -m '+ email + '\n'
|
||||
cmd += cmd_register
|
||||
|
||||
|
||||
# acme.sh --issue -d "example.com" -d "*.example.com" --dns dns_cf
|
||||
cmd_apply = 'acme.sh --issue --dns '+str(cmd_data['type'])+' -d '+domain+' -d "*.'+domain+'"'
|
||||
if row['effective_date'] != '':
|
||||
effective_date = int(row['effective_date'])
|
||||
now_int = int(time.time())
|
||||
day = (now_int - effective_date)/86400
|
||||
if int(day) > 7:
|
||||
cmd_apply = 'acme.sh --issue --dns '+str(cmd_data['type'])+' -d '+domain+' -d "*.'+domain+'" --force'
|
||||
cmd += cmd_apply
|
||||
|
||||
run_log = runLog()
|
||||
cmd += ' >> '+ run_log
|
||||
print(cmd)
|
||||
os.system(cmd)
|
||||
hookWriteLog('结束申请【'+domain+'】SSL证书')
|
||||
isok, path = domainApplyPathJudge(domain)
|
||||
print(isok,path)
|
||||
if isok:
|
||||
autoUpdateSslData(domain, path)
|
||||
hookWriteLog('开始执行【'+domain+'】Hook脚本')
|
||||
runHookPy(domain,path)
|
||||
hookWriteLog('结束执行【'+domain+'】Hook脚本')
|
||||
|
||||
def getHookIdCmd():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['id'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
cmd = "cd "+mw.getRunDir()+" "
|
||||
cmd += '&& python3 plugins/acme_pandominassl_apply/index.py run_hook_id 1.0 {"id":"'+args['id']+'"}'
|
||||
return mw.returnJson(True, 'ok',cmd)
|
||||
|
||||
def runHookId():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['id'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
conn = pSqliteDb('domain')
|
||||
field = 'id,domain,dnsapi_id,email,effective_date,expiration_date,remark'
|
||||
row = conn.field(field).where('id=?',(args['id'],)).find()
|
||||
runHookDstDomain(row)
|
||||
return 'run hook '+args['id']+' end'
|
||||
|
||||
def runHookCmd():
|
||||
cmd = "cd "+mw.getRunDir()+" "
|
||||
cmd += '&& python3 plugins/acme_pandominassl_apply/index.py run_hook'
|
||||
return mw.returnJson(True, 'ok',cmd)
|
||||
|
||||
def runHook():
|
||||
conn = pSqliteDb('domain')
|
||||
|
||||
field = 'id,domain,dnsapi_id,email,effective_date,expiration_date,remark'
|
||||
clist = conn.field(field).where('status=?',(1,)).limit('1000').order('id desc').select()
|
||||
|
||||
for idx in range(len(clist)):
|
||||
row = clist[idx]
|
||||
# print(row)
|
||||
runHookDstDomain(row)
|
||||
time.sleep(1)
|
||||
return 'run hook end'
|
||||
|
||||
def autoSyncDomain(domain, dnsapi_id, email):
|
||||
conn = pSqliteDb('domain')
|
||||
|
||||
field = 'id,domain,dnsapi_id,email,effective_date,expiration_date,remark'
|
||||
fdata = conn.field(field).where('domain=?',(domain,)).select()
|
||||
# print(fdata)
|
||||
mdate = time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
if len(fdata) == 0:
|
||||
conn.add('domain,dnsapi_id,email,remark,addtime', (domain, dnsapi_id, email,"备注", mdate))
|
||||
print(domain+" 同步成功!")
|
||||
return True
|
||||
|
||||
def runSyncCfDataRow(row, page = 1):
|
||||
# print(row, page)
|
||||
|
||||
cf_key = row['kv']['CF_Key']
|
||||
cf_mail = row['kv']['CF_Email']
|
||||
header = {
|
||||
'X-Auth-Email': cf_mail,
|
||||
'X-Auth-Key': cf_key,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
url = "https://api.cloudflare.com/client/v4/zones?status=active&page="+str(page)+"&per_page=20&order=status&direction=desc&match=all"
|
||||
try:
|
||||
r = requests.get(url, timeout=30, headers=header)
|
||||
r.raise_for_status()
|
||||
r.encoding = r.apparent_encoding
|
||||
# print(r.text)
|
||||
jdata = json.loads(r.text)
|
||||
result = jdata['result']
|
||||
result_info = jdata['result_info']
|
||||
|
||||
# print(len(result))
|
||||
for i in result:
|
||||
autoSyncDomain(i['name'], row['id'], cf_mail)
|
||||
|
||||
if result_info['total_pages'] > page:
|
||||
page += 1
|
||||
runSyncCfDataRow(row, page)
|
||||
# print(result)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
# 同步CloudFlare数据
|
||||
def runSyncCfData():
|
||||
print("同步CloudFlare数据开始")
|
||||
conn_dnsapi = pSqliteDb('dnsapi')
|
||||
field = "id,name,type,val"
|
||||
fdata = conn_dnsapi.field(field).where('type=?', ('dns_cf',)).limit('10').select()
|
||||
|
||||
for x in range(len(fdata)):
|
||||
row = fdata[x]
|
||||
dnsapi_kv = getDnsapiKv(row['val'])
|
||||
row['kv'] = dnsapi_kv
|
||||
runSyncCfDataRow(row)
|
||||
|
||||
print("同步CloudFlare数据结束")
|
||||
return ''
|
||||
|
||||
def runSyncCfCmd():
|
||||
cmd = "cd "+mw.getRunDir()+" "
|
||||
cmd += '&& python3 plugins/acme_pandominassl_apply/index.py run_sync_cf_data'
|
||||
return mw.returnJson(True, 'ok',cmd)
|
||||
|
||||
def runSyncDnspodDataRow(row, page = 1):
|
||||
# print(row, page)
|
||||
|
||||
DPI_Id = row['kv']['DPI_Id']
|
||||
DPI_Key = row['kv']['DPI_Key']
|
||||
data = {
|
||||
'login_token': DPI_Id+','+DPI_Key,
|
||||
'length':5,
|
||||
'format':'json',
|
||||
}
|
||||
url = "https://api.dnspod.com/Domain.List"
|
||||
try:
|
||||
r = requests.post(url, timeout=30, data=data)
|
||||
r.raise_for_status()
|
||||
r.encoding = r.apparent_encoding
|
||||
|
||||
# print(r.text)
|
||||
jdata = json.loads(r.text)
|
||||
info = jdata['info']
|
||||
domains = jdata['domains']
|
||||
|
||||
# print(jdata)
|
||||
for i in domains:
|
||||
autoSyncDomain(i['name'], row['id'], i['owner'])
|
||||
|
||||
page_total = int(info['domain_total']/data['length'])
|
||||
if page_total > page:
|
||||
page += 1
|
||||
runSyncDnspodDataRow(row, page)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
# 同步DnsPod数据
|
||||
def runSyncDnsPodData():
|
||||
print("同步DnsPod数据开始")
|
||||
conn_dnsapi = pSqliteDb('dnsapi')
|
||||
field = "id,name,type,val"
|
||||
fdata = conn_dnsapi.field(field).where('type=?', ('dns_dpi',)).limit('10').select()
|
||||
for x in range(len(fdata)):
|
||||
row = fdata[x]
|
||||
dnsapi_kv = getDnsapiKv(row['val'])
|
||||
row['kv'] = dnsapi_kv
|
||||
runSyncDnspodDataRow(row)
|
||||
|
||||
print(fdata)
|
||||
print("同步DnsPod数据结束")
|
||||
return ''
|
||||
|
||||
def runSyncDnsPodCmd():
|
||||
cmd = "cd "+mw.getRunDir()+" "
|
||||
cmd += '&& python3 plugins/acme_pandominassl_apply/index.py run_sync_dnspod_data'
|
||||
return mw.returnJson(True, 'ok',cmd)
|
||||
|
||||
if __name__ == "__main__":
|
||||
func = sys.argv[1]
|
||||
# print(func)
|
||||
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 == 'run_info':
|
||||
print(runInfo())
|
||||
elif func == 'conf':
|
||||
print(getConf())
|
||||
elif func == 'run_log':
|
||||
print(runLog())
|
||||
elif func == 'config_tpl':
|
||||
print(configTpl())
|
||||
elif func == 'read_config_tpl':
|
||||
print(readConfigTpl())
|
||||
elif func == 'dnsapi_list':
|
||||
print(dnsapiList())
|
||||
elif func == 'dnsapi_list_all':
|
||||
print(dnsapiListAll())
|
||||
elif func == 'dnsapi_add':
|
||||
print(dnsapiAdd())
|
||||
elif func == 'dnsapi_del':
|
||||
print(dnsapiDel())
|
||||
elif func == 'email_list':
|
||||
print(emailList())
|
||||
elif func == 'email_add':
|
||||
print(emailAdd())
|
||||
elif func == 'email_del':
|
||||
print(emailDel())
|
||||
elif func == 'domain_list':
|
||||
print(domainList())
|
||||
elif func == 'domain_add':
|
||||
print(domainAdd())
|
||||
elif func == 'domain_del':
|
||||
print(domainDel())
|
||||
elif func == 'domain_status_toggle':
|
||||
print(domainStatusToggle())
|
||||
elif func == 'run_hook':
|
||||
print(runHook())
|
||||
elif func == 'run_hook_cmd':
|
||||
print(runHookCmd())
|
||||
elif func == 'get_run_hook_id_cmd':
|
||||
print(getHookIdCmd())
|
||||
elif func == 'run_hook_id':
|
||||
print(runHookId())
|
||||
elif func == 'run_sync_cf_data':
|
||||
print(runSyncCfData())
|
||||
elif func == 'run_sync_cf_cmd':
|
||||
print(runSyncCfCmd())
|
||||
elif func == 'run_sync_dnspod_data':
|
||||
print(runSyncDnsPodData())
|
||||
elif func == 'run_sync_dnspod_cmd':
|
||||
print(runSyncDnsPodCmd())
|
||||
else:
|
||||
print('error')
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"sort": 7,
|
||||
"ps": "ACME泛域名SSL申请/管理",
|
||||
"name": "acme_pandominassl_apply",
|
||||
"title": "ACME泛域名SSL",
|
||||
"shell": "install.sh",
|
||||
"versions":["1.0"],
|
||||
"tip": "soft",
|
||||
"checks": "server/acme_pandominassl_apply",
|
||||
"path": "server/acme_pandominassl_apply",
|
||||
"display": 1,
|
||||
"author": "ACME",
|
||||
"date": "2024-09-12",
|
||||
"home": "https://github.com/acmesh-official/acme.sh",
|
||||
"type": 0,
|
||||
"pid": "5"
|
||||
}
|
||||
Executable
+55
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=$2
|
||||
|
||||
# curl https://get.acme.sh | sh
|
||||
# acme.sh --uninstall
|
||||
|
||||
|
||||
# source /Users/xxx/.zshrc
|
||||
|
||||
# https://github.com/acmesh-official/acme.sh/wiki/dnsapi
|
||||
# https://docs.dnspod.com/api-legacy/domains.html#get-the-domain-list
|
||||
|
||||
# cd /www/server/mdserver-web && python3 plugins/acme_pandominassl_apply/index.py run_hook
|
||||
# cd /www/server/mdserver-web && python3 plugins/acme_pandominassl_apply/index.py run_sync_cf_data
|
||||
# cd /www/server/mdserver-web && python3 plugins/acme_pandominassl_apply/index.py run_sync_dnspod_data
|
||||
|
||||
|
||||
if [ -f ${rootPath}/bin/activate ];then
|
||||
source ${rootPath}/bin/activate
|
||||
fi
|
||||
|
||||
# pip install cloudflare
|
||||
Install_App()
|
||||
{
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
mkdir -p $serverPath/source
|
||||
mkdir -p $serverPath/acme_pandominassl_apply
|
||||
echo "${VERSION}" > $serverPath/acme_pandominassl_apply/version.pl
|
||||
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/acme_pandominassl_apply/index.py start
|
||||
echo '安装[ACME泛域名SSL]完成'
|
||||
}
|
||||
|
||||
Uninstall_App()
|
||||
{
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/acme_pandominassl_apply/index.py stop
|
||||
rm -rf $serverPath/acme_pandominassl_apply
|
||||
echo "卸载[ACME泛域名SSL]成功"
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_App
|
||||
else
|
||||
Uninstall_App
|
||||
fi
|
||||
Executable
+792
@@ -0,0 +1,792 @@
|
||||
function apaPost(method, args,callback){
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
|
||||
var req_data = {};
|
||||
req_data['name'] = 'acme_pandominassl_apply';
|
||||
req_data['func'] = method;
|
||||
req_data['version'] = $('.plugin_version').attr('version');
|
||||
|
||||
if (typeof(args) == 'string'){
|
||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
req_data['args'] = JSON.stringify(args);
|
||||
}
|
||||
|
||||
$.post('/plugins/run', req_data, function(data) {
|
||||
layer.close(loadT);
|
||||
if (!data.status){
|
||||
//错误展示10S
|
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof(callback) == 'function'){
|
||||
callback(data);
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
|
||||
|
||||
function apaPostN(method, args,callback){
|
||||
|
||||
var req_data = {};
|
||||
req_data['name'] = 'acme_pandominassl_apply';
|
||||
req_data['func'] = method;
|
||||
req_data['version'] = $('.plugin_version').attr('version');
|
||||
|
||||
if (typeof(args) == 'string'){
|
||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
req_data['args'] = JSON.stringify(args);
|
||||
}
|
||||
|
||||
$.post('/plugins/run', req_data, function(data) {
|
||||
if (!data.status){
|
||||
//错误展示10S
|
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof(callback) == 'function'){
|
||||
callback(data);
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
|
||||
function apaPostCallbak(method, version, args,callback){
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
|
||||
var req_data = {};
|
||||
req_data['name'] = 'acme_pandominassl_apply';
|
||||
req_data['func'] = method;
|
||||
args['version'] = version;
|
||||
|
||||
if (typeof(args) == 'string'){
|
||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
req_data['args'] = JSON.stringify(args);
|
||||
}
|
||||
|
||||
$.post('/plugins/callback', req_data, 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 apaReadme(){
|
||||
var readme = '<ul class="help-info-text c7">';
|
||||
readme += '<li>ACME泛域名SSL申请/管理/HOOK</li>';
|
||||
readme += '<li>通过DNS验证获取SSL证书!</li>';
|
||||
readme += '<li>HOOK: ssl发生变动时调用!</li>';
|
||||
readme += '<li>暂时仅支持1000个域名管理!</li>';
|
||||
readme += '<li>DNSAPI文档: https://github.com/acmesh-official/acme.sh/wiki/dnsapi</li>';
|
||||
readme += '<li>默认7天强制更新!</li>';
|
||||
|
||||
|
||||
readme += '</ul>';
|
||||
$('.soft-man-con').html(readme);
|
||||
}
|
||||
|
||||
|
||||
function emailDel(id, name){
|
||||
safeMessage('删除['+name+']','您真的要删除['+name+']吗?',function(){
|
||||
var data='id='+id+'&name='+name;
|
||||
apaPost('email_del', data, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
emailList();
|
||||
},{icon: rdata.status ? 1 : 2}, 600);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function emailAdd(type){
|
||||
layer.open({
|
||||
type: 1,
|
||||
area: '500px',
|
||||
title: '添加邮件地址',
|
||||
closeBtn: 1,
|
||||
shift: 5,
|
||||
shadeClose: true,
|
||||
btn:["提交","关闭"],
|
||||
content: "<form class='bt-form pd20' id='email_add'>\
|
||||
<div class='line'>\
|
||||
<span class='tname'>邮件地址</span>\
|
||||
<div class='info-r'><input name='addr' class='bt-input-text mr5' style='width:100%;' placeholder='邮件地址' type='text'></div>\
|
||||
</div>\
|
||||
<div class='line'>\
|
||||
<span class='tname'>备注</span>\
|
||||
<div class='info-r'><input name='remark' class='bt-input-text mr5' style='width:100%;' placeholder='备注' type='text'></div>\
|
||||
</div>\
|
||||
</form>",
|
||||
success:function(){
|
||||
$("input[name='addr']").keyup(function(){
|
||||
var v = $(this).val();
|
||||
$("input[name='remark']").val(v);
|
||||
});
|
||||
},
|
||||
yes:function(index) {
|
||||
var data = $("#email_add").serialize();
|
||||
data = decodeURIComponent(data);
|
||||
// data = toArrayObject(data);
|
||||
apaPost('email_add', data, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
if (rdata.status){
|
||||
layer.close(index);
|
||||
emailList();
|
||||
}
|
||||
},{icon: rdata.status ? 1 : 2}, 2000);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function emailList(page, search){
|
||||
var _data = {};
|
||||
if (typeof(page) =='undefined'){
|
||||
var page = 1;
|
||||
}
|
||||
|
||||
_data['page'] = page;
|
||||
_data['page_size'] = 10;
|
||||
if(typeof(search) != 'undefined'){
|
||||
_data['search'] = search;
|
||||
}
|
||||
|
||||
apaPost('email_list', _data, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
var list = '';
|
||||
for(i in rdata.data){
|
||||
list += '<tr>';
|
||||
list +='<td><input value="'+rdata.data[i]['id']+'" class="check" onclick="checkSelect();" type="checkbox"></td>';
|
||||
list += '<td>' + rdata.data[i]['addr'] +'</td>';
|
||||
list += '<td>' + rdata.data[i]['remark'] +'</td>';
|
||||
list += '<td style="text-align:right">';
|
||||
list += '<a href="javascript:;" class="btlink" onclick="emailDel(\''+rdata.data[i]['id']+'\',\''+rdata.data[i]['addr']+'\')" title="删除">删除</a>' +
|
||||
'</td>';
|
||||
list += '</tr>';
|
||||
}
|
||||
|
||||
var con = '<div class="safe bgw">\
|
||||
<button onclick="emailAdd()" title="添加邮件地址" class="btn btn-success btn-sm" type="button" style="margin-right: 5px;">添加邮件地址</button>\
|
||||
<span style="float:right"> \
|
||||
<button batch="true" style="float: right;display: none;margin-left:10px;" onclick="delDbBatch();" title="删除选中项" class="btn btn-default btn-sm">删除选中</button>\
|
||||
</span>\
|
||||
<div class="divtable mtb10">\
|
||||
<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 width="30"><input class="check" onclick="checkSelect();" type="checkbox"></th>\
|
||||
<th>邮件地址</th>\
|
||||
<th>备注</th>\
|
||||
<th style="text-align:right;">操作</th></tr></thead>\
|
||||
<tbody>'+ list +'</tbody>\
|
||||
</table>\
|
||||
</div>\
|
||||
<div class="dataTables_paginate paging_bootstrap page"></div>\
|
||||
</div>\
|
||||
</div>';
|
||||
|
||||
$(".soft-man-con").html(con);
|
||||
$('.dataTables_paginate').html(rdata.page);
|
||||
|
||||
readerTableChecked();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function dnsapiDel(id, name){
|
||||
safeMessage('删除['+name+']','您真的要删除['+name+']吗?',function(){
|
||||
var data='id='+id+'&name='+name;
|
||||
apaPost('dnsapi_del', data, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
dnsapiList();
|
||||
},{icon: rdata.status ? 1 : 2}, 600);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var dnsapi_option = [
|
||||
{"name":"dns_cf", "title":'cloudflare', 'key':'CF_Key:CF_Email'},
|
||||
{"name":"dns_dp", "title":'dnspod/国内', 'key':'DP_Id:DP_Key'},
|
||||
{"name":"dns_dpi", "title":'dnspod/国际', 'key':'DPI_Id:DPI_Key'},
|
||||
{"name":"dns_gd", "title":'GoDaddy', 'key':'GD_Key:GD_Secret'},
|
||||
{"name":"dns_pdns", "title":'PowerDNS', 'key':'PDNS_Url:PDNS_ServerId:PDNS_Token:PDNS_Ttl'},
|
||||
{"name":"dns_lua", "title":'LuaDNS', 'key':'LUA_Key:LUA_Email'},
|
||||
{"name":"dns_me", "title":'DNSMadeEasy', 'key':'ME_Key:ME_Secret'},
|
||||
{"name":"dns_aws", "title":'Amazon Route53', 'key':'AWS_ACCESS_KEY_ID:AWS_SECRET_ACCESS_KEY'},
|
||||
{"name":"dns_ali", "title":'Aliyun', 'key':'Ali_Key:Ali_Secret'},
|
||||
{"name":"dns_ispconfig", "title":'ISPConfig', 'key':'ISPC_User:ISPC_Password:ISPC_Api:ISPC_Api_Insecure'},
|
||||
{"name":"dns_ad", "title":'Alwaysdata', 'key':'AD_API_KEY'},
|
||||
{"name":"dns_linode_v4", "title":'Linode', 'key':'LINODE_V4_API_KEY'},
|
||||
{"name":"dns_freedns", "title":'FreeDNS', 'key':'FREEDNS_User:FREEDNS_Password'},
|
||||
{"name":"dns_cyon", "title":'cyon.ch', 'key':'CY_Username:CY_Password:CY_OTP_Secret'},
|
||||
{"name":"dns_gandi_livedns", "title":'LiveDNS', 'key':'GANDI_LIVEDNS_TOKEN'},
|
||||
{"name":"dns_knot", "title":'Knot', 'key':'KNOT_SERVER:KNOT_KEY'},
|
||||
{"name":"dns_dgon", "title":'DigitalOcean', 'key':'DO_API_KEY'},
|
||||
{"name":"dns_cloudns", "title":'ClouDNS.net', 'key':'CLOUDNS_SUB_AUTH_ID:CLOUDNS_AUTH_PASSWORD'},
|
||||
{"name":"dns_namesilo", "title":'Namesilo', 'key':'Namesilo_Key'},
|
||||
{"name":"dns_azure", "title":'Azure', 'key':'AZUREDNS_SUBSCRIPTIONID:AZUREDNS_TENANTID:AZUREDNS_APPID:AZUREDNS_CLIENTSECRET'},
|
||||
{"name":"dns_selectel", "title":'selectel.com', 'key':'SL_Key'},
|
||||
{"name":"dns_zonomi", "title":'zonomi.com', 'key':'ZM_Key'},
|
||||
{"name":"dns_kinghost", "title":'KingHost', 'key':'KINGHOST_Username:KINGHOST_Password'},
|
||||
{"name":"dns_zilore", "title":'Zilore', 'key':'Zilore_Key'},
|
||||
{"name":"dns_gcloud", "title":'Google Cloud DNS', 'key':'CLOUDSDK_ACTIVE_CONFIG_NAME'},
|
||||
{"name":"dns_mydnsjp", "title":'MyDNS.JP', 'key':'MYDNSJP_MasterID:MYDNSJP_Password'},
|
||||
{"name":"dns_doapi", "title":'do.de', 'key':'DO_LETOKEN'},
|
||||
{"name":"dns_online", "title":'Online', 'key':'ONLINE_API_KEY'},
|
||||
{"name":"dns_cn", "title":'Core-Networks', 'key':'CN_User:CN_Password'},
|
||||
{"name":"dns_ultra", "title":'UltraDNS', 'key':'ULTRA_USR:ULTRA_PWD'},
|
||||
{"name":"dns_hetzner", "title":'Hetzner', 'key':'HETZNER_Token'},
|
||||
{"name":"dns_ddnss", "title":'DDNSS.de', 'key':'DDNSS_Token'},
|
||||
];
|
||||
|
||||
function getDnsapiKey(name){
|
||||
for (var i = 0; i < dnsapi_option.length; i++) {
|
||||
if (dnsapi_option[i]['name'] == name){
|
||||
return dnsapi_option[i]['key'];
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function getDnsapiTitle(name){
|
||||
for (var i = 0; i < dnsapi_option.length; i++) {
|
||||
if (dnsapi_option[i]['name'] == name){
|
||||
return dnsapi_option[i]['title'];
|
||||
}
|
||||
}
|
||||
return '其他';
|
||||
}
|
||||
|
||||
|
||||
|
||||
function dnsapiAdd(row){
|
||||
// console.log(row);
|
||||
var option_name = '';
|
||||
var option_remark = '';
|
||||
var option_type = 'cf';
|
||||
var option_val = '';
|
||||
var option_id = 0;
|
||||
if (typeof(row) != 'undefined'){
|
||||
option_name = row['name'];
|
||||
option_remark = row['remark'];
|
||||
option_type = row['type'];
|
||||
option_val = row['val'];
|
||||
option_id = row['id'];
|
||||
|
||||
}
|
||||
|
||||
// console.log(option_name);
|
||||
function renderDnsapiOption(name, val){
|
||||
var vlist = {};
|
||||
if (val != ''){
|
||||
var t = val.split('~');
|
||||
for (var i = 0; i < t.length; i++) {
|
||||
var kv = t[i].split('|');
|
||||
if (kv.length == 2){
|
||||
vlist[kv[0]] = kv[1];
|
||||
} else {
|
||||
vlist[kv[0]] = '';
|
||||
}
|
||||
}
|
||||
// console.log(vlist);
|
||||
}
|
||||
|
||||
|
||||
var key = getDnsapiKey(name);
|
||||
var klist = key.split(':');
|
||||
// console.log(klist);
|
||||
var option_html = '';
|
||||
for (var i = 0; i < klist.length; i++) {
|
||||
var klist_val = '';
|
||||
if (klist[i] in vlist){
|
||||
klist_val = vlist[klist[i]];
|
||||
}
|
||||
|
||||
option_html += "\
|
||||
<span class='tname'>"+klist[i]+"</span>\
|
||||
<div class='info-r'>\
|
||||
<input name='"+klist[i]+"' class='bt-input-text mr5' style='width:100%;' value='"+klist_val+"' placeholder='请输入对应值' type='text'>\
|
||||
</div>";
|
||||
}
|
||||
$('#dnsapi_option').html(option_html);
|
||||
}
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
area: '500px',
|
||||
title: '添加DNSAPI',
|
||||
closeBtn: 1,
|
||||
shift: 5,
|
||||
shadeClose: true,
|
||||
btn:["提交","关闭"],
|
||||
content: "<form class='bt-form pd20' id='dnsapi_add'>\
|
||||
<div class='line'>\
|
||||
<span class='tname'>名称</span>\
|
||||
<div class='info-r'><input name='name' class='bt-input-text mr5' style='width:100%;' placeholder='名称' value='"+option_name+"' type='text'></div>\
|
||||
</div>\
|
||||
<div class='line'>\
|
||||
<span class='tname'>DNSAPI类型</span>\
|
||||
<div class='info-r'>\
|
||||
<select class='bt-input-text mr5' name='type'>\
|
||||
<option name='cf'>cloudflare</option>\
|
||||
</select>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class='line' id='dnsapi_option'>\
|
||||
<span class='tname'>CF_Key</span>\
|
||||
<div class='info-r'>\
|
||||
<input name='v1' class='bt-input-text mr5' style='width:100%;' placeholder='请输入对应值' type='text'>\
|
||||
</div>\
|
||||
<span class='tname'>CF_Email</span>\
|
||||
<div class='info-r'>\
|
||||
<input name='v2' class='bt-input-text mr5' style='width:100%;' placeholder='请输入对应值' type='text'>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class='line'>\
|
||||
<span class='tname'>备注</span>\
|
||||
<div class='info-r'><input name='remark' class='bt-input-text mr5' style='width:100%;' placeholder='备注' value='"+option_remark+"' type='text'></div>\
|
||||
</div>\
|
||||
<input name='id' value='"+option_id+"' type='hidden'>\
|
||||
</form>",
|
||||
success:function(){
|
||||
$("input[name='name']").keyup(function(){
|
||||
var v = $(this).val();
|
||||
$("input[name='remark']").val(v);
|
||||
});
|
||||
|
||||
var option = '';
|
||||
for (var i = 0; i<dnsapi_option.length; i++) {
|
||||
|
||||
if (dnsapi_option[i]['name'] == option_type){
|
||||
option += "<option value='"+dnsapi_option[i]['name']+"' key='"+dnsapi_option[i]['key']+"' selected>"+dnsapi_option[i]['title']+"</option>";
|
||||
} else {
|
||||
option += "<option value='"+dnsapi_option[i]['name']+"' key='"+dnsapi_option[i]['key']+"'>"+dnsapi_option[i]['title']+"</option>";
|
||||
}
|
||||
}
|
||||
|
||||
renderDnsapiOption(option_type, option_val);
|
||||
$('select[name="type"]').html(option);
|
||||
$('select[name="type"]').change(function(){
|
||||
var name = $(this).val();
|
||||
|
||||
if (option_type == name){
|
||||
renderDnsapiOption(name, option_val);
|
||||
} else {
|
||||
renderDnsapiOption(name,'');
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
yes:function(index) {
|
||||
var data = $("#dnsapi_add").serialize();
|
||||
data = decodeURIComponent(data);
|
||||
data = toArrayObject(data);
|
||||
|
||||
var key = getDnsapiKey(data['type']);
|
||||
var klist = key.split(':');
|
||||
var val = '';
|
||||
for (var i = 0; i < klist.length; i++) {
|
||||
var k = klist[i];
|
||||
if (k in data){
|
||||
if (klist.length - 1 == i){
|
||||
val += k + '|' + data[k];
|
||||
} else {
|
||||
val += k + '|' + data[k]+'~';
|
||||
}
|
||||
}
|
||||
}
|
||||
data['val'] = val;
|
||||
apaPost('dnsapi_add', data, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
if (rdata.status){
|
||||
layer.close(index);
|
||||
dnsapiList();
|
||||
}
|
||||
},{icon: rdata.status ? 1 : 2}, 2000);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function dnsapiList(page, search){
|
||||
var _data = {};
|
||||
if (typeof(page) =='undefined'){
|
||||
var page = 1;
|
||||
}
|
||||
|
||||
_data['page'] = page;
|
||||
_data['page_size'] = 10;
|
||||
if(typeof(search) != 'undefined'){
|
||||
_data['search'] = search;
|
||||
}
|
||||
|
||||
apaPost('dnsapi_list', _data, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
var list = '';
|
||||
for(i in rdata.data){
|
||||
list += '<tr>';
|
||||
list +='<td><input value="'+rdata.data[i]['id']+'" class="check" onclick="checkSelect();" type="checkbox"></td>';
|
||||
list += '<td>' + rdata.data[i]['name'] +'</td>';
|
||||
list += '<td>' + getDnsapiTitle(rdata.data[i]['type']) +'</td>';
|
||||
list += '<td>' + rdata.data[i]['val'].split('~').join("<br/>") +'</td>';
|
||||
list += '<td>' + rdata.data[i]['remark'] +'</td>';
|
||||
|
||||
list += '<td style="text-align:right">';
|
||||
list += '<a href="javascript:;" index="'+i+'" class="btlink edit" title="编辑">编辑</a> | ';
|
||||
list += '<a href="javascript:;" class="btlink" onclick="dnsapiDel(\''+rdata.data[i]['id']+'\',\''+rdata.data[i]['name']+'\')" title="删除">删除</a>';
|
||||
list += '</td></tr>';
|
||||
}
|
||||
|
||||
var con = '<div class="safe bgw">\
|
||||
<button onclick="dnsapiAdd()" title="DNSAPI" class="btn btn-success btn-sm" type="button" style="margin-right: 5px;">添加DNSAPI</button>\
|
||||
<span style="float:right"> \
|
||||
<button batch="true" style="float: right;display: none;margin-left:10px;" onclick="delDbBatch();" title="删除选中项" class="btn btn-default btn-sm">删除选中</button>\
|
||||
</span>\
|
||||
<div class="divtable mtb10">\
|
||||
<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 width="30"><input class="check" onclick="checkSelect();" type="checkbox"></th>\
|
||||
<th>名称</th>\
|
||||
<th>类型</th>\
|
||||
<th>值</th>\
|
||||
<th>备注</th>\
|
||||
<th style="text-align:right;">操作</th></tr></thead>\
|
||||
<tbody>'+ list +'</tbody>\
|
||||
</table>\
|
||||
</div>\
|
||||
<div class="dataTables_paginate paging_bootstrap page"></div>\
|
||||
</div>\
|
||||
</div>';
|
||||
|
||||
$(".soft-man-con").html(con);
|
||||
$('.dataTables_paginate').html(rdata.page);
|
||||
|
||||
$('.edit').click(function(){
|
||||
var idx = $(this).attr('index');
|
||||
var row = rdata.data[idx];
|
||||
// console.log(row);
|
||||
dnsapiAdd(row);
|
||||
})
|
||||
|
||||
readerTableChecked();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function domainDel(id, name){
|
||||
safeMessage('删除['+name+']','您真的要删除['+name+']吗?',function(){
|
||||
var data='id='+id+'&name='+name;
|
||||
apaPost('domain_del', data, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
domainList();
|
||||
},{icon: rdata.status ? 1 : 2}, 600);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function domainStatusToggle(id){
|
||||
var data='id='+id;
|
||||
apaPost('domain_status_toggle', data, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
domainList();
|
||||
},{icon: rdata.status ? 1 : 2}, 600);
|
||||
});
|
||||
}
|
||||
|
||||
function domainIdCmd(id){
|
||||
var data='id='+id;
|
||||
apaPost('get_run_hook_id_cmd', data, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
// console.log(rdata);
|
||||
layer.open({
|
||||
title: "手动同步命令",
|
||||
area: ['600px', '180px'],
|
||||
type:1,
|
||||
closeBtn: 1,
|
||||
shadeClose: false,
|
||||
btn:["复制","取消"],
|
||||
content: '<div class="pd15">\
|
||||
<div class="divtable">\
|
||||
<pre class="layui-code">'+rdata.data+'</pre>\
|
||||
</div>\
|
||||
</div>',
|
||||
success:function(){
|
||||
copyText(rdata.data);
|
||||
},
|
||||
yes:function(){
|
||||
copyText(rdata.data);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function domainHookCmd(){
|
||||
apaPost('run_hook_cmd', {}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
layer.open({
|
||||
title: "手动同步全部命令",
|
||||
area: ['600px', '180px'],
|
||||
type:1,
|
||||
closeBtn: 1,
|
||||
shadeClose: false,
|
||||
btn:["复制","取消"],
|
||||
content: '<div class="pd15">\
|
||||
<div class="divtable">\
|
||||
<pre class="layui-code">'+rdata.data+'</pre>\
|
||||
</div>\
|
||||
</div>',
|
||||
success:function(){
|
||||
copyText(rdata.data);
|
||||
},
|
||||
yes:function(){
|
||||
copyText(rdata.data);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function syncCfCmd(){
|
||||
apaPost('run_sync_cf_cmd', {}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
layer.open({
|
||||
title: "手动同步CloudFlare全部域名命令",
|
||||
area: ['600px', '180px'],
|
||||
type:1,
|
||||
closeBtn: 1,
|
||||
shadeClose: false,
|
||||
btn:["复制","取消"],
|
||||
content: '<div class="pd15">\
|
||||
<div class="divtable">\
|
||||
<pre class="layui-code">'+rdata.data+'</pre>\
|
||||
</div>\
|
||||
</div>',
|
||||
success:function(){
|
||||
copyText(rdata.data);
|
||||
},
|
||||
yes:function(){
|
||||
copyText(rdata.data);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function syncDnsPodCmd(){
|
||||
apaPost('run_sync_dnspod_cmd', {}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
layer.open({
|
||||
title: "手动同步DnsPod全部域名命令",
|
||||
area: ['600px', '180px'],
|
||||
type:1,
|
||||
closeBtn: 1,
|
||||
shadeClose: false,
|
||||
btn:["复制","取消"],
|
||||
content: '<div class="pd15">\
|
||||
<div class="divtable">\
|
||||
<pre class="layui-code">'+rdata.data+'</pre>\
|
||||
</div>\
|
||||
</div>',
|
||||
success:function(){
|
||||
copyText(rdata.data);
|
||||
},
|
||||
yes:function(){
|
||||
copyText(rdata.data);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function domainAdd(row){
|
||||
|
||||
var option_domian = '';
|
||||
var option_remark = '备注';
|
||||
var option_email = '';
|
||||
var option_id = 0;
|
||||
var option_dnsapi_id = 0;
|
||||
if (typeof(row) != 'undefined'){
|
||||
option_domian = row['domain'];
|
||||
option_remark = row['remark'];
|
||||
option_email = row['email'];
|
||||
option_id = row['id'];
|
||||
option_dnsapi_id = row['dnsapi_id'];
|
||||
}
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
area: '500px',
|
||||
title: '添加顶级域名',
|
||||
closeBtn: 1,
|
||||
shift: 5,
|
||||
shadeClose: true,
|
||||
btn:["提交","关闭"],
|
||||
content: "<form class='bt-form pd20' id='domain_add'>\
|
||||
<div class='line'>\
|
||||
<span class='tname'>域名</span>\
|
||||
<div class='info-r'><input name='domain' class='bt-input-text mr5' style='width:100%;' value='"+option_domian+"' placeholder='域名' type='text'></div>\
|
||||
</div>\
|
||||
<div class='line'>\
|
||||
<span class='tname'>DNSAPI</span>\
|
||||
<div class='info-r'>\
|
||||
<select class='bt-input-text mr5' name='dnsapi_id'>\
|
||||
<option name='0'>无设置</option>\
|
||||
</select>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class='line'>\
|
||||
<span class='tname'>邮件</span>\
|
||||
<div class='info-r'><input name='email' class='bt-input-text mr5' style='width:100%;' value='"+option_email+"' placeholder='邮件' type='text'></div>\
|
||||
</div>\
|
||||
<div class='line'>\
|
||||
<span class='tname'>备注</span>\
|
||||
<div class='info-r'><input name='remark' class='bt-input-text mr5' style='width:100%;' value='"+option_remark+"' placeholder='备注' type='text'></div>\
|
||||
</div>\
|
||||
<input name='id' value='"+option_id+"' type='hidden'>\
|
||||
</form>",
|
||||
success:function(){
|
||||
// $("input[name='domain']").keyup(function(){
|
||||
// var v = $(this).val();
|
||||
// $("input[name='remark']").val(v);
|
||||
// });
|
||||
|
||||
var dnsapi_id_html = "<option value='0'>无设置</option>";
|
||||
apaPostN('dnsapi_list_all', {}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
for (var i = 0; i < rdata.length; i++) {
|
||||
if (option_dnsapi_id == rdata[i]['id']){
|
||||
dnsapi_id_html += "<option value='"+rdata[i]['id']+"' selected>"+rdata[i]['name']+"</option>";
|
||||
} else {
|
||||
dnsapi_id_html += "<option value='"+rdata[i]['id']+"'>"+rdata[i]['name']+"</option>";
|
||||
}
|
||||
}
|
||||
$('select[name="dnsapi_id"]').html(dnsapi_id_html);
|
||||
});
|
||||
},
|
||||
yes:function(index) {
|
||||
var data = $("#domain_add").serialize();
|
||||
data = decodeURIComponent(data);
|
||||
apaPost('domain_add', data, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
if (rdata.status){
|
||||
layer.close(index);
|
||||
domainList();
|
||||
}
|
||||
},{icon: rdata.status ? 1 : 2}, 2000);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function domainList(page, search){
|
||||
var _data = {};
|
||||
if (typeof(page) =='undefined'){
|
||||
var page = 1;
|
||||
}
|
||||
|
||||
_data['page'] = page;
|
||||
_data['page_size'] = 10;
|
||||
if(typeof(search) != 'undefined'){
|
||||
_data['search'] = search;
|
||||
}
|
||||
|
||||
apaPost('domain_list', _data, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
// console.log(rdata);
|
||||
var list = '';
|
||||
for(i in rdata.data){
|
||||
list += '<tr>';
|
||||
list +='<td><input value="'+rdata.data[i]['id']+'" class="check" onclick="checkSelect();" type="checkbox"></td>';
|
||||
list += '<td>' + rdata.data[i]['domain'] +'</td>';
|
||||
list += '<td>' + rdata.data[i]['dnsapi_id_alias'] +'</td>';
|
||||
list += '<td>' + rdata.data[i]['email'] +'</td>';
|
||||
list += '<td>' + rdata.data[i]['remark'] +'</td>';
|
||||
|
||||
|
||||
|
||||
if (rdata.data[i]['effective_date'] == ''){
|
||||
list += '<td>空/未申请</td>';
|
||||
} else {
|
||||
list += '<td>'+getFormatTime(rdata.data[i]['effective_date'],'yyyy/MM/dd')+'</td>';
|
||||
}
|
||||
|
||||
if (rdata.data[i]['expiration_date'] == ''){
|
||||
list += '<td>空/未申请</td>';
|
||||
} else {
|
||||
list += '<td>'+getFormatTime(rdata.data[i]['expiration_date'],'yyyy/MM/dd')+'</td>';
|
||||
}
|
||||
|
||||
if (rdata.data[i]['status'] == '0'){
|
||||
list += '<td><a href="javascript:;" index="'+i+'" class="btlink status">否</a></td>';
|
||||
} else {
|
||||
list += '<td><a href="javascript:;" index="'+i+'" class="btlink status">是</a></td>';
|
||||
}
|
||||
|
||||
list += '<td style="text-align:right">';
|
||||
list += '<a href="javascript:;" index="'+i+'" class="btlink cmd" title="命令">命令</a> | ';
|
||||
list += '<a href="javascript:;" index="'+i+'" class="btlink edit" title="编辑">编辑</a> | ';
|
||||
list += '<a href="javascript:;" class="btlink" onclick="domainDel(\''+rdata.data[i]['id']+'\',\''+rdata.data[i]['domain']+'\')" title="删除">删除</a>';
|
||||
list += '</td></tr>';
|
||||
}
|
||||
|
||||
var con = '<div class="safe bgw">\
|
||||
<button onclick="domainAdd()" title="添加顶级域名" class="btn btn-success btn-sm" type="button" style="margin-right: 5px;">添加域名</button>\
|
||||
<button onclick="domainHookCmd()" title="全部同步命令" class="btn btn-success btn-sm" type="button" style="margin-right: 5px;">全部同步命令</button>\
|
||||
<button onclick="syncCfCmd()" title="cloudflare同步命令" class="btn btn-success btn-sm" type="button" style="margin-right: 5px;">cloudflare同步命令</button>\
|
||||
<button onclick="syncDnsPodCmd()" title="DnsPod国际同步命令" class="btn btn-success btn-sm" type="button" style="margin-right: 5px;">DnsPod国际同步命令</button>\
|
||||
<div class="divtable mtb10">\
|
||||
<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 width="30"><input class="check" onclick="checkSelect();" type="checkbox"></th>\
|
||||
<th>域名</th>\
|
||||
<th>DNSAPI</th>\
|
||||
<th>邮件</th>\
|
||||
<th>备注</th>\
|
||||
<th>开始</th>\
|
||||
<th>结束</th>\
|
||||
<th>同步</th>\
|
||||
<th style="text-align:right;">操作</th></tr></thead>\
|
||||
<tbody>'+ list +'</tbody>\
|
||||
</table>\
|
||||
</div>\
|
||||
<div class="dataTables_paginate paging_bootstrap page"></div>\
|
||||
</div>\
|
||||
</div>';
|
||||
|
||||
$(".soft-man-con").html(con);
|
||||
$('.dataTables_paginate').html(rdata.page);
|
||||
|
||||
$('.edit').click(function(){
|
||||
var idx = $(this).attr('index');
|
||||
var row = rdata.data[idx];
|
||||
domainAdd(row);
|
||||
});
|
||||
|
||||
$('.status').click(function(){
|
||||
var idx = $(this).attr('index');
|
||||
var row = rdata.data[idx];
|
||||
domainStatusToggle(row['id']);
|
||||
});
|
||||
|
||||
$('.cmd').click(function(){
|
||||
var idx = $(this).attr('index');
|
||||
var row = rdata.data[idx];
|
||||
domainIdCmd(row['id']);
|
||||
});
|
||||
|
||||
readerTableChecked();
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import json
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'acme_pandominassl_apply'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getTaskConf():
|
||||
conf = getServerDir() + "/cron_config.json"
|
||||
return conf
|
||||
|
||||
def getTaskDeltaConf():
|
||||
conf = getServerDir() + "/cron_delta_config.json"
|
||||
return conf
|
||||
|
||||
|
||||
def getConfigData():
|
||||
try:
|
||||
return json.loads(mw.readFile(getTaskConf()))
|
||||
except:
|
||||
pass
|
||||
return {
|
||||
"task_id": -1,
|
||||
"period": "day-n",
|
||||
"where1": "1",
|
||||
"hour": "0",
|
||||
"minute": "15",
|
||||
}
|
||||
|
||||
|
||||
def createBgTask():
|
||||
removeBgTask()
|
||||
createBgTaskByName(getPluginName())
|
||||
return True
|
||||
|
||||
|
||||
def createBgTaskByName(name):
|
||||
args = getConfigData()
|
||||
_name = "[勿删]ACME泛域名SSL[APA]"
|
||||
res = mw.M("crontab").field("id, name").where("name=?", (_name,)).find()
|
||||
if res:
|
||||
return True
|
||||
|
||||
if "task_id" in args and args["task_id"] > 0:
|
||||
res = mw.M("crontab").field("id, name").where(
|
||||
"id=?", (args["task_id"],)).find()
|
||||
if res and res["id"] == args["task_id"]:
|
||||
print("计划任务已经存在!")
|
||||
return True
|
||||
import crontab_api
|
||||
api = crontab_api.crontab_api()
|
||||
|
||||
mw_dir = mw.getRunDir()
|
||||
cmd = '''
|
||||
mw_dir=%s
|
||||
rname=%s
|
||||
plugin_path=%s
|
||||
script_path=%s
|
||||
logs_file=$plugin_path/${rname}.log
|
||||
''' % (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/index.py run_hook"' + "\n"
|
||||
cmd += 'cd $mw_dir && python3 $script_path/index.py run_hook' + "\n"
|
||||
cmd += 'echo "【`date +"%Y-%m-%d %H:%M:%S"`】 END★" >> $logs_file' + "\n"
|
||||
cmd += 'echo "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" >> $logs_file' + "\n"
|
||||
|
||||
params = {
|
||||
'name': _name,
|
||||
'type': args['period'],
|
||||
'week': "",
|
||||
'where1': args['where1'],
|
||||
'hour': args['hour'],
|
||||
'minute': args['minute'],
|
||||
'save': "",
|
||||
'backup_to': "",
|
||||
'stype': "toShell",
|
||||
'sname': '',
|
||||
'sbody': cmd,
|
||||
'urladdress': '',
|
||||
}
|
||||
|
||||
task_id = api.add(params)
|
||||
if task_id > 0:
|
||||
args["task_id"] = task_id
|
||||
args["name"] = name
|
||||
mw.writeFile(getTaskConf(), json.dumps(args))
|
||||
|
||||
|
||||
def removeBgTask():
|
||||
cfg = getConfigData()
|
||||
if "task_id" in cfg and cfg["task_id"] > 0:
|
||||
res = mw.M("crontab").field("id, name").where(
|
||||
"id=?", (cfg["task_id"],)).find()
|
||||
if res and res["id"] == cfg["task_id"]:
|
||||
import crontab_api
|
||||
api = crontab_api.crontab_api()
|
||||
data = api.delete(cfg["task_id"])
|
||||
if data[0]:
|
||||
cfg["task_id"] = -1
|
||||
mw.writeFile(getTaskConf(), json.dumps(cfg))
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1:
|
||||
action = sys.argv[1]
|
||||
if action == "remove":
|
||||
removeBgTask()
|
||||
elif action == "add":
|
||||
createBgTask()
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
Executable
+31
@@ -0,0 +1,31 @@
|
||||
<style>
|
||||
.overflow_hide {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="bt-form">
|
||||
<div class='plugin_version'></div>
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<p class="bgw" onclick="pluginService('alist');">服务</p>
|
||||
<p onclick="pluginInitD('alist');">自启动</p>
|
||||
<p onclick="alistCommonFunc();">常用功能</p>
|
||||
<p onclick="pluginConfigTpl('alist',$('.plugin_version').attr('version'));">配置修改</p>
|
||||
<p onclick="pluginLogs('alist','','run_log');">运行日志</p>
|
||||
<p onclick="alistReadme();">相关说明</p>
|
||||
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
<div class="soft-man-con" style="height: 520px; overflow: auto;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$.getScript( "/plugins/file?name=alist&f=js/alist.js", function(){
|
||||
pluginService('alist', $('.plugin_version').attr('version'));
|
||||
});
|
||||
</script>
|
||||
Executable
+292
@@ -0,0 +1,292 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'alist'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getInitDFile():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return '/tmp/' + getPluginName()
|
||||
|
||||
if current_os.startswith('freebsd'):
|
||||
return '/etc/rc.d/' + getPluginName()
|
||||
|
||||
return '/etc/init.d/' + getPluginName()
|
||||
|
||||
|
||||
def getInitDTpl():
|
||||
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
|
||||
return path
|
||||
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[3:]
|
||||
tmp = {}
|
||||
args_len = len(args)
|
||||
|
||||
if args_len == 1:
|
||||
t = args[0].strip('{').strip('}')
|
||||
if t.strip() == '':
|
||||
tmp = []
|
||||
else:
|
||||
t = t.split(':')
|
||||
tmp[t[0]] = t[1]
|
||||
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 getConf():
|
||||
path = getServerDir() + "/data/config.json"
|
||||
return path
|
||||
|
||||
def configTpl():
|
||||
path = getPluginDir() + '/tpl'
|
||||
pathFile = os.listdir(path)
|
||||
tmp = []
|
||||
for one in pathFile:
|
||||
file = path + '/' + one
|
||||
tmp.append(file)
|
||||
return mw.getJson(tmp)
|
||||
|
||||
|
||||
def readConfigTpl():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
content = mw.readFile(args['file'])
|
||||
content = contentReplace(content)
|
||||
return mw.returnJson(True, 'ok', content)
|
||||
|
||||
|
||||
def status():
|
||||
data = mw.execShell(
|
||||
"ps aux|grep alist |grep -v grep | grep -v python | grep -v mdserver-web | awk '{print $2}'")
|
||||
|
||||
if data[0] == '':
|
||||
return 'stop'
|
||||
return 'start'
|
||||
|
||||
def contentReplace(content):
|
||||
service_path = mw.getServerDir()
|
||||
content = content.replace('{$ROOT_PATH}', mw.getRootDir())
|
||||
content = content.replace('{$SERVER_PATH}', service_path)
|
||||
content = content.replace('{$SERVER_APP}', service_path + '/'+getPluginName())
|
||||
return content
|
||||
|
||||
def initDreplace():
|
||||
|
||||
file_tpl = getInitDTpl()
|
||||
service_path = os.path.dirname(os.getcwd())
|
||||
|
||||
initD_path = getServerDir() + '/init.d'
|
||||
if not os.path.exists(initD_path):
|
||||
os.mkdir(initD_path)
|
||||
file_bin = initD_path + '/' + getPluginName()
|
||||
|
||||
# initd replace
|
||||
if not os.path.exists(file_bin):
|
||||
content = mw.readFile(file_tpl)
|
||||
content = content.replace('{$SERVER_PATH}', service_path)
|
||||
mw.writeFile(file_bin, content)
|
||||
mw.execShell('chmod +x ' + file_bin)
|
||||
|
||||
# systemd
|
||||
systemDir = mw.systemdCfgDir()
|
||||
systemService = systemDir + '/' + getPluginName() + '.service'
|
||||
if os.path.exists(systemDir) and not os.path.exists(systemService):
|
||||
systemServiceTpl = getPluginDir() + '/init.d/' + getPluginName() + '.service.tpl'
|
||||
service_path = mw.getServerDir()
|
||||
se_content = mw.readFile(systemServiceTpl)
|
||||
se_content = se_content.replace('{$SERVER_PATH}', service_path)
|
||||
mw.writeFile(systemService, se_content)
|
||||
mw.execShell('systemctl daemon-reload')
|
||||
|
||||
return file_bin
|
||||
|
||||
|
||||
def alistOp(method):
|
||||
file = initDreplace()
|
||||
|
||||
current_os = mw.getOs()
|
||||
if current_os == "darwin":
|
||||
data = mw.execShell(file + ' ' + method)
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
if current_os.startswith("freebsd"):
|
||||
data = mw.execShell('service ' + getPluginName() + ' ' + method)
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
data = mw.execShell('systemctl ' + method + ' ' + getPluginName())
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
|
||||
def start():
|
||||
return alistOp('start')
|
||||
|
||||
|
||||
def stop():
|
||||
return alistOp('stop')
|
||||
|
||||
|
||||
def restart():
|
||||
status = alistOp('restart')
|
||||
return status
|
||||
|
||||
|
||||
def reload():
|
||||
return alistOp('reload')
|
||||
|
||||
|
||||
def initdStatus():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
|
||||
if current_os.startswith('freebsd'):
|
||||
initd_bin = getInitDFile()
|
||||
if os.path.exists(initd_bin):
|
||||
return 'ok'
|
||||
|
||||
shell_cmd = 'systemctl status ' + \
|
||||
getPluginName() + ' | grep loaded | grep "enabled;"'
|
||||
data = mw.execShell(shell_cmd)
|
||||
if data[0] == '':
|
||||
return 'fail'
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdInstall():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
|
||||
# freebsd initd install
|
||||
if current_os.startswith('freebsd'):
|
||||
import shutil
|
||||
source_bin = initDreplace()
|
||||
initd_bin = getInitDFile()
|
||||
shutil.copyfile(source_bin, initd_bin)
|
||||
mw.execShell('chmod +x ' + initd_bin)
|
||||
mw.execShell('sysrc ' + getPluginName() + '_enable="YES"')
|
||||
return 'ok'
|
||||
|
||||
mw.execShell('systemctl enable ' + getPluginName())
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdUinstall():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
|
||||
if current_os.startswith('freebsd'):
|
||||
initd_bin = getInitDFile()
|
||||
os.remove(initd_bin)
|
||||
mw.execShell('sysrc ' + getPluginName() + '_enable="NO"')
|
||||
return 'ok'
|
||||
|
||||
mw.execShell('systemctl disable ' + getPluginName())
|
||||
return 'ok'
|
||||
|
||||
|
||||
def runLog():
|
||||
return getServerDir() + '/data/log/log.log'
|
||||
|
||||
def pSqliteDb(dbname='databases'):
|
||||
pos_file = getServerDir() + '/data/'
|
||||
file = pos_file + '/data.db'
|
||||
name = 'data'
|
||||
conn = mw.M(dbname).dbPos(pos_file, name)
|
||||
return conn
|
||||
|
||||
def clearCopyTask():
|
||||
conn = pSqliteDb('x_task_items')
|
||||
conn.where('key=?', ('copy',)).setField('persist_data','[]')
|
||||
restart()
|
||||
return mw.returnJson(True, '清空成功并重启服务!')
|
||||
|
||||
def homePage():
|
||||
import json
|
||||
content = mw.readFile(getConf())
|
||||
data = json.loads(content)
|
||||
http_port = data['scheme']['http_port']
|
||||
ip = mw.getLocalIp()
|
||||
if mw.isAppleSystem():
|
||||
ip = '127.0.0.1'
|
||||
url = 'http://'+ip+":"+str(http_port)
|
||||
# print(url)
|
||||
return mw.returnJson(True, 'ok!', url)
|
||||
|
||||
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 == 'initd_status':
|
||||
print(initdStatus())
|
||||
elif func == 'initd_install':
|
||||
print(initdInstall())
|
||||
elif func == 'initd_uninstall':
|
||||
print(initdUinstall())
|
||||
elif func == 'conf':
|
||||
print(getConf())
|
||||
elif func == 'run_log':
|
||||
print(runLog())
|
||||
elif func == 'config_tpl':
|
||||
print(configTpl())
|
||||
elif func == 'read_config_tpl':
|
||||
print(readConfigTpl())
|
||||
elif func == 'clear_copy_task':
|
||||
print(clearCopyTask())
|
||||
elif func == 'home_page':
|
||||
print(homePage())
|
||||
else:
|
||||
print('error')
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"sort": 7,
|
||||
"ps": "一个支持多种存储的文件列表程序",
|
||||
"name": "alist",
|
||||
"title": "Alist",
|
||||
"shell": "install.sh",
|
||||
"versions":["3.37.4","3.38.0"],
|
||||
"tip": "soft",
|
||||
"checks": "server/alist",
|
||||
"path": "server/alist",
|
||||
"display": 1,
|
||||
"author": "alist",
|
||||
"date": "2022-10-09",
|
||||
"home": "https://alist.nn.ci",
|
||||
"type": 0,
|
||||
"pid": "5"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=A file list program that supports multiple storage
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory={$SERVER_PATH}/alist
|
||||
ExecStart={$SERVER_PATH}/alist/alist server
|
||||
ExecReload=/bin/kill -USR2 $MAINPID
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,46 @@
|
||||
#!/bin/sh
|
||||
# chkconfig: 2345 55 25
|
||||
# description: alist Service
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: alist
|
||||
# Required-Start: $all
|
||||
# Required-Stop: $all
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: starts alist
|
||||
# Description: starts the MDW-Web
|
||||
### END INIT INFO
|
||||
|
||||
# Simple alist init.d script conceived to work on Linux systems
|
||||
# as it does use of the /proc filesystem.
|
||||
|
||||
app_start(){
|
||||
echo "Starting alist server..."
|
||||
cd {$SERVER_PATH}/alist
|
||||
./alist server >> {$SERVER_PATH}/alist/logs.pl 2>&1 &
|
||||
}
|
||||
|
||||
app_stop(){
|
||||
echo "dztasks stopped"
|
||||
ps -ef| grep alist | grep -v grep | grep -v python | grep -v sh | awk '{print $2}'| xargs kill
|
||||
}
|
||||
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
app_start
|
||||
;;
|
||||
stop)
|
||||
app_stop
|
||||
;;
|
||||
restart|reload)
|
||||
app_stop
|
||||
sleep 0.3
|
||||
app_start
|
||||
;;
|
||||
*)
|
||||
echo "Please use start or stop as first argument"
|
||||
;;
|
||||
esac
|
||||
|
||||
Executable
+94
@@ -0,0 +1,94 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/alist && bash install.sh install 3.37.4
|
||||
# cd /www/server/mdserver-web/plugins/alist && bash install.sh install 3.37.4
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=$2
|
||||
|
||||
sysArch=`arch`
|
||||
sysName=`uname`
|
||||
|
||||
ALIST_ARCH_NAME=amd64
|
||||
if [ "$sysArch" == "arm64" ];then
|
||||
ALIST_ARCH_NAME=arm64
|
||||
elif [ "$sysArch" == "x86_64" ]; then
|
||||
ALIST_ARCH_NAME=amd64
|
||||
elif [ "$sysArch" == "aarch64" ]; then
|
||||
ALIST_ARCH_NAME=arm64
|
||||
fi
|
||||
|
||||
ALIST_NAME=linux
|
||||
if [ "$sysName" == "Darwin" ];then
|
||||
ALIST_NAME=darwin
|
||||
fi
|
||||
|
||||
Install_App()
|
||||
{
|
||||
echo '正在安装脚本文件...'
|
||||
|
||||
mkdir -p $serverPath/source
|
||||
mkdir -p $serverPath/source/alist
|
||||
|
||||
FILE_TGZ=alist-${ALIST_NAME}-${ALIST_ARCH_NAME}.tar.gz
|
||||
|
||||
ALIST_DIR=$serverPath/source/alist
|
||||
|
||||
if [ ! -f $ALIST_DIR/${FILE_TGZ} ];then
|
||||
wget -O $ALIST_DIR/${FILE_TGZ} https://github.com/alist-org/alist/releases/download/v${VERSION}/${FILE_TGZ}
|
||||
fi
|
||||
|
||||
mkdir -p $serverPath/alist
|
||||
|
||||
cd $ALIST_DIR && tar -zxvf ${FILE_TGZ} -C $serverPath/alist
|
||||
echo "${VERSION}" > $serverPath/alist/version.pl
|
||||
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/alist/index.py start
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/alist/index.py initd_install
|
||||
|
||||
cd $serverPath/alist && ./alist admin set admin
|
||||
# cd /www/server/alist && ./alist admin set admin
|
||||
|
||||
echo '安装完成'
|
||||
}
|
||||
|
||||
Uninstall_App()
|
||||
{
|
||||
if [ -f /usr/lib/systemd/system/alist.service ];then
|
||||
systemctl stop alist
|
||||
systemctl disable alist
|
||||
rm -rf /usr/lib/systemd/system/alist.service
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
|
||||
if [ -f /lib/systemd/system/alist.service ];then
|
||||
systemctl stop alist
|
||||
systemctl disable alist
|
||||
rm -rf /lib/systemd/system/alist.service
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
|
||||
if [ -f $serverPath/alist/initd/alist ];then
|
||||
$serverPath/alist/initd/alist stop
|
||||
fi
|
||||
|
||||
if [ -d $serverPath/alist ];then
|
||||
rm -rf $serverPath/alist
|
||||
fi
|
||||
|
||||
echo "卸载alist成功"
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_App
|
||||
else
|
||||
Uninstall_App
|
||||
fi
|
||||
Executable
+92
@@ -0,0 +1,92 @@
|
||||
function alistPost(method, version, args,callback){
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
|
||||
var req_data = {};
|
||||
req_data['name'] = 'alist';
|
||||
req_data['func'] = method;
|
||||
req_data['version'] = version;
|
||||
|
||||
if (typeof(args) == 'string'){
|
||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
req_data['args'] = JSON.stringify(args);
|
||||
}
|
||||
|
||||
$.post('/plugins/run', req_data, function(data) {
|
||||
layer.close(loadT);
|
||||
if (!data.status){
|
||||
//错误展示10S
|
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof(callback) == 'function'){
|
||||
callback(data);
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
|
||||
function alistPostCallbak(method, version, args,callback){
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
|
||||
var req_data = {};
|
||||
req_data['name'] = 'alist';
|
||||
req_data['func'] = method;
|
||||
args['version'] = version;
|
||||
|
||||
if (typeof(args) == 'string'){
|
||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
req_data['args'] = JSON.stringify(args);
|
||||
}
|
||||
|
||||
$.post('/plugins/callback', req_data, 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 clearTaskCopy(){
|
||||
layer.confirm('您真的要清空复制任务吗?', { icon: 3, closeBtn: 2 }, function() {
|
||||
alistPost('clear_copy_task', '', {}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg, function(){},{ icon: rdata.status ? 1 : 2 });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function commonHomePage(){
|
||||
alistPost('home_page', '', {}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
window.open(rdata.data);
|
||||
});
|
||||
}
|
||||
|
||||
function alistCommonFunc(){
|
||||
var con = '';
|
||||
con += '<hr/><p class="conf_p" style="text-align:center;">\
|
||||
<button class="btn btn-default btn-sm" onclick="commonHomePage()">主页</button>\
|
||||
<button class="btn btn-default btn-sm" onclick="clearTaskCopy()">清空复制任务</button>\
|
||||
</p>';
|
||||
|
||||
$(".soft-man-con").html(con);
|
||||
}
|
||||
|
||||
function alistReadme(){
|
||||
|
||||
|
||||
var readme = '<ul class="help-info-text c7">';
|
||||
readme += '<li>默认admin:admin</li>';
|
||||
readme += '<li>手动改密码: cd /www/server/alist && ./alist admin set NEW_PASSWORD</li>';
|
||||
readme += '</ul>';
|
||||
|
||||
$('.soft-man-con').html(readme);
|
||||
}
|
||||
|
||||
@@ -113,6 +113,9 @@ def initConf():
|
||||
|
||||
"/tmp/yum_save_*",
|
||||
"/tmp/tmp.*",
|
||||
|
||||
"/www/server/dztasks/logs/dztasks.*.log",
|
||||
"/www/server/dztasks/logs/dztasks_*",
|
||||
]
|
||||
for i in clog:
|
||||
content += i + "\n"
|
||||
@@ -127,6 +130,7 @@ def initConf():
|
||||
"/var/log/cron",
|
||||
"/www/wwwlogs",
|
||||
"/www/server/rsyncd",
|
||||
"/www/server/acme_pandominassl_apply",
|
||||
"/www/server/sphinx/index",
|
||||
"/www/server/mongodb/logs",
|
||||
"/www/server/php/53/var/log",
|
||||
@@ -146,6 +150,8 @@ def initConf():
|
||||
"/www/server/openresty/nginx/logs",
|
||||
"/www/server/phpmyadmin",
|
||||
"/www/server/redis/data",
|
||||
"/www/server/alist/data/log",
|
||||
"/www/server/dztasks/logs",
|
||||
"/www/server/cron",
|
||||
]
|
||||
for i in clogcom:
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
Executable
+31
@@ -0,0 +1,31 @@
|
||||
<style>
|
||||
.overflow_hide {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="bt-form">
|
||||
<div class='plugin_version'></div>
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<p class="bgw" onclick="pluginService('cloudreve');">服务</p>
|
||||
<p onclick="pluginInitD('cloudreve');">自启动</p>
|
||||
<p onclick="alistCommonFunc();">常用功能</p>
|
||||
<p onclick="pluginConfigTpl('cloudreve',$('.plugin_version').attr('version'));">配置修改</p>
|
||||
<p onclick="pluginLogs('cloudreve','','run_log');">运行日志</p>
|
||||
<p onclick="alistReadme();">相关说明</p>
|
||||
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
<div class="soft-man-con" style="height: 520px; overflow: auto;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$.getScript( "/plugins/file?name=cloudreve&f=js/cloudreve.js", function(){
|
||||
pluginService('cloudreve', $('.plugin_version').attr('version'));
|
||||
});
|
||||
</script>
|
||||
Executable
+288
@@ -0,0 +1,288 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'cloudreve'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getInitDFile():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return '/tmp/' + getPluginName()
|
||||
|
||||
if current_os.startswith('freebsd'):
|
||||
return '/etc/rc.d/' + getPluginName()
|
||||
|
||||
return '/etc/init.d/' + getPluginName()
|
||||
|
||||
|
||||
def getInitDTpl():
|
||||
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
|
||||
return path
|
||||
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[3:]
|
||||
tmp = {}
|
||||
args_len = len(args)
|
||||
|
||||
if args_len == 1:
|
||||
t = args[0].strip('{').strip('}')
|
||||
if t.strip() == '':
|
||||
tmp = []
|
||||
else:
|
||||
t = t.split(':')
|
||||
tmp[t[0]] = t[1]
|
||||
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 getConf():
|
||||
path = getServerDir() + "/conf.ini"
|
||||
return path
|
||||
|
||||
def configTpl():
|
||||
path = getPluginDir() + '/tpl'
|
||||
pathFile = os.listdir(path)
|
||||
tmp = []
|
||||
for one in pathFile:
|
||||
file = path + '/' + one
|
||||
tmp.append(file)
|
||||
return mw.getJson(tmp)
|
||||
|
||||
|
||||
def readConfigTpl():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
content = mw.readFile(args['file'])
|
||||
content = contentReplace(content)
|
||||
return mw.returnJson(True, 'ok', content)
|
||||
|
||||
|
||||
def status():
|
||||
data = mw.execShell(
|
||||
"ps aux|grep cloudreve |grep -v grep | grep -v python | grep -v mdserver-web | awk '{print $2}'")
|
||||
|
||||
if data[0] == '':
|
||||
return 'stop'
|
||||
return 'start'
|
||||
|
||||
def contentReplace(content):
|
||||
service_path = mw.getServerDir()
|
||||
content = content.replace('{$ROOT_PATH}', mw.getRootDir())
|
||||
content = content.replace('{$SERVER_PATH}', service_path)
|
||||
content = content.replace('{$SERVER_APP}', service_path + '/'+getPluginName())
|
||||
return content
|
||||
|
||||
def initDreplace():
|
||||
|
||||
file_tpl = getInitDTpl()
|
||||
service_path = os.path.dirname(os.getcwd())
|
||||
|
||||
initD_path = getServerDir() + '/init.d'
|
||||
if not os.path.exists(initD_path):
|
||||
os.mkdir(initD_path)
|
||||
file_bin = initD_path + '/' + getPluginName()
|
||||
|
||||
# initd replace
|
||||
if not os.path.exists(file_bin):
|
||||
content = mw.readFile(file_tpl)
|
||||
content = content.replace('{$SERVER_PATH}', service_path)
|
||||
mw.writeFile(file_bin, content)
|
||||
mw.execShell('chmod +x ' + file_bin)
|
||||
|
||||
# systemd
|
||||
systemDir = mw.systemdCfgDir()
|
||||
systemService = systemDir + '/' + getPluginName() + '.service'
|
||||
if os.path.exists(systemDir) and not os.path.exists(systemService):
|
||||
systemServiceTpl = getPluginDir() + '/init.d/' + getPluginName() + '.service.tpl'
|
||||
service_path = mw.getServerDir()
|
||||
se_content = mw.readFile(systemServiceTpl)
|
||||
se_content = se_content.replace('{$SERVER_PATH}', service_path)
|
||||
mw.writeFile(systemService, se_content)
|
||||
mw.execShell('systemctl daemon-reload')
|
||||
|
||||
return file_bin
|
||||
|
||||
|
||||
def alistOp(method):
|
||||
file = initDreplace()
|
||||
|
||||
current_os = mw.getOs()
|
||||
if current_os == "darwin":
|
||||
data = mw.execShell(file + ' ' + method)
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
if current_os.startswith("freebsd"):
|
||||
data = mw.execShell('service ' + getPluginName() + ' ' + method)
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
data = mw.execShell('systemctl ' + method + ' ' + getPluginName())
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
|
||||
def start():
|
||||
return alistOp('start')
|
||||
|
||||
|
||||
def stop():
|
||||
return alistOp('stop')
|
||||
|
||||
|
||||
def restart():
|
||||
status = alistOp('restart')
|
||||
return status
|
||||
|
||||
|
||||
def reload():
|
||||
return alistOp('reload')
|
||||
|
||||
|
||||
def initdStatus():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
|
||||
if current_os.startswith('freebsd'):
|
||||
initd_bin = getInitDFile()
|
||||
if os.path.exists(initd_bin):
|
||||
return 'ok'
|
||||
|
||||
shell_cmd = 'systemctl status ' + \
|
||||
getPluginName() + ' | grep loaded | grep "enabled;"'
|
||||
data = mw.execShell(shell_cmd)
|
||||
if data[0] == '':
|
||||
return 'fail'
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdInstall():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
|
||||
# freebsd initd install
|
||||
if current_os.startswith('freebsd'):
|
||||
import shutil
|
||||
source_bin = initDreplace()
|
||||
initd_bin = getInitDFile()
|
||||
shutil.copyfile(source_bin, initd_bin)
|
||||
mw.execShell('chmod +x ' + initd_bin)
|
||||
mw.execShell('sysrc ' + getPluginName() + '_enable="YES"')
|
||||
return 'ok'
|
||||
|
||||
mw.execShell('systemctl enable ' + getPluginName())
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdUinstall():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
|
||||
if current_os.startswith('freebsd'):
|
||||
initd_bin = getInitDFile()
|
||||
os.remove(initd_bin)
|
||||
mw.execShell('sysrc ' + getPluginName() + '_enable="NO"')
|
||||
return 'ok'
|
||||
|
||||
mw.execShell('systemctl disable ' + getPluginName())
|
||||
return 'ok'
|
||||
|
||||
|
||||
def runLog():
|
||||
return getServerDir() + '/logs.pl'
|
||||
|
||||
def pSqliteDb(dbname='databases'):
|
||||
pos_file = getServerDir() + '/data/'
|
||||
file = pos_file + '/data.db'
|
||||
name = 'data'
|
||||
conn = mw.M(dbname).dbPos(pos_file, name)
|
||||
return conn
|
||||
|
||||
def getCloudrevePort():
|
||||
file = getConf()
|
||||
content = mw.readFile(file)
|
||||
rep = r'Listen\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
return tmp.groups()[0].strip()
|
||||
|
||||
def homePage():
|
||||
http_port = getCloudrevePort()
|
||||
ip = mw.getLocalIp()
|
||||
if mw.isAppleSystem():
|
||||
ip = '127.0.0.1'
|
||||
url = 'http://'+ip+""+str(http_port)
|
||||
# print(url)
|
||||
return mw.returnJson(True, 'ok!', url)
|
||||
|
||||
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 == 'initd_status':
|
||||
print(initdStatus())
|
||||
elif func == 'initd_install':
|
||||
print(initdInstall())
|
||||
elif func == 'initd_uninstall':
|
||||
print(initdUinstall())
|
||||
elif func == 'conf':
|
||||
print(getConf())
|
||||
elif func == 'run_log':
|
||||
print(runLog())
|
||||
elif func == 'config_tpl':
|
||||
print(configTpl())
|
||||
elif func == 'read_config_tpl':
|
||||
print(readConfigTpl())
|
||||
elif func == 'home_page':
|
||||
print(homePage())
|
||||
else:
|
||||
print('error')
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"sort": 7,
|
||||
"ps": "一个支持多种存储的文件列表程序",
|
||||
"name": "cloudreve",
|
||||
"title": "cloudreve",
|
||||
"shell": "install.sh",
|
||||
"versions":["3.8.3"],
|
||||
"tip": "soft",
|
||||
"checks": "server/cloudreve",
|
||||
"path": "server/cloudreve",
|
||||
"display": 1,
|
||||
"author": "cloudreve",
|
||||
"date": "2024-10-14",
|
||||
"home": "https://cloudreve.org/",
|
||||
"type": 0,
|
||||
"pid": "5"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=A file list program that supports multiple storage
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory={$SERVER_PATH}/cloudreve
|
||||
ExecStart={$SERVER_PATH}/cloudreve/cloudreve
|
||||
ExecReload=/bin/kill -USR2 $MAINPID
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,46 @@
|
||||
#!/bin/sh
|
||||
# chkconfig: 2345 55 25
|
||||
# description: cloudreve Service
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: cloudreve
|
||||
# Required-Start: $all
|
||||
# Required-Stop: $all
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: starts cloudreve
|
||||
# Description: starts the MDW-Web
|
||||
### END INIT INFO
|
||||
|
||||
# Simple cloudreve init.d script conceived to work on Linux systems
|
||||
# as it does use of the /proc filesystem.
|
||||
|
||||
app_start(){
|
||||
echo "Starting cloudreve server..."
|
||||
cd {$SERVER_PATH}/cloudreve
|
||||
./cloudreve >> {$SERVER_PATH}/cloudreve/logs.pl 2>&1 &
|
||||
}
|
||||
|
||||
app_stop(){
|
||||
echo "dztasks stopped"
|
||||
ps -ef| grep cloudreve | grep -v grep | grep -v python | grep -v sh | awk '{print $2}'| xargs kill
|
||||
}
|
||||
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
app_start
|
||||
;;
|
||||
stop)
|
||||
app_stop
|
||||
;;
|
||||
restart|reload)
|
||||
app_stop
|
||||
sleep 0.3
|
||||
app_start
|
||||
;;
|
||||
*)
|
||||
echo "Please use start or stop as first argument"
|
||||
;;
|
||||
esac
|
||||
|
||||
Executable
+91
@@ -0,0 +1,91 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/cloudreve && bash install.sh install 3.8.3
|
||||
# cd /www/server/mdserver-web/plugins/cloudreve && bash install.sh install 3.8.3
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=$2
|
||||
|
||||
sysArch=`arch`
|
||||
sysName=`uname`
|
||||
|
||||
ALIST_ARCH_NAME=amd64
|
||||
if [ "$sysArch" == "arm64" ];then
|
||||
ALIST_ARCH_NAME=arm64
|
||||
elif [ "$sysArch" == "x86_64" ]; then
|
||||
ALIST_ARCH_NAME=amd64
|
||||
elif [ "$sysArch" == "aarch64" ]; then
|
||||
ALIST_ARCH_NAME=aarch64
|
||||
fi
|
||||
|
||||
ALIST_NAME=linux
|
||||
if [ "$sysName" == "Darwin" ];then
|
||||
ALIST_NAME=darwin
|
||||
fi
|
||||
|
||||
Install_App()
|
||||
{
|
||||
echo '正在安装脚本文件...'
|
||||
|
||||
mkdir -p $serverPath/source
|
||||
mkdir -p $serverPath/source/cloudreve
|
||||
|
||||
FILE_TGZ=cloudreve_${VERSION}_${ALIST_NAME}_${ALIST_ARCH_NAME}.tar.gz
|
||||
CLOUDREVE_DIR=$serverPath/source/cloudreve
|
||||
|
||||
if [ ! -f $CLOUDREVE_DIR/${FILE_TGZ} ];then
|
||||
wget -O $CLOUDREVE_DIR/${FILE_TGZ} https://github.com/cloudreve/Cloudreve/releases/download/${VERSION}/${FILE_TGZ}
|
||||
fi
|
||||
|
||||
mkdir -p $serverPath/cloudreve
|
||||
|
||||
cd $CLOUDREVE_DIR && tar -zxvf ${FILE_TGZ} -C $serverPath/cloudreve
|
||||
echo "${VERSION}" > $serverPath/cloudreve/version.pl
|
||||
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/cloudreve/index.py start
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/cloudreve/index.py initd_install
|
||||
|
||||
# cd $serverPath/cloudreve && ./alist admin set admin
|
||||
echo '安装cloudreve完成'
|
||||
}
|
||||
|
||||
Uninstall_App()
|
||||
{
|
||||
if [ -f /usr/lib/systemd/system/cloudreve.service ];then
|
||||
systemctl stop cloudreve
|
||||
systemctl disable cloudreve
|
||||
rm -rf /usr/lib/systemd/system/cloudreve.service
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
|
||||
if [ -f /lib/systemd/system/cloudreve.service ];then
|
||||
systemctl stop cloudreve
|
||||
systemctl disable cloudreve
|
||||
rm -rf /lib/systemd/system/cloudreve.service
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
|
||||
if [ -f $serverPath/cloudreve/initd/cloudreve ];then
|
||||
$serverPath/cloudreve/initd/cloudreve stop
|
||||
fi
|
||||
|
||||
if [ -d $serverPath/cloudreve ];then
|
||||
rm -rf $serverPath/cloudreve
|
||||
fi
|
||||
|
||||
echo "卸载cloudreve成功"
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_App
|
||||
else
|
||||
Uninstall_App
|
||||
fi
|
||||
Executable
+82
@@ -0,0 +1,82 @@
|
||||
function alistPost(method, version, args,callback){
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
|
||||
var req_data = {};
|
||||
req_data['name'] = 'cloudreve';
|
||||
req_data['func'] = method;
|
||||
req_data['version'] = version;
|
||||
|
||||
if (typeof(args) == 'string'){
|
||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
req_data['args'] = JSON.stringify(args);
|
||||
}
|
||||
|
||||
$.post('/plugins/run', req_data, function(data) {
|
||||
layer.close(loadT);
|
||||
if (!data.status){
|
||||
//错误展示10S
|
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof(callback) == 'function'){
|
||||
callback(data);
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
|
||||
function alistPostCallbak(method, version, args,callback){
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
|
||||
var req_data = {};
|
||||
req_data['name'] = 'cloudreve';
|
||||
req_data['func'] = method;
|
||||
args['version'] = version;
|
||||
|
||||
if (typeof(args) == 'string'){
|
||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
req_data['args'] = JSON.stringify(args);
|
||||
}
|
||||
|
||||
$.post('/plugins/callback', req_data, 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 commonHomePage(){
|
||||
alistPost('home_page', '', {}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
window.open(rdata.data);
|
||||
});
|
||||
}
|
||||
|
||||
function alistCommonFunc(){
|
||||
var con = '';
|
||||
con += '<hr/><p class="conf_p" style="text-align:center;">\
|
||||
<button class="btn btn-default btn-sm" onclick="commonHomePage()">主页</button>\
|
||||
</p>';
|
||||
|
||||
$(".soft-man-con").html(con);
|
||||
}
|
||||
|
||||
function alistReadme(){
|
||||
|
||||
|
||||
var readme = '<ul class="help-info-text c7">';
|
||||
readme += '<li>记住安装时生成的用户+密码</li>';
|
||||
readme += '</ul>';
|
||||
|
||||
$('.soft-man-con').html(readme);
|
||||
}
|
||||
|
||||
@@ -11,8 +11,12 @@ import re
|
||||
import json
|
||||
import pymemcache
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
try:
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
except Exception as e:
|
||||
import core.mw as mw
|
||||
|
||||
|
||||
def singleton(cls):
|
||||
_instance = {}
|
||||
|
||||
@@ -12,8 +12,11 @@ import yaml
|
||||
from bson.objectid import ObjectId
|
||||
from bson.json_util import dumps
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
try:
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
except Exception as e:
|
||||
import core.mw as mw
|
||||
|
||||
def singleton(cls):
|
||||
_instance = {}
|
||||
@@ -262,7 +265,12 @@ class nosqlMongodbCtr():
|
||||
|
||||
# print(where)
|
||||
result = collection_instance.find(where).skip(start_index).limit(size).sort('_id',-1)
|
||||
count = collection_instance.count_documents(where)
|
||||
if where:
|
||||
count = collection_instance.count_documents(where)
|
||||
else:
|
||||
collection_stats = db_instance.command("collStats", collection)
|
||||
count = collection_stats.get("count")
|
||||
|
||||
d = []
|
||||
for document in result:
|
||||
d.append(document)
|
||||
|
||||
@@ -7,8 +7,13 @@ import time
|
||||
import re
|
||||
import redis
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
try:
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
except Exception as e:
|
||||
import core.mw as mw
|
||||
|
||||
|
||||
# def getPluginName():
|
||||
# return 'data_query'
|
||||
|
||||
@@ -8,9 +8,11 @@ import re
|
||||
import pymongo
|
||||
import json
|
||||
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
try:
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
except Exception as e:
|
||||
import core.mw as mw
|
||||
|
||||
def singleton(cls):
|
||||
_instance = {}
|
||||
@@ -167,6 +169,19 @@ class nosqlMySQLCtr():
|
||||
sid = args['sid']
|
||||
db = args['db']
|
||||
table = args['table']
|
||||
if table == '':
|
||||
page_args = {}
|
||||
page_args['count'] = 0
|
||||
page_args['tojs'] = 'mysqlGetDataList'
|
||||
page_args['p'] = 1
|
||||
page_args['row'] = 10
|
||||
|
||||
rdata = {}
|
||||
rdata['page'] = mw.getPage(page_args)
|
||||
rdata['list'] = []
|
||||
rdata['count'] = 0
|
||||
return mw.returnData(True,'ok', rdata)
|
||||
|
||||
p = 1
|
||||
size = 10
|
||||
if 'p' in args:
|
||||
@@ -223,6 +238,7 @@ class nosqlMySQLCtr():
|
||||
rdata['soso_field'] = ''
|
||||
if 'field' in args_where:
|
||||
rdata['soso_field'] = args_where['field']
|
||||
|
||||
return mw.returnData(True,'ok', rdata)
|
||||
|
||||
def showProcessList(self,args):
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<div class="bgw mtb15 pd15 tab-view-box firewall-tab-view safe" style="overflow: hidden;">
|
||||
|
||||
<div class="mask_layer" style="display:none;">
|
||||
<div class="prompt_description">当前未安装本地服务器,<a class="btlink install_server" href="/soft">点击安装</a></div>
|
||||
<div class="prompt_description">当前未安装本地服务器,<a class="btlink install_server" href="/soft/index">点击安装</a></div>
|
||||
</div>
|
||||
|
||||
<!-- mysql start -->
|
||||
@@ -135,7 +135,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pull-right" style="padding-top: 5px;">
|
||||
<div id="mongodb_select" class="pull-right" style="padding-top: 5px;">
|
||||
<div class="server_list" style="float:left;">
|
||||
<select name="sid" class="bt-input-text c5 mr5">
|
||||
<option value="0">本地服务器</option>
|
||||
|
||||
@@ -227,7 +227,6 @@ function initTabMongodb(){
|
||||
}
|
||||
|
||||
|
||||
|
||||
function initTabMemcached(){
|
||||
memcachedGetList();
|
||||
|
||||
@@ -288,7 +287,11 @@ function mysqlGetDbName(){
|
||||
}
|
||||
|
||||
function mysqlGetTableName(){
|
||||
return $('#mysql .mysql_table_list select[name=mysql_table]').val();
|
||||
var table = $('#mysql .mysql_table_list select[name=mysql_table]').val();
|
||||
if (!table){
|
||||
return '';
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
function mysqlInitField(f, data){
|
||||
@@ -397,7 +400,7 @@ function mysqlGetDataList(p){
|
||||
} else {
|
||||
request_data['where'] = {};
|
||||
}
|
||||
// console.log(request_data);
|
||||
|
||||
myPostCB('get_data_list',request_data ,function(rdata){
|
||||
|
||||
if (rdata.data.status){
|
||||
@@ -758,6 +761,7 @@ function mongodbCollectionName(){
|
||||
function mongodbGetList(){
|
||||
var sid = mongodbGetSid();
|
||||
mgdbPostCB('get_db_list',{'sid':sid} ,function(rdata){
|
||||
// console.log(rdata);
|
||||
if (rdata.data.status){
|
||||
var list = rdata.data.data['list'];
|
||||
var content = '';
|
||||
@@ -775,6 +779,11 @@ function mongodbGetList(){
|
||||
mongodbGetCollections(list[0]);
|
||||
}
|
||||
|
||||
$('#mongodb_select .db_list select[name="db"]').change(function(){
|
||||
var collection_name = $(this).val();
|
||||
mongodbGetCollections(collection_name);
|
||||
});
|
||||
|
||||
closeInstallLayer();
|
||||
} else {
|
||||
showInstallLayer();
|
||||
@@ -787,6 +796,7 @@ function mongodbGetCollections(name){
|
||||
var sid = mongodbGetSid();
|
||||
|
||||
mgdbPostCB('get_collections_list',{'sid':sid,'name':name} ,function(rdata){
|
||||
// console.log(rdata);
|
||||
if (rdata.data.status){
|
||||
var list = rdata.data.data['collections'];
|
||||
|
||||
@@ -817,13 +827,19 @@ function mongodbGetCollections(name){
|
||||
var isAdd = data.isAdd;
|
||||
if (isAdd){
|
||||
$('#mongodb').data('collection',change[0].value);
|
||||
mongodbDataList(1);
|
||||
|
||||
setTimeout(function(){
|
||||
mongodbDataList(1);
|
||||
},200);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
if (select_list.length > 0){
|
||||
mongodbDataList(1);
|
||||
|
||||
setTimeout(function(){
|
||||
mongodbDataList(1);
|
||||
},200);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -10,7 +10,11 @@ import json
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
import docker
|
||||
try:
|
||||
import docker
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
app_debug = False
|
||||
|
||||
@@ -0,0 +1,594 @@
|
||||
[INCLUDES]
|
||||
before = paths-debian.conf
|
||||
|
||||
[DEFAULT]
|
||||
backend = systemd
|
||||
ignorecommand =
|
||||
bantime = 10m
|
||||
findtime = 10m
|
||||
maxretry = 5
|
||||
|
||||
maxmatches = %(maxretry)s
|
||||
usedns = warn
|
||||
logencoding = auto
|
||||
enabled = false
|
||||
mode = normal
|
||||
filter = %(__name__)s[mode=%(mode)s]
|
||||
|
||||
destemail = root@localhost
|
||||
|
||||
sender = root@<fq-hostname>
|
||||
|
||||
mta = sendmail
|
||||
|
||||
protocol = tcp
|
||||
|
||||
chain = <known/chain>
|
||||
|
||||
port = 0:65535
|
||||
|
||||
fail2ban_agent = Fail2Ban/%(fail2ban_version)s
|
||||
|
||||
|
||||
banaction = iptables-multiport
|
||||
banaction_allports = iptables-allports
|
||||
|
||||
action_ = %(banaction)s[port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
|
||||
action_mw = %(action_)s
|
||||
%(mta)s-whois[sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
|
||||
action_mwl = %(action_)s
|
||||
%(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
|
||||
|
||||
action_xarf = %(action_)s
|
||||
xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath="%(logpath)s", port="%(port)s"]
|
||||
|
||||
action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"]
|
||||
%(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
|
||||
|
||||
action_blocklist_de = blocklist_de[email="%(sender)s", service="%(__name__)s", apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"]
|
||||
|
||||
action_badips = badips.py[category="%(__name__)s", banaction="%(banaction)s", agent="%(fail2ban_agent)s"]
|
||||
action_badips_report = badips[category="%(__name__)s", agent="%(fail2ban_agent)s"]
|
||||
|
||||
action_abuseipdb = abuseipdb
|
||||
|
||||
action = %(action_)s
|
||||
|
||||
[sshd]
|
||||
port = ssh
|
||||
logpath = %(sshd_log)s
|
||||
backend = %(sshd_backend)s
|
||||
|
||||
[dropbear]
|
||||
port = ssh
|
||||
logpath = %(dropbear_log)s
|
||||
backend = %(dropbear_backend)s
|
||||
|
||||
|
||||
[selinux-ssh]
|
||||
port = ssh
|
||||
logpath = %(auditd_log)s
|
||||
|
||||
|
||||
[apache-auth]
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
|
||||
[apache-badbots]
|
||||
port = http,https
|
||||
logpath = %(apache_access_log)s
|
||||
bantime = 48h
|
||||
maxretry = 1
|
||||
|
||||
[apache-noscript]
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
|
||||
|
||||
[apache-overflows]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
[apache-nohome]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
[apache-botsearch]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
[apache-fakegooglebot]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_access_log)s
|
||||
maxretry = 1
|
||||
ignorecommand = %(ignorecommands_dir)s/apache-fakegooglebot <ip>
|
||||
|
||||
|
||||
[apache-modsecurity]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
[apache-shellshock]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 1
|
||||
|
||||
|
||||
[openhab-auth]
|
||||
|
||||
filter = openhab
|
||||
banaction = %(banaction_allports)s
|
||||
logpath = /opt/openhab/logs/request.log
|
||||
|
||||
|
||||
[nginx-http-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = %(nginx_error_log)s
|
||||
|
||||
[nginx-limit-req]
|
||||
port = http,https
|
||||
logpath = %(nginx_error_log)s
|
||||
|
||||
[nginx-botsearch]
|
||||
|
||||
port = http,https
|
||||
logpath = %(nginx_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
|
||||
[php-url-fopen]
|
||||
|
||||
port = http,https
|
||||
logpath = %(nginx_access_log)s
|
||||
%(apache_access_log)s
|
||||
|
||||
|
||||
[suhosin]
|
||||
|
||||
port = http,https
|
||||
logpath = %(suhosin_log)s
|
||||
|
||||
|
||||
[lighttpd-auth]
|
||||
port = http,https
|
||||
logpath = %(lighttpd_error_log)s
|
||||
|
||||
|
||||
|
||||
[roundcube-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = %(roundcube_errors_log)s
|
||||
|
||||
|
||||
[openwebmail]
|
||||
|
||||
port = http,https
|
||||
logpath = /var/log/openwebmail.log
|
||||
|
||||
|
||||
[horde]
|
||||
|
||||
port = http,https
|
||||
logpath = /var/log/horde/horde.log
|
||||
|
||||
|
||||
[groupoffice]
|
||||
|
||||
port = http,https
|
||||
logpath = /home/groupoffice/log/info.log
|
||||
|
||||
|
||||
[sogo-auth]
|
||||
port = http,https
|
||||
logpath = /var/log/sogo/sogo.log
|
||||
|
||||
|
||||
[tine20]
|
||||
|
||||
logpath = /var/log/tine20/tine20.log
|
||||
port = http,https
|
||||
|
||||
|
||||
|
||||
[drupal-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = %(syslog_daemon)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
[guacamole]
|
||||
|
||||
port = http,https
|
||||
logpath = /var/log/tomcat*/catalina.out
|
||||
|
||||
[monit]
|
||||
port = 2812
|
||||
logpath = /var/log/monit
|
||||
/var/log/monit.log
|
||||
|
||||
|
||||
[webmin-auth]
|
||||
|
||||
port = 10000
|
||||
logpath = %(syslog_authpriv)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[froxlor-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = %(syslog_authpriv)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
|
||||
[squid]
|
||||
|
||||
port = 80,443,3128,8080
|
||||
logpath = /var/log/squid/access.log
|
||||
|
||||
|
||||
[3proxy]
|
||||
|
||||
port = 3128
|
||||
logpath = /var/log/3proxy.log
|
||||
|
||||
|
||||
|
||||
|
||||
[proftpd]
|
||||
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(proftpd_log)s
|
||||
backend = %(proftpd_backend)s
|
||||
|
||||
|
||||
[pure-ftpd]
|
||||
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(pureftpd_log)s
|
||||
backend = %(pureftpd_backend)s
|
||||
|
||||
|
||||
[gssftpd]
|
||||
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(syslog_daemon)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[wuftpd]
|
||||
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(wuftpd_log)s
|
||||
backend = %(wuftpd_backend)s
|
||||
|
||||
|
||||
[vsftpd]
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(vsftpd_log)s
|
||||
|
||||
|
||||
|
||||
[assp]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = /root/path/to/assp/logs/maillog.txt
|
||||
|
||||
|
||||
[courier-smtp]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[postfix]
|
||||
mode = more
|
||||
port = smtp,465,submission
|
||||
logpath = %(postfix_log)s
|
||||
backend = %(postfix_backend)s
|
||||
|
||||
|
||||
[postfix-rbl]
|
||||
|
||||
filter = postfix[mode=rbl]
|
||||
port = smtp,465,submission
|
||||
logpath = %(postfix_log)s
|
||||
backend = %(postfix_backend)s
|
||||
maxretry = 1
|
||||
|
||||
|
||||
[sendmail-auth]
|
||||
|
||||
port = submission,465,smtp
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[sendmail-reject]
|
||||
port = smtp,465,submission
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[qmail-rbl]
|
||||
|
||||
filter = qmail
|
||||
port = smtp,465,submission
|
||||
logpath = /service/qmail/log/main/current
|
||||
|
||||
|
||||
[dovecot]
|
||||
|
||||
port = pop3,pop3s,imap,imaps,submission,465,sieve
|
||||
logpath = %(dovecot_log)s
|
||||
backend = %(dovecot_backend)s
|
||||
|
||||
|
||||
[sieve]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = %(dovecot_log)s
|
||||
backend = %(dovecot_backend)s
|
||||
|
||||
|
||||
[solid-pop3d]
|
||||
|
||||
port = pop3,pop3s
|
||||
logpath = %(solidpop3d_log)s
|
||||
|
||||
|
||||
[exim]
|
||||
port = smtp,465,submission
|
||||
logpath = %(exim_main_log)s
|
||||
|
||||
|
||||
[exim-spam]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = %(exim_main_log)s
|
||||
|
||||
|
||||
[kerio]
|
||||
|
||||
port = imap,smtp,imaps,465
|
||||
logpath = /opt/kerio/mailserver/store/logs/security.log
|
||||
|
||||
|
||||
|
||||
[courier-auth]
|
||||
port = smtp,465,submission,imap,imaps,pop3,pop3s
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[postfix-sasl]
|
||||
filter = postfix[mode=auth]
|
||||
port = smtp,465,submission,imap,imaps,pop3,pop3s
|
||||
logpath = %(postfix_log)s
|
||||
backend = %(postfix_backend)s
|
||||
|
||||
|
||||
[perdition]
|
||||
port = imap,imaps,pop3,pop3s
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[squirrelmail]
|
||||
port = smtp,465,submission,imap,imap2,imaps,pop3,pop3s,http,https,socks
|
||||
logpath = /var/lib/squirrelmail/prefs/squirrelmail_access_log
|
||||
|
||||
|
||||
[cyrus-imap]
|
||||
port = imap,imaps
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[uwimap-auth]
|
||||
port = imap,imaps
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[named-refused]
|
||||
port = domain,953
|
||||
logpath = /var/log/named/security.log
|
||||
|
||||
|
||||
[nsd]
|
||||
|
||||
port = 53
|
||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||
logpath = /var/log/nsd.log
|
||||
|
||||
|
||||
|
||||
[asterisk]
|
||||
port = 5060,5061
|
||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||
logpath = /var/log/asterisk/messages
|
||||
maxretry = 10
|
||||
|
||||
|
||||
[freeswitch]
|
||||
port = 5060,5061
|
||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||
logpath = /var/log/freeswitch.log
|
||||
maxretry = 10
|
||||
|
||||
|
||||
[znc-adminlog]
|
||||
port = 6667
|
||||
logpath = /var/lib/znc/moddata/adminlog/znc.log
|
||||
|
||||
|
||||
[mysqld-auth]
|
||||
|
||||
port = 3306
|
||||
logpath = %(mysql_log)s
|
||||
backend = %(mysql_backend)s
|
||||
|
||||
|
||||
[mongodb-auth]
|
||||
port = 27017
|
||||
logpath = /var/log/mongodb/mongodb.log
|
||||
|
||||
|
||||
[recidive]
|
||||
|
||||
logpath = /var/log/fail2ban.log
|
||||
banaction = %(banaction_allports)s
|
||||
bantime = 1w
|
||||
findtime = 1d
|
||||
|
||||
[pam-generic]
|
||||
banaction = %(banaction_allports)s
|
||||
logpath = %(syslog_authpriv)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[xinetd-fail]
|
||||
|
||||
banaction = iptables-multiport-log
|
||||
logpath = %(syslog_daemon)s
|
||||
backend = %(syslog_backend)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
[stunnel]
|
||||
|
||||
logpath = /var/log/stunnel4/stunnel.log
|
||||
|
||||
|
||||
[ejabberd-auth]
|
||||
|
||||
port = 5222
|
||||
logpath = /var/log/ejabberd/ejabberd.log
|
||||
|
||||
|
||||
[counter-strike]
|
||||
|
||||
logpath = /opt/cstrike/logs/L[0-9]*.log
|
||||
tcpport = 27030,27031,27032,27033,27034,27035,27036,27037,27038,27039
|
||||
udpport = 1200,27000,27001,27002,27003,27004,27005,27006,27007,27008,27009,27010,27011,27012,27013,27014,27015
|
||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, port="%(tcpport)s", protocol="tcp"]
|
||||
%(default/action_)s[name=%(__name__)s-udp, port="%(udpport)s", protocol="udp"]
|
||||
|
||||
[softethervpn]
|
||||
port = 500,4500
|
||||
protocol = udp
|
||||
logpath = /usr/local/vpnserver/security_log/*/sec.log
|
||||
|
||||
[gitlab]
|
||||
port = http,https
|
||||
logpath = /var/log/gitlab/gitlab-rails/application.log
|
||||
|
||||
[grafana]
|
||||
port = http,https
|
||||
logpath = /var/log/grafana/grafana.log
|
||||
|
||||
[bitwarden]
|
||||
port = http,https
|
||||
logpath = /home/*/bwdata/logs/identity/Identity/log.txt
|
||||
|
||||
[centreon]
|
||||
port = http,https
|
||||
logpath = /var/log/centreon/login.log
|
||||
|
||||
[nagios]
|
||||
|
||||
logpath = %(syslog_daemon)s ; nrpe.cfg may define a different log_facility
|
||||
backend = %(syslog_backend)s
|
||||
maxretry = 1
|
||||
|
||||
|
||||
[oracleims]
|
||||
logpath = /opt/sun/comms/messaging64/log/mail.log_current
|
||||
banaction = %(banaction_allports)s
|
||||
|
||||
[directadmin]
|
||||
logpath = /var/log/directadmin/login.log
|
||||
port = 2222
|
||||
|
||||
[portsentry]
|
||||
logpath = /var/lib/portsentry/portsentry.history
|
||||
maxretry = 1
|
||||
|
||||
[pass2allow-ftp]
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
knocking_url = /knocking/
|
||||
filter = apache-pass[knocking_url="%(knocking_url)s"]
|
||||
logpath = %(apache_access_log)s
|
||||
blocktype = RETURN
|
||||
returntype = DROP
|
||||
action = %(action_)s[blocktype=%(blocktype)s, returntype=%(returntype)s,
|
||||
actionstart_on_demand=false, actionrepair_on_unban=true]
|
||||
bantime = 1h
|
||||
maxretry = 1
|
||||
findtime = 1
|
||||
|
||||
|
||||
[murmur]
|
||||
port = 64738
|
||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||
logpath = /var/log/mumble-server/mumble-server.log
|
||||
|
||||
|
||||
[screensharingd]
|
||||
logpath = /var/log/system.log
|
||||
logencoding = utf-8
|
||||
|
||||
[haproxy-http-auth]
|
||||
logpath = /var/log/haproxy.log
|
||||
|
||||
[slapd]
|
||||
port = ldap,ldaps
|
||||
logpath = /var/log/slapd.log
|
||||
|
||||
[domino-smtp]
|
||||
port = smtp,ssmtp
|
||||
logpath = /home/domino01/data/IBM_TECHNICAL_SUPPORT/console.log
|
||||
|
||||
[phpmyadmin-syslog]
|
||||
port = http,https
|
||||
logpath = %(syslog_authpriv)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[zoneminder]
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
|
||||
[traefik-auth]
|
||||
port = http,https
|
||||
logpath = /var/log/traefik/access.log
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
Executable
+32
@@ -0,0 +1,32 @@
|
||||
<style>
|
||||
.overflow_hide {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="bt-form">
|
||||
<div class='plugin_version'></div>
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<p class="bgw" onclick="pluginService('fail2ban');">服务</p>
|
||||
<p onclick="pluginInitD('fail2ban');">自启动</p>
|
||||
<p onclick="pluginConfigTpl('fail2ban',$('.plugin_version').attr('version'));">配置修改</p>
|
||||
<p onclick="f2bBanIp();">IP黑名单</p>
|
||||
<!-- <p onclick="redisStatus($('.plugin_version').attr('version'));">负载状态</p> -->
|
||||
<p onclick="pluginLogs('fail2ban','','run_log');">运行日志</p>
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
<div class="soft-man-con" style="height: 520px; overflow: auto;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
resetPluginWinWidth(1000);
|
||||
// resetPluginWinHeight(500);
|
||||
$.getScript( "/plugins/file?name=fail2ban&f=js/fail2ban.js", function(){
|
||||
pluginService('fail2ban', $('.plugin_version').attr('version'));
|
||||
});
|
||||
</script>
|
||||
Executable
+384
@@ -0,0 +1,384 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import json
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'fail2ban'
|
||||
|
||||
def f2bDir():
|
||||
return '/run/'+getPluginName()
|
||||
|
||||
def f2bEtcDir():
|
||||
return '/etc/'+getPluginName()
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getInitDFile():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return '/tmp/' + getPluginName()
|
||||
|
||||
if current_os.startswith('freebsd'):
|
||||
return '/etc/rc.d/' + getPluginName()
|
||||
|
||||
return '/etc/init.d/' + getPluginName()
|
||||
|
||||
|
||||
def getConf():
|
||||
path = f2bEtcDir() + "/fail2ban.conf"
|
||||
return path
|
||||
|
||||
|
||||
def getConfTpl():
|
||||
path = getPluginDir() + "/tpl/fail2ban.conf"
|
||||
return path
|
||||
|
||||
|
||||
def getInitDTpl():
|
||||
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
|
||||
return path
|
||||
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[3:]
|
||||
tmp = {}
|
||||
args_len = len(args)
|
||||
|
||||
if args_len == 1:
|
||||
t = args[0].strip('{').strip('}')
|
||||
if t.strip() == '':
|
||||
tmp = []
|
||||
else:
|
||||
t = t.split(':')
|
||||
tmp[t[0]] = t[1]
|
||||
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 configTpl():
|
||||
path = f2bEtcDir()
|
||||
pathFile = os.listdir(path)
|
||||
tmp = []
|
||||
for one in pathFile:
|
||||
if one.endswith("conf"):
|
||||
file = path + '/' + one
|
||||
tmp.append(file)
|
||||
return mw.getJson(tmp)
|
||||
|
||||
|
||||
def readConfigTpl():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
content = mw.readFile(args['file'])
|
||||
content = contentReplace(content)
|
||||
return mw.returnJson(True, 'ok', content)
|
||||
|
||||
def runLog():
|
||||
return '/var/log/fail2ban.log'
|
||||
|
||||
def getPidFile():
|
||||
f2dir = f2bDir()
|
||||
return f2dir+'/fail2ban.pid'
|
||||
|
||||
def status():
|
||||
pid_file = getPidFile()
|
||||
if not os.path.exists(pid_file):
|
||||
return 'stop'
|
||||
return 'start'
|
||||
|
||||
def contentReplace(content):
|
||||
service_path = mw.getServerDir()
|
||||
content = content.replace('{$ROOT_PATH}', mw.getRootDir())
|
||||
content = content.replace('{$SERVER_PATH}', service_path)
|
||||
return content
|
||||
|
||||
|
||||
def initFail2BanD():
|
||||
dst_conf = f2bEtcDir() + '/fail2ban.d/default.conf'
|
||||
dst_conf_tpl = getPluginDir() + '/tpl/fail2ban.d/default.conf'
|
||||
if not os.path.exists(dst_conf):
|
||||
content = mw.readFile(dst_conf_tpl)
|
||||
content = contentReplace(content)
|
||||
mw.writeFile(dst_conf, content)
|
||||
|
||||
def initJailD():
|
||||
dst_conf = f2bEtcDir() + '/jail.d/default.conf'
|
||||
dst_conf_tpl = getPluginDir() + '/tpl/jail.d/default.conf'
|
||||
if not os.path.exists(dst_conf):
|
||||
content = mw.readFile(dst_conf_tpl)
|
||||
content = contentReplace(content)
|
||||
mw.writeFile(dst_conf, content)
|
||||
|
||||
def initDreplace():
|
||||
|
||||
file_tpl = getInitDTpl()
|
||||
service_path = os.path.dirname(os.getcwd())
|
||||
|
||||
initD_path = getServerDir() + '/init.d'
|
||||
if not os.path.exists(initD_path):
|
||||
os.mkdir(initD_path)
|
||||
file_bin = initD_path + '/' + getPluginName()
|
||||
|
||||
# config replace
|
||||
# dst_conf = getConf()
|
||||
# dst_conf_init = getServerDir() + '/init.pl'
|
||||
# if not os.path.exists(dst_conf_init):
|
||||
# content = mw.readFile(getConfTpl())
|
||||
# content = contentReplace(content)
|
||||
# mw.writeFile(dst_conf, content)
|
||||
# mw.writeFile(dst_conf_init, 'ok')
|
||||
|
||||
initFail2BanD()
|
||||
initJailD()
|
||||
|
||||
# systemd
|
||||
systemDir = mw.systemdCfgDir()
|
||||
systemService = systemDir + '/' + getPluginName() + '.service'
|
||||
if os.path.exists(systemDir) and not os.path.exists(systemService):
|
||||
systemServiceTpl = getPluginDir() + '/init.d/' + getPluginName() + '.service.tpl'
|
||||
service_path = mw.getServerDir()
|
||||
content = mw.readFile(systemServiceTpl)
|
||||
content = content.replace('{$SERVER_PATH}', service_path)
|
||||
mw.writeFile(systemService, content)
|
||||
mw.execShell('systemctl daemon-reload')
|
||||
|
||||
return file_bin
|
||||
|
||||
|
||||
def f2bOp(method):
|
||||
file = initDreplace()
|
||||
|
||||
current_os = mw.getOs()
|
||||
if current_os == "darwin":
|
||||
data = mw.execShell(file + ' ' + method)
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
if current_os.startswith("freebsd"):
|
||||
data = mw.execShell('service ' + getPluginName() + ' ' + method)
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
data = mw.execShell('systemctl ' + method + ' ' + getPluginName())
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
|
||||
def start():
|
||||
return f2bOp('start')
|
||||
|
||||
|
||||
def stop():
|
||||
return f2bOp('stop')
|
||||
|
||||
|
||||
def restart():
|
||||
status = f2bOp('restart')
|
||||
|
||||
log_file = runLog()
|
||||
mw.execShell("echo '' > " + log_file)
|
||||
return status
|
||||
|
||||
|
||||
def reload():
|
||||
return f2bOp('reload')
|
||||
|
||||
|
||||
def initdStatus():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
|
||||
if current_os.startswith('freebsd'):
|
||||
initd_bin = getInitDFile()
|
||||
if os.path.exists(initd_bin):
|
||||
return 'ok'
|
||||
|
||||
shell_cmd = 'systemctl status ' + \
|
||||
getPluginName() + ' | grep loaded | grep "enabled;"'
|
||||
data = mw.execShell(shell_cmd)
|
||||
if data[0] == '':
|
||||
return 'fail'
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdInstall():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
|
||||
# freebsd initd install
|
||||
if current_os.startswith('freebsd'):
|
||||
import shutil
|
||||
source_bin = initDreplace()
|
||||
initd_bin = getInitDFile()
|
||||
shutil.copyfile(source_bin, initd_bin)
|
||||
mw.execShell('chmod +x ' + initd_bin)
|
||||
mw.execShell('sysrc ' + getPluginName() + '_enable="YES"')
|
||||
return 'ok'
|
||||
|
||||
mw.execShell('systemctl enable ' + getPluginName())
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdUinstall():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
|
||||
if current_os.startswith('freebsd'):
|
||||
initd_bin = getInitDFile()
|
||||
os.remove(initd_bin)
|
||||
mw.execShell('sysrc ' + getPluginName() + '_enable="NO"')
|
||||
return 'ok'
|
||||
|
||||
mw.execShell('systemctl disable ' + getPluginName())
|
||||
return 'ok'
|
||||
|
||||
|
||||
# 读取配置
|
||||
def _read_conf(path, l=None):
|
||||
conf = mw.readFile(path)
|
||||
if not conf:
|
||||
if not l:
|
||||
conf = {}
|
||||
else:
|
||||
conf = []
|
||||
mw.writeFile(path, json.dumps(conf))
|
||||
return conf
|
||||
return json.loads(conf)
|
||||
|
||||
def getBlackFile():
|
||||
return getServerDir() + "/black_list.json"
|
||||
|
||||
|
||||
def getConfigFile():
|
||||
return getServerDir() + "/config.json"
|
||||
|
||||
|
||||
def getBlackListArr():
|
||||
_black_list = getBlackFile()
|
||||
conf = _read_conf(_black_list, l=1)
|
||||
if not conf:
|
||||
conf = []
|
||||
return conf
|
||||
|
||||
|
||||
def getBlackList():
|
||||
conf = getBlackListArr()
|
||||
content = "\n".join(conf)
|
||||
return mw.returnJson(True, 'ok', content)
|
||||
|
||||
def setBlackIp():
|
||||
ip_list = getBlackListArr()
|
||||
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['black_ip'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
new_ip_list = args['black_ip']
|
||||
add_ip_list = [new_ip for new_ip in new_ip_list if new_ip not in ip_list]
|
||||
del_ip_list = [del_ip for del_ip in ip_list if del_ip not in new_ip_list]
|
||||
rep_ip = "^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}($|[\\/\\d]+$)"
|
||||
rep_ipv6 = "^\\s*((([0-9A-Fa-f]{1,4}:){7}(([0-9A-Fa-f]{1,4})|:))|(([0-9A-Fa-f]{1,4}:){6}(:|((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})|(:[0-9A-Fa-f]{1,4})))|(([0-9A-Fa-f]{1,4}:){5}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){4}(:[0-9A-Fa-f]{1,4}){0,1}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Fa-f]{1,4}){0,2}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)(:[0-9A-Fa-f]{1,4}){0,4}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(:(:[0-9A-Fa-f]{1,4}){0,5}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})))(%.+)?\\s*$"
|
||||
|
||||
data = _read_conf(getConfigFile())
|
||||
|
||||
if new_ip_list == '':
|
||||
for d in data:
|
||||
for ip in ip_list:
|
||||
mw.execShell('fail2ban-client -vvv set {jail} unbanip {ip}'.format(jail=d, ip=ip))
|
||||
|
||||
mw.writeFile(getBlackFile(), json.dumps([]))
|
||||
return nw.returnJson(True, "禁止IP成功")
|
||||
|
||||
# 检查IP格式
|
||||
for ip in add_ip_list:
|
||||
if not re.search(rep_ip, ip) and not re.search(rep_ipv6, ip):
|
||||
return mw.returnJson(False, "IP格式错误 {}".format(ip))
|
||||
|
||||
# 添加新域名到黑名单
|
||||
for d in data:
|
||||
for ip in add_ip_list:
|
||||
mw.execShell('fail2ban-client -vvv set {jail} banip {ip}'.format(jail=d, ip=ip))
|
||||
|
||||
# 检查是否有清理掉的IP
|
||||
for d in data:
|
||||
for ip in del_ip_list:
|
||||
mw.execShell('fail2ban-client -vvv set {jail} unbanip {ip}'.format(jail=d, ip=ip))
|
||||
|
||||
for ip in add_ip_list:
|
||||
ip_list.append(ip)
|
||||
|
||||
mw.writeFile(getBlackFile(), json.dumps(ip_list))
|
||||
return mw.returnJson(True, "添加黑名单成功")
|
||||
|
||||
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 == 'initd_status':
|
||||
print(initdStatus())
|
||||
elif func == 'initd_install':
|
||||
print(initdInstall())
|
||||
elif func == 'initd_uninstall':
|
||||
print(initdUinstall())
|
||||
elif func == 'run_info':
|
||||
print(runInfo())
|
||||
elif func == 'conf':
|
||||
print(getConf())
|
||||
elif func == 'run_log':
|
||||
print(runLog())
|
||||
elif func == 'config_tpl':
|
||||
print(configTpl())
|
||||
elif func == 'read_config_tpl':
|
||||
print(readConfigTpl())
|
||||
elif func == 'get_black_list':
|
||||
print(getBlackList())
|
||||
elif func == 'set_black_ip':
|
||||
print(setBlackIp())
|
||||
else:
|
||||
print('error')
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"sort": 7,
|
||||
"ps": "防止恶意IP地址暴力破解服务、站点,禁止导致多个身份验证错误的主机",
|
||||
"name": "fail2ban",
|
||||
"title": "fail2ban",
|
||||
"shell": "install.sh",
|
||||
"versions":["1.1.0"],
|
||||
"updates":["1.1.0"],
|
||||
"tip": "soft",
|
||||
"checks": "server/fail2ban",
|
||||
"path": "server/fail2ban",
|
||||
"display": 1,
|
||||
"author": "fail2ban",
|
||||
"date": "2024-07-28",
|
||||
"home": "https://www.fail2ban.org",
|
||||
"type": 0,
|
||||
"pid": "4"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
[Unit]
|
||||
Description=Fail2Ban Service
|
||||
Documentation=man:fail2ban(1)
|
||||
After=network.target iptables.service firewalld.service ip6tables.service ipset.service nftables.service
|
||||
PartOf=firewalld.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Environment="PYTHONNOUSERSITE=1"
|
||||
ExecStartPre=/bin/mkdir -p /run/fail2ban
|
||||
ExecStart=/usr/bin/fail2ban-server -xf start
|
||||
# if should be logged in systemd journal, use following line or set logtarget to sysout in fail2ban.local
|
||||
# ExecStart=/usr/bin/fail2ban-server -xf --logtarget=sysout start
|
||||
ExecStop=/usr/bin/fail2ban-client stop
|
||||
ExecReload=/usr/bin/fail2ban-client reload
|
||||
PIDFile=/run/fail2ban/fail2ban.pid
|
||||
Restart=on-failure
|
||||
RestartPreventExitStatus=0 255
|
||||
Environment="PYTHONNOUSERSITE=yes"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Executable
+71
@@ -0,0 +1,71 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=$2
|
||||
|
||||
# cd /www/server/mdserver-web/plugins/fail2ban && bash install.sh install 1.1.0
|
||||
# cd /www/server/mdserver-web && python3 plugins/fail2ban/index.py config_tpl
|
||||
|
||||
Install_App()
|
||||
{
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
mkdir -p $serverPath/source
|
||||
|
||||
apt install -y fail2ban
|
||||
|
||||
mkdir -p $serverPath/fail2ban
|
||||
echo "${VERSION}" > $serverPath/fail2ban/version.pl
|
||||
echo '安装fail2ban完成'
|
||||
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/fail2ban/index.py start
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/fail2ban/index.py initd_install
|
||||
}
|
||||
|
||||
Uninstall_App()
|
||||
{
|
||||
apt remove -y fail2ban
|
||||
apt purge -y fail2ban
|
||||
|
||||
if [ -f /usr/lib/systemd/system/fail2ban.service ];then
|
||||
systemctl stop fail2ban
|
||||
systemctl disable fail2ban
|
||||
rm -rf /usr/lib/systemd/system/fail2ban.service
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
|
||||
if [ -f /lib/systemd/system/fail2ban.service ];then
|
||||
systemctl stop fail2ban
|
||||
systemctl disable fail2ban
|
||||
rm -rf /lib/systemd/system/fail2ban.service
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
|
||||
if [ -f $serverPath/fail2ban/initd/fail2ban ];then
|
||||
$serverPath/fail2ban/initd/fail2ban stop
|
||||
fi
|
||||
|
||||
if [ -d $serverPath/fail2ban ];then
|
||||
rm -rf $serverPath/fail2ban
|
||||
fi
|
||||
|
||||
if [ -d /etc/fail2ban ];then
|
||||
rm -rf /etc/fail2ban
|
||||
fi
|
||||
|
||||
echo "卸载fail2ban成功"
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_App
|
||||
else
|
||||
Uninstall_App
|
||||
fi
|
||||
Executable
+110
@@ -0,0 +1,110 @@
|
||||
function getVersion(){
|
||||
return $('.plugin_version').attr('version');
|
||||
}
|
||||
|
||||
function f2bPost(method, version, args,callback){
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
|
||||
var req_data = {};
|
||||
req_data['name'] = 'fail2ban';
|
||||
req_data['func'] = method;
|
||||
req_data['version'] = version;
|
||||
|
||||
if (typeof(args) == 'string'){
|
||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
req_data['args'] = JSON.stringify(args);
|
||||
}
|
||||
|
||||
$.post('/plugins/run', req_data, function(data) {
|
||||
layer.close(loadT);
|
||||
if (!data.status){
|
||||
//错误展示10S
|
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof(callback) == 'function'){
|
||||
callback(data);
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
|
||||
function f2bPostCallbak(method, version, args, callback){
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
|
||||
var req_data = {};
|
||||
req_data['name'] = 'fail2ban';
|
||||
req_data['func'] = method;
|
||||
args['version'] = version;
|
||||
|
||||
if (typeof(args) == 'string'){
|
||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
req_data['args'] = JSON.stringify(args);
|
||||
}
|
||||
|
||||
$.post('/plugins/callback', req_data, 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 f2bBanIpSave(black_ip){
|
||||
var ver = getVersion();
|
||||
f2bPost('set_black_ip', ver, {'black_ip':black_ip}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
|
||||
});
|
||||
}
|
||||
|
||||
function f2bBanIp(){
|
||||
var con = '<p style="color: #666; margin-bottom: 7px">提示:Ctrl+F 搜索关键字,Ctrl+G 查找下一个,Ctrl+S 保存,Ctrl+Shift+R 查找替换!</p>\
|
||||
<textarea class="bt-input-text" style="height: 320px; line-height:18px;" id="textBody"></textarea>\
|
||||
<button id="onlineEditFileBtn" class="btn btn-success btn-sm" style="margin-top:10px;">保存</button>\
|
||||
<ul class="help-info-text c7 ptb15">\
|
||||
<li>如有多个请以换行隔开例:<br/>\
|
||||
192.168.1.1<br/>\
|
||||
192.168.1.0/24\
|
||||
</li>\
|
||||
</ul>';
|
||||
|
||||
$(".soft-man-con").html(con);
|
||||
$("#textBody").empty();
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("textBody"), {
|
||||
extraKeys: {
|
||||
"Ctrl-Space": "autocomplete",
|
||||
"Ctrl-F": "findPersistent",
|
||||
"Ctrl-H": "replaceAll",
|
||||
"Ctrl-S": function() {
|
||||
$("#textBody").text(editor.getValue());
|
||||
f2bPost('set_black_list', '', {'black_ip':editor.getValue()}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
|
||||
});
|
||||
|
||||
f2bBanIpSave(editor.getValue());
|
||||
}
|
||||
},
|
||||
lineNumbers: true,
|
||||
matchBrackets:true,
|
||||
});
|
||||
editor.focus();
|
||||
|
||||
f2bPost('get_black_list', '', {}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
$("#textBody").text(rdata.data);
|
||||
});
|
||||
|
||||
$("#onlineEditFileBtn").click(function(){
|
||||
f2bBanIpSave(editor.getValue());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,594 @@
|
||||
[INCLUDES]
|
||||
before = paths-debian.conf
|
||||
|
||||
[DEFAULT]
|
||||
backend = systemd
|
||||
ignorecommand =
|
||||
bantime = 10m
|
||||
findtime = 10m
|
||||
maxretry = 5
|
||||
|
||||
maxmatches = %(maxretry)s
|
||||
usedns = warn
|
||||
logencoding = auto
|
||||
enabled = false
|
||||
mode = normal
|
||||
filter = %(__name__)s[mode=%(mode)s]
|
||||
|
||||
destemail = root@localhost
|
||||
|
||||
sender = root@<fq-hostname>
|
||||
|
||||
mta = sendmail
|
||||
|
||||
protocol = tcp
|
||||
|
||||
chain = <known/chain>
|
||||
|
||||
port = 0:65535
|
||||
|
||||
fail2ban_agent = Fail2Ban/%(fail2ban_version)s
|
||||
|
||||
|
||||
banaction = iptables-multiport
|
||||
banaction_allports = iptables-allports
|
||||
|
||||
action_ = %(banaction)s[port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
|
||||
action_mw = %(action_)s
|
||||
%(mta)s-whois[sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
|
||||
action_mwl = %(action_)s
|
||||
%(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
|
||||
|
||||
action_xarf = %(action_)s
|
||||
xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath="%(logpath)s", port="%(port)s"]
|
||||
|
||||
action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"]
|
||||
%(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
|
||||
|
||||
action_blocklist_de = blocklist_de[email="%(sender)s", service="%(__name__)s", apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"]
|
||||
|
||||
action_badips = badips.py[category="%(__name__)s", banaction="%(banaction)s", agent="%(fail2ban_agent)s"]
|
||||
action_badips_report = badips[category="%(__name__)s", agent="%(fail2ban_agent)s"]
|
||||
|
||||
action_abuseipdb = abuseipdb
|
||||
|
||||
action = %(action_)s
|
||||
|
||||
[sshd]
|
||||
port = ssh
|
||||
logpath = %(sshd_log)s
|
||||
backend = %(sshd_backend)s
|
||||
|
||||
[dropbear]
|
||||
port = ssh
|
||||
logpath = %(dropbear_log)s
|
||||
backend = %(dropbear_backend)s
|
||||
|
||||
|
||||
[selinux-ssh]
|
||||
port = ssh
|
||||
logpath = %(auditd_log)s
|
||||
|
||||
|
||||
[apache-auth]
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
|
||||
[apache-badbots]
|
||||
port = http,https
|
||||
logpath = %(apache_access_log)s
|
||||
bantime = 48h
|
||||
maxretry = 1
|
||||
|
||||
[apache-noscript]
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
|
||||
|
||||
[apache-overflows]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
[apache-nohome]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
[apache-botsearch]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
[apache-fakegooglebot]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_access_log)s
|
||||
maxretry = 1
|
||||
ignorecommand = %(ignorecommands_dir)s/apache-fakegooglebot <ip>
|
||||
|
||||
|
||||
[apache-modsecurity]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
[apache-shellshock]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 1
|
||||
|
||||
|
||||
[openhab-auth]
|
||||
|
||||
filter = openhab
|
||||
banaction = %(banaction_allports)s
|
||||
logpath = /opt/openhab/logs/request.log
|
||||
|
||||
|
||||
[nginx-http-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = %(nginx_error_log)s
|
||||
|
||||
[nginx-limit-req]
|
||||
port = http,https
|
||||
logpath = %(nginx_error_log)s
|
||||
|
||||
[nginx-botsearch]
|
||||
|
||||
port = http,https
|
||||
logpath = %(nginx_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
|
||||
[php-url-fopen]
|
||||
|
||||
port = http,https
|
||||
logpath = %(nginx_access_log)s
|
||||
%(apache_access_log)s
|
||||
|
||||
|
||||
[suhosin]
|
||||
|
||||
port = http,https
|
||||
logpath = %(suhosin_log)s
|
||||
|
||||
|
||||
[lighttpd-auth]
|
||||
port = http,https
|
||||
logpath = %(lighttpd_error_log)s
|
||||
|
||||
|
||||
|
||||
[roundcube-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = %(roundcube_errors_log)s
|
||||
|
||||
|
||||
[openwebmail]
|
||||
|
||||
port = http,https
|
||||
logpath = /var/log/openwebmail.log
|
||||
|
||||
|
||||
[horde]
|
||||
|
||||
port = http,https
|
||||
logpath = /var/log/horde/horde.log
|
||||
|
||||
|
||||
[groupoffice]
|
||||
|
||||
port = http,https
|
||||
logpath = /home/groupoffice/log/info.log
|
||||
|
||||
|
||||
[sogo-auth]
|
||||
port = http,https
|
||||
logpath = /var/log/sogo/sogo.log
|
||||
|
||||
|
||||
[tine20]
|
||||
|
||||
logpath = /var/log/tine20/tine20.log
|
||||
port = http,https
|
||||
|
||||
|
||||
|
||||
[drupal-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = %(syslog_daemon)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
[guacamole]
|
||||
|
||||
port = http,https
|
||||
logpath = /var/log/tomcat*/catalina.out
|
||||
|
||||
[monit]
|
||||
port = 2812
|
||||
logpath = /var/log/monit
|
||||
/var/log/monit.log
|
||||
|
||||
|
||||
[webmin-auth]
|
||||
|
||||
port = 10000
|
||||
logpath = %(syslog_authpriv)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[froxlor-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = %(syslog_authpriv)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
|
||||
[squid]
|
||||
|
||||
port = 80,443,3128,8080
|
||||
logpath = /var/log/squid/access.log
|
||||
|
||||
|
||||
[3proxy]
|
||||
|
||||
port = 3128
|
||||
logpath = /var/log/3proxy.log
|
||||
|
||||
|
||||
|
||||
|
||||
[proftpd]
|
||||
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(proftpd_log)s
|
||||
backend = %(proftpd_backend)s
|
||||
|
||||
|
||||
[pure-ftpd]
|
||||
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(pureftpd_log)s
|
||||
backend = %(pureftpd_backend)s
|
||||
|
||||
|
||||
[gssftpd]
|
||||
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(syslog_daemon)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[wuftpd]
|
||||
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(wuftpd_log)s
|
||||
backend = %(wuftpd_backend)s
|
||||
|
||||
|
||||
[vsftpd]
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(vsftpd_log)s
|
||||
|
||||
|
||||
|
||||
[assp]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = /root/path/to/assp/logs/maillog.txt
|
||||
|
||||
|
||||
[courier-smtp]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[postfix]
|
||||
mode = more
|
||||
port = smtp,465,submission
|
||||
logpath = %(postfix_log)s
|
||||
backend = %(postfix_backend)s
|
||||
|
||||
|
||||
[postfix-rbl]
|
||||
|
||||
filter = postfix[mode=rbl]
|
||||
port = smtp,465,submission
|
||||
logpath = %(postfix_log)s
|
||||
backend = %(postfix_backend)s
|
||||
maxretry = 1
|
||||
|
||||
|
||||
[sendmail-auth]
|
||||
|
||||
port = submission,465,smtp
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[sendmail-reject]
|
||||
port = smtp,465,submission
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[qmail-rbl]
|
||||
|
||||
filter = qmail
|
||||
port = smtp,465,submission
|
||||
logpath = /service/qmail/log/main/current
|
||||
|
||||
|
||||
[dovecot]
|
||||
|
||||
port = pop3,pop3s,imap,imaps,submission,465,sieve
|
||||
logpath = %(dovecot_log)s
|
||||
backend = %(dovecot_backend)s
|
||||
|
||||
|
||||
[sieve]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = %(dovecot_log)s
|
||||
backend = %(dovecot_backend)s
|
||||
|
||||
|
||||
[solid-pop3d]
|
||||
|
||||
port = pop3,pop3s
|
||||
logpath = %(solidpop3d_log)s
|
||||
|
||||
|
||||
[exim]
|
||||
port = smtp,465,submission
|
||||
logpath = %(exim_main_log)s
|
||||
|
||||
|
||||
[exim-spam]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = %(exim_main_log)s
|
||||
|
||||
|
||||
[kerio]
|
||||
|
||||
port = imap,smtp,imaps,465
|
||||
logpath = /opt/kerio/mailserver/store/logs/security.log
|
||||
|
||||
|
||||
|
||||
[courier-auth]
|
||||
port = smtp,465,submission,imap,imaps,pop3,pop3s
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[postfix-sasl]
|
||||
filter = postfix[mode=auth]
|
||||
port = smtp,465,submission,imap,imaps,pop3,pop3s
|
||||
logpath = %(postfix_log)s
|
||||
backend = %(postfix_backend)s
|
||||
|
||||
|
||||
[perdition]
|
||||
port = imap,imaps,pop3,pop3s
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[squirrelmail]
|
||||
port = smtp,465,submission,imap,imap2,imaps,pop3,pop3s,http,https,socks
|
||||
logpath = /var/lib/squirrelmail/prefs/squirrelmail_access_log
|
||||
|
||||
|
||||
[cyrus-imap]
|
||||
port = imap,imaps
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[uwimap-auth]
|
||||
port = imap,imaps
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[named-refused]
|
||||
port = domain,953
|
||||
logpath = /var/log/named/security.log
|
||||
|
||||
|
||||
[nsd]
|
||||
|
||||
port = 53
|
||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||
logpath = /var/log/nsd.log
|
||||
|
||||
|
||||
|
||||
[asterisk]
|
||||
port = 5060,5061
|
||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||
logpath = /var/log/asterisk/messages
|
||||
maxretry = 10
|
||||
|
||||
|
||||
[freeswitch]
|
||||
port = 5060,5061
|
||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||
logpath = /var/log/freeswitch.log
|
||||
maxretry = 10
|
||||
|
||||
|
||||
[znc-adminlog]
|
||||
port = 6667
|
||||
logpath = /var/lib/znc/moddata/adminlog/znc.log
|
||||
|
||||
|
||||
[mysqld-auth]
|
||||
|
||||
port = 3306
|
||||
logpath = %(mysql_log)s
|
||||
backend = %(mysql_backend)s
|
||||
|
||||
|
||||
[mongodb-auth]
|
||||
port = 27017
|
||||
logpath = /var/log/mongodb/mongodb.log
|
||||
|
||||
|
||||
[recidive]
|
||||
|
||||
logpath = /var/log/fail2ban.log
|
||||
banaction = %(banaction_allports)s
|
||||
bantime = 1w
|
||||
findtime = 1d
|
||||
|
||||
[pam-generic]
|
||||
banaction = %(banaction_allports)s
|
||||
logpath = %(syslog_authpriv)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[xinetd-fail]
|
||||
|
||||
banaction = iptables-multiport-log
|
||||
logpath = %(syslog_daemon)s
|
||||
backend = %(syslog_backend)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
[stunnel]
|
||||
|
||||
logpath = /var/log/stunnel4/stunnel.log
|
||||
|
||||
|
||||
[ejabberd-auth]
|
||||
|
||||
port = 5222
|
||||
logpath = /var/log/ejabberd/ejabberd.log
|
||||
|
||||
|
||||
[counter-strike]
|
||||
|
||||
logpath = /opt/cstrike/logs/L[0-9]*.log
|
||||
tcpport = 27030,27031,27032,27033,27034,27035,27036,27037,27038,27039
|
||||
udpport = 1200,27000,27001,27002,27003,27004,27005,27006,27007,27008,27009,27010,27011,27012,27013,27014,27015
|
||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, port="%(tcpport)s", protocol="tcp"]
|
||||
%(default/action_)s[name=%(__name__)s-udp, port="%(udpport)s", protocol="udp"]
|
||||
|
||||
[softethervpn]
|
||||
port = 500,4500
|
||||
protocol = udp
|
||||
logpath = /usr/local/vpnserver/security_log/*/sec.log
|
||||
|
||||
[gitlab]
|
||||
port = http,https
|
||||
logpath = /var/log/gitlab/gitlab-rails/application.log
|
||||
|
||||
[grafana]
|
||||
port = http,https
|
||||
logpath = /var/log/grafana/grafana.log
|
||||
|
||||
[bitwarden]
|
||||
port = http,https
|
||||
logpath = /home/*/bwdata/logs/identity/Identity/log.txt
|
||||
|
||||
[centreon]
|
||||
port = http,https
|
||||
logpath = /var/log/centreon/login.log
|
||||
|
||||
[nagios]
|
||||
|
||||
logpath = %(syslog_daemon)s ; nrpe.cfg may define a different log_facility
|
||||
backend = %(syslog_backend)s
|
||||
maxretry = 1
|
||||
|
||||
|
||||
[oracleims]
|
||||
logpath = /opt/sun/comms/messaging64/log/mail.log_current
|
||||
banaction = %(banaction_allports)s
|
||||
|
||||
[directadmin]
|
||||
logpath = /var/log/directadmin/login.log
|
||||
port = 2222
|
||||
|
||||
[portsentry]
|
||||
logpath = /var/lib/portsentry/portsentry.history
|
||||
maxretry = 1
|
||||
|
||||
[pass2allow-ftp]
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
knocking_url = /knocking/
|
||||
filter = apache-pass[knocking_url="%(knocking_url)s"]
|
||||
logpath = %(apache_access_log)s
|
||||
blocktype = RETURN
|
||||
returntype = DROP
|
||||
action = %(action_)s[blocktype=%(blocktype)s, returntype=%(returntype)s,
|
||||
actionstart_on_demand=false, actionrepair_on_unban=true]
|
||||
bantime = 1h
|
||||
maxretry = 1
|
||||
findtime = 1
|
||||
|
||||
|
||||
[murmur]
|
||||
port = 64738
|
||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||
logpath = /var/log/mumble-server/mumble-server.log
|
||||
|
||||
|
||||
[screensharingd]
|
||||
logpath = /var/log/system.log
|
||||
logencoding = utf-8
|
||||
|
||||
[haproxy-http-auth]
|
||||
logpath = /var/log/haproxy.log
|
||||
|
||||
[slapd]
|
||||
port = ldap,ldaps
|
||||
logpath = /var/log/slapd.log
|
||||
|
||||
[domino-smtp]
|
||||
port = smtp,ssmtp
|
||||
logpath = /home/domino01/data/IBM_TECHNICAL_SUPPORT/console.log
|
||||
|
||||
[phpmyadmin-syslog]
|
||||
port = http,https
|
||||
logpath = %(syslog_authpriv)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[zoneminder]
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
|
||||
[traefik-auth]
|
||||
port = http,https
|
||||
logpath = /var/log/traefik/access.log
|
||||
@@ -0,0 +1,25 @@
|
||||
[DEFAULT]
|
||||
allowipv6 = auto
|
||||
|
||||
action_ = %(banaction)s[port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
|
||||
action_mw = %(action_)s
|
||||
%(mta)s-whois[sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
|
||||
action_mwl = %(action_)s
|
||||
%(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
|
||||
|
||||
action_xarf = %(action_)s
|
||||
xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath="%(logpath)s", port="%(port)s"]
|
||||
|
||||
action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"]
|
||||
%(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
|
||||
|
||||
action_blocklist_de = blocklist_de[email="%(sender)s", service="%(__name__)s", apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"]
|
||||
|
||||
action_badips = badips.py[category="%(__name__)s", banaction="%(banaction)s", agent="%(fail2ban_agent)s"]
|
||||
action_badips_report = badips[category="%(__name__)s", agent="%(fail2ban_agent)s"]
|
||||
|
||||
action_abuseipdb = abuseipdb
|
||||
|
||||
action = %(action_)s
|
||||
@@ -0,0 +1,964 @@
|
||||
#
|
||||
# WARNING: heavily refactored in 0.9.0 release. Please review and
|
||||
# customize settings for your setup.
|
||||
#
|
||||
# Changes: in most of the cases you should not modify this
|
||||
# file, but provide customizations in jail.local file,
|
||||
# or separate .conf files under jail.d/ directory, e.g.:
|
||||
#
|
||||
# HOW TO ACTIVATE JAILS:
|
||||
#
|
||||
# YOU SHOULD NOT MODIFY THIS FILE.
|
||||
#
|
||||
# It will probably be overwritten or improved in a distribution update.
|
||||
#
|
||||
# Provide customizations in a jail.local file or a jail.d/customisation.local.
|
||||
# For example to change the default bantime for all jails and to enable the
|
||||
# ssh-iptables jail the following (uncommented) would appear in the .local file.
|
||||
# See man 5 jail.conf for details.
|
||||
#
|
||||
# [DEFAULT]
|
||||
# bantime = 1h
|
||||
#
|
||||
# [sshd]
|
||||
# enabled = true
|
||||
#
|
||||
# See jail.conf(5) man page for more information
|
||||
|
||||
|
||||
|
||||
# Comments: use '#' for comment lines and ';' (following a space) for inline comments
|
||||
|
||||
|
||||
[INCLUDES]
|
||||
|
||||
#before = paths-distro.conf
|
||||
before = paths-debian.conf
|
||||
|
||||
# The DEFAULT allows a global definition of the options. They can be overridden
|
||||
# in each jail afterwards.
|
||||
|
||||
[DEFAULT]
|
||||
|
||||
#
|
||||
# MISCELLANEOUS OPTIONS
|
||||
#
|
||||
|
||||
# "bantime.increment" allows to use database for searching of previously banned ip's to increase a
|
||||
# default ban time using special formula, default it is banTime * 1, 2, 4, 8, 16, 32...
|
||||
#bantime.increment = true
|
||||
|
||||
# "bantime.rndtime" is the max number of seconds using for mixing with random time
|
||||
# to prevent "clever" botnets calculate exact time IP can be unbanned again:
|
||||
#bantime.rndtime =
|
||||
|
||||
# "bantime.maxtime" is the max number of seconds using the ban time can reach (doesn't grow further)
|
||||
#bantime.maxtime =
|
||||
|
||||
# "bantime.factor" is a coefficient to calculate exponent growing of the formula or common multiplier,
|
||||
# default value of factor is 1 and with default value of formula, the ban time
|
||||
# grows by 1, 2, 4, 8, 16 ...
|
||||
#bantime.factor = 1
|
||||
|
||||
# "bantime.formula" used by default to calculate next value of ban time, default value below,
|
||||
# the same ban time growing will be reached by multipliers 1, 2, 4, 8, 16, 32...
|
||||
#bantime.formula = ban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * banFactor
|
||||
#
|
||||
# more aggressive example of formula has the same values only for factor "2.0 / 2.885385" :
|
||||
#bantime.formula = ban.Time * math.exp(float(ban.Count+1)*banFactor)/math.exp(1*banFactor)
|
||||
|
||||
# "bantime.multipliers" used to calculate next value of ban time instead of formula, coresponding
|
||||
# previously ban count and given "bantime.factor" (for multipliers default is 1);
|
||||
# following example grows ban time by 1, 2, 4, 8, 16 ... and if last ban count greater as multipliers count,
|
||||
# always used last multiplier (64 in example), for factor '1' and original ban time 600 - 10.6 hours
|
||||
#bantime.multipliers = 1 2 4 8 16 32 64
|
||||
# following example can be used for small initial ban time (bantime=60) - it grows more aggressive at begin,
|
||||
# for bantime=60 the multipliers are minutes and equal: 1 min, 5 min, 30 min, 1 hour, 5 hour, 12 hour, 1 day, 2 day
|
||||
#bantime.multipliers = 1 5 30 60 300 720 1440 2880
|
||||
|
||||
# "bantime.overalljails" (if true) specifies the search of IP in the database will be executed
|
||||
# cross over all jails, if false (dafault), only current jail of the ban IP will be searched
|
||||
#bantime.overalljails = false
|
||||
|
||||
# --------------------
|
||||
|
||||
# "ignoreself" specifies whether the local resp. own IP addresses should be ignored
|
||||
# (default is true). Fail2ban will not ban a host which matches such addresses.
|
||||
#ignoreself = true
|
||||
|
||||
# "ignoreip" can be a list of IP addresses, CIDR masks or DNS hosts. Fail2ban
|
||||
# will not ban a host which matches an address in this list. Several addresses
|
||||
# can be defined using space (and/or comma) separator.
|
||||
#ignoreip = 127.0.0.1/8 ::1
|
||||
|
||||
# External command that will take an tagged arguments to ignore, e.g. <ip>,
|
||||
# and return true if the IP is to be ignored. False otherwise.
|
||||
#
|
||||
# ignorecommand = /path/to/command <ip>
|
||||
ignorecommand =
|
||||
|
||||
# "bantime" is the number of seconds that a host is banned.
|
||||
bantime = 10m
|
||||
|
||||
# A host is banned if it has generated "maxretry" during the last "findtime"
|
||||
# seconds.
|
||||
findtime = 10m
|
||||
|
||||
# "maxretry" is the number of failures before a host get banned.
|
||||
maxretry = 5
|
||||
|
||||
# "maxmatches" is the number of matches stored in ticket (resolvable via tag <matches> in actions).
|
||||
maxmatches = %(maxretry)s
|
||||
|
||||
# "backend" specifies the backend used to get files modification.
|
||||
# Available options are "pyinotify", "gamin", "polling", "systemd" and "auto".
|
||||
# This option can be overridden in each jail as well.
|
||||
#
|
||||
# pyinotify: requires pyinotify (a file alteration monitor) to be installed.
|
||||
# If pyinotify is not installed, Fail2ban will use auto.
|
||||
# gamin: requires Gamin (a file alteration monitor) to be installed.
|
||||
# If Gamin is not installed, Fail2ban will use auto.
|
||||
# polling: uses a polling algorithm which does not require external libraries.
|
||||
# systemd: uses systemd python library to access the systemd journal.
|
||||
# Specifying "logpath" is not valid for this backend.
|
||||
# See "journalmatch" in the jails associated filter config
|
||||
# auto: will try to use the following backends, in order:
|
||||
# pyinotify, gamin, polling.
|
||||
#
|
||||
# Note: if systemd backend is chosen as the default but you enable a jail
|
||||
# for which logs are present only in its own log files, specify some other
|
||||
# backend for that jail (e.g. polling) and provide empty value for
|
||||
# journalmatch. See https://github.com/fail2ban/fail2ban/issues/959#issuecomment-74901200
|
||||
backend = systemd
|
||||
|
||||
# "usedns" specifies if jails should trust hostnames in logs,
|
||||
# warn when DNS lookups are performed, or ignore all hostnames in logs
|
||||
#
|
||||
# yes: if a hostname is encountered, a DNS lookup will be performed.
|
||||
# warn: if a hostname is encountered, a DNS lookup will be performed,
|
||||
# but it will be logged as a warning.
|
||||
# no: if a hostname is encountered, will not be used for banning,
|
||||
# but it will be logged as info.
|
||||
# raw: use raw value (no hostname), allow use it for no-host filters/actions (example user)
|
||||
usedns = warn
|
||||
|
||||
# "logencoding" specifies the encoding of the log files handled by the jail
|
||||
# This is used to decode the lines from the log file.
|
||||
# Typical examples: "ascii", "utf-8"
|
||||
#
|
||||
# auto: will use the system locale setting
|
||||
logencoding = auto
|
||||
|
||||
# "enabled" enables the jails.
|
||||
# By default all jails are disabled, and it should stay this way.
|
||||
# Enable only relevant to your setup jails in your .local or jail.d/*.conf
|
||||
#
|
||||
# true: jail will be enabled and log files will get monitored for changes
|
||||
# false: jail is not enabled
|
||||
enabled = false
|
||||
|
||||
|
||||
# "mode" defines the mode of the filter (see corresponding filter implementation for more info).
|
||||
mode = normal
|
||||
|
||||
# "filter" defines the filter to use by the jail.
|
||||
# By default jails have names matching their filter name
|
||||
#
|
||||
filter = %(__name__)s[mode=%(mode)s]
|
||||
|
||||
|
||||
#
|
||||
# ACTIONS
|
||||
#
|
||||
|
||||
# Some options used for actions
|
||||
|
||||
# Destination email address used solely for the interpolations in
|
||||
# jail.{conf,local,d/*} configuration files.
|
||||
destemail = root@localhost
|
||||
|
||||
# Sender email address used solely for some actions
|
||||
sender = root@<fq-hostname>
|
||||
|
||||
# E-mail action. Since 0.8.1 Fail2Ban uses sendmail MTA for the
|
||||
# mailing. Change mta configuration parameter to mail if you want to
|
||||
# revert to conventional 'mail'.
|
||||
mta = sendmail
|
||||
|
||||
# Default protocol
|
||||
protocol = tcp
|
||||
|
||||
# Specify chain where jumps would need to be added in ban-actions expecting parameter chain
|
||||
chain = <known/chain>
|
||||
|
||||
# Ports to be banned
|
||||
# Usually should be overridden in a particular jail
|
||||
port = 0:65535
|
||||
|
||||
# Format of user-agent https://tools.ietf.org/html/rfc7231#section-5.5.3
|
||||
fail2ban_agent = Fail2Ban/%(fail2ban_version)s
|
||||
|
||||
#
|
||||
# Action shortcuts. To be used to define action parameter
|
||||
|
||||
# Default banning action (e.g. iptables, iptables-new,
|
||||
# iptables-multiport, shorewall, etc) It is used to define
|
||||
# action_* variables. Can be overridden globally or per
|
||||
# section within jail.local file
|
||||
banaction = iptables-multiport
|
||||
banaction_allports = iptables-allports
|
||||
|
||||
# The simplest action to take: ban only
|
||||
action_ = %(banaction)s[port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
|
||||
# ban & send an e-mail with whois report to the destemail.
|
||||
action_mw = %(action_)s
|
||||
%(mta)s-whois[sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
|
||||
# ban & send an e-mail with whois report and relevant log lines
|
||||
# to the destemail.
|
||||
action_mwl = %(action_)s
|
||||
%(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
|
||||
|
||||
# See the IMPORTANT note in action.d/xarf-login-attack for when to use this action
|
||||
#
|
||||
# ban & send a xarf e-mail to abuse contact of IP address and include relevant log lines
|
||||
# to the destemail.
|
||||
action_xarf = %(action_)s
|
||||
xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath="%(logpath)s", port="%(port)s"]
|
||||
|
||||
# ban IP on CloudFlare & send an e-mail with whois report and relevant log lines
|
||||
# to the destemail.
|
||||
action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"]
|
||||
%(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
|
||||
|
||||
# Report block via blocklist.de fail2ban reporting service API
|
||||
#
|
||||
# See the IMPORTANT note in action.d/blocklist_de.conf for when to use this action.
|
||||
# Specify expected parameters in file action.d/blocklist_de.local or if the interpolation
|
||||
# `action_blocklist_de` used for the action, set value of `blocklist_de_apikey`
|
||||
# in your `jail.local` globally (section [DEFAULT]) or per specific jail section (resp. in
|
||||
# corresponding jail.d/my-jail.local file).
|
||||
#
|
||||
action_blocklist_de = blocklist_de[email="%(sender)s", service="%(__name__)s", apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"]
|
||||
|
||||
# Report ban via badips.com, and use as blacklist
|
||||
#
|
||||
# See BadIPsAction docstring in config/action.d/badips.py for
|
||||
# documentation for this action.
|
||||
#
|
||||
# NOTE: This action relies on banaction being present on start and therefore
|
||||
# should be last action defined for a jail.
|
||||
#
|
||||
action_badips = badips.py[category="%(__name__)s", banaction="%(banaction)s", agent="%(fail2ban_agent)s"]
|
||||
#
|
||||
# Report ban via badips.com (uses action.d/badips.conf for reporting only)
|
||||
#
|
||||
action_badips_report = badips[category="%(__name__)s", agent="%(fail2ban_agent)s"]
|
||||
|
||||
# Report ban via abuseipdb.com.
|
||||
#
|
||||
# See action.d/abuseipdb.conf for usage example and details.
|
||||
#
|
||||
action_abuseipdb = abuseipdb
|
||||
|
||||
# Choose default action. To change, just override value of 'action' with the
|
||||
# interpolation to the chosen action shortcut (e.g. action_mw, action_mwl, etc) in jail.local
|
||||
# globally (section [DEFAULT]) or per specific section
|
||||
action = %(action_)s
|
||||
|
||||
|
||||
#
|
||||
# JAILS
|
||||
#
|
||||
|
||||
#
|
||||
# SSH servers
|
||||
#
|
||||
|
||||
[sshd]
|
||||
|
||||
# To use more aggressive sshd modes set filter parameter "mode" in jail.local:
|
||||
# normal (default), ddos, extra or aggressive (combines all).
|
||||
# See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details.
|
||||
#mode = normal
|
||||
port = ssh
|
||||
logpath = %(sshd_log)s
|
||||
backend = %(sshd_backend)s
|
||||
|
||||
|
||||
[dropbear]
|
||||
|
||||
port = ssh
|
||||
logpath = %(dropbear_log)s
|
||||
backend = %(dropbear_backend)s
|
||||
|
||||
|
||||
[selinux-ssh]
|
||||
|
||||
port = ssh
|
||||
logpath = %(auditd_log)s
|
||||
|
||||
|
||||
#
|
||||
# HTTP servers
|
||||
#
|
||||
|
||||
[apache-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
|
||||
|
||||
[apache-badbots]
|
||||
# Ban hosts which agent identifies spammer robots crawling the web
|
||||
# for email addresses. The mail outputs are buffered.
|
||||
port = http,https
|
||||
logpath = %(apache_access_log)s
|
||||
bantime = 48h
|
||||
maxretry = 1
|
||||
|
||||
|
||||
[apache-noscript]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
|
||||
|
||||
[apache-overflows]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
[apache-nohome]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
[apache-botsearch]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
[apache-fakegooglebot]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_access_log)s
|
||||
maxretry = 1
|
||||
ignorecommand = %(ignorecommands_dir)s/apache-fakegooglebot <ip>
|
||||
|
||||
|
||||
[apache-modsecurity]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
[apache-shellshock]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 1
|
||||
|
||||
|
||||
[openhab-auth]
|
||||
|
||||
filter = openhab
|
||||
banaction = %(banaction_allports)s
|
||||
logpath = /opt/openhab/logs/request.log
|
||||
|
||||
|
||||
[nginx-http-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = %(nginx_error_log)s
|
||||
|
||||
# To use 'nginx-limit-req' jail you should have `ngx_http_limit_req_module`
|
||||
# and define `limit_req` and `limit_req_zone` as described in nginx documentation
|
||||
# http://nginx.org/en/docs/http/ngx_http_limit_req_module.html
|
||||
# or for example see in 'config/filter.d/nginx-limit-req.conf'
|
||||
[nginx-limit-req]
|
||||
port = http,https
|
||||
logpath = %(nginx_error_log)s
|
||||
|
||||
[nginx-botsearch]
|
||||
|
||||
port = http,https
|
||||
logpath = %(nginx_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
# Ban attackers that try to use PHP's URL-fopen() functionality
|
||||
# through GET/POST variables. - Experimental, with more than a year
|
||||
# of usage in production environments.
|
||||
|
||||
[php-url-fopen]
|
||||
|
||||
port = http,https
|
||||
logpath = %(nginx_access_log)s
|
||||
%(apache_access_log)s
|
||||
|
||||
|
||||
[suhosin]
|
||||
|
||||
port = http,https
|
||||
logpath = %(suhosin_log)s
|
||||
|
||||
|
||||
[lighttpd-auth]
|
||||
# Same as above for Apache's mod_auth
|
||||
# It catches wrong authentifications
|
||||
port = http,https
|
||||
logpath = %(lighttpd_error_log)s
|
||||
|
||||
|
||||
#
|
||||
# Webmail and groupware servers
|
||||
#
|
||||
|
||||
[roundcube-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = %(roundcube_errors_log)s
|
||||
# Use following line in your jail.local if roundcube logs to journal.
|
||||
#backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[openwebmail]
|
||||
|
||||
port = http,https
|
||||
logpath = /var/log/openwebmail.log
|
||||
|
||||
|
||||
[horde]
|
||||
|
||||
port = http,https
|
||||
logpath = /var/log/horde/horde.log
|
||||
|
||||
|
||||
[groupoffice]
|
||||
|
||||
port = http,https
|
||||
logpath = /home/groupoffice/log/info.log
|
||||
|
||||
|
||||
[sogo-auth]
|
||||
# Monitor SOGo groupware server
|
||||
# without proxy this would be:
|
||||
# port = 20000
|
||||
port = http,https
|
||||
logpath = /var/log/sogo/sogo.log
|
||||
|
||||
|
||||
[tine20]
|
||||
|
||||
logpath = /var/log/tine20/tine20.log
|
||||
port = http,https
|
||||
|
||||
|
||||
#
|
||||
# Web Applications
|
||||
#
|
||||
#
|
||||
|
||||
[drupal-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = %(syslog_daemon)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
[guacamole]
|
||||
|
||||
port = http,https
|
||||
logpath = /var/log/tomcat*/catalina.out
|
||||
#logpath = /var/log/guacamole.log
|
||||
|
||||
[monit]
|
||||
#Ban clients brute-forcing the monit gui login
|
||||
port = 2812
|
||||
logpath = /var/log/monit
|
||||
/var/log/monit.log
|
||||
|
||||
|
||||
[webmin-auth]
|
||||
|
||||
port = 10000
|
||||
logpath = %(syslog_authpriv)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[froxlor-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = %(syslog_authpriv)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
#
|
||||
# HTTP Proxy servers
|
||||
#
|
||||
#
|
||||
|
||||
[squid]
|
||||
|
||||
port = 80,443,3128,8080
|
||||
logpath = /var/log/squid/access.log
|
||||
|
||||
|
||||
[3proxy]
|
||||
|
||||
port = 3128
|
||||
logpath = /var/log/3proxy.log
|
||||
|
||||
|
||||
#
|
||||
# FTP servers
|
||||
#
|
||||
|
||||
|
||||
[proftpd]
|
||||
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(proftpd_log)s
|
||||
backend = %(proftpd_backend)s
|
||||
|
||||
|
||||
[pure-ftpd]
|
||||
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(pureftpd_log)s
|
||||
backend = %(pureftpd_backend)s
|
||||
|
||||
|
||||
[gssftpd]
|
||||
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(syslog_daemon)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[wuftpd]
|
||||
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(wuftpd_log)s
|
||||
backend = %(wuftpd_backend)s
|
||||
|
||||
|
||||
[vsftpd]
|
||||
# or overwrite it in jails.local to be
|
||||
# logpath = %(syslog_authpriv)s
|
||||
# if you want to rely on PAM failed login attempts
|
||||
# vsftpd's failregex should match both of those formats
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(vsftpd_log)s
|
||||
|
||||
|
||||
#
|
||||
# Mail servers
|
||||
#
|
||||
|
||||
# ASSP SMTP Proxy Jail
|
||||
[assp]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = /root/path/to/assp/logs/maillog.txt
|
||||
|
||||
|
||||
[courier-smtp]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[postfix]
|
||||
# To use another modes set filter parameter "mode" in jail.local:
|
||||
mode = more
|
||||
port = smtp,465,submission
|
||||
logpath = %(postfix_log)s
|
||||
backend = %(postfix_backend)s
|
||||
|
||||
|
||||
[postfix-rbl]
|
||||
|
||||
filter = postfix[mode=rbl]
|
||||
port = smtp,465,submission
|
||||
logpath = %(postfix_log)s
|
||||
backend = %(postfix_backend)s
|
||||
maxretry = 1
|
||||
|
||||
|
||||
[sendmail-auth]
|
||||
|
||||
port = submission,465,smtp
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[sendmail-reject]
|
||||
# To use more aggressive modes set filter parameter "mode" in jail.local:
|
||||
# normal (default), extra or aggressive
|
||||
# See "tests/files/logs/sendmail-reject" or "filter.d/sendmail-reject.conf" for usage example and details.
|
||||
#mode = normal
|
||||
port = smtp,465,submission
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[qmail-rbl]
|
||||
|
||||
filter = qmail
|
||||
port = smtp,465,submission
|
||||
logpath = /service/qmail/log/main/current
|
||||
|
||||
|
||||
# dovecot defaults to logging to the mail syslog facility
|
||||
# but can be set by syslog_facility in the dovecot configuration.
|
||||
[dovecot]
|
||||
|
||||
port = pop3,pop3s,imap,imaps,submission,465,sieve
|
||||
logpath = %(dovecot_log)s
|
||||
backend = %(dovecot_backend)s
|
||||
|
||||
|
||||
[sieve]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = %(dovecot_log)s
|
||||
backend = %(dovecot_backend)s
|
||||
|
||||
|
||||
[solid-pop3d]
|
||||
|
||||
port = pop3,pop3s
|
||||
logpath = %(solidpop3d_log)s
|
||||
|
||||
|
||||
[exim]
|
||||
# see filter.d/exim.conf for further modes supported from filter:
|
||||
#mode = normal
|
||||
port = smtp,465,submission
|
||||
logpath = %(exim_main_log)s
|
||||
|
||||
|
||||
[exim-spam]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = %(exim_main_log)s
|
||||
|
||||
|
||||
[kerio]
|
||||
|
||||
port = imap,smtp,imaps,465
|
||||
logpath = /opt/kerio/mailserver/store/logs/security.log
|
||||
|
||||
|
||||
#
|
||||
# Mail servers authenticators: might be used for smtp,ftp,imap servers, so
|
||||
# all relevant ports get banned
|
||||
#
|
||||
|
||||
[courier-auth]
|
||||
|
||||
port = smtp,465,submission,imap,imaps,pop3,pop3s
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[postfix-sasl]
|
||||
|
||||
filter = postfix[mode=auth]
|
||||
port = smtp,465,submission,imap,imaps,pop3,pop3s
|
||||
# You might consider monitoring /var/log/mail.warn instead if you are
|
||||
# running postfix since it would provide the same log lines at the
|
||||
# "warn" level but overall at the smaller filesize.
|
||||
logpath = %(postfix_log)s
|
||||
backend = %(postfix_backend)s
|
||||
|
||||
|
||||
[perdition]
|
||||
|
||||
port = imap,imaps,pop3,pop3s
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[squirrelmail]
|
||||
|
||||
port = smtp,465,submission,imap,imap2,imaps,pop3,pop3s,http,https,socks
|
||||
logpath = /var/lib/squirrelmail/prefs/squirrelmail_access_log
|
||||
|
||||
|
||||
[cyrus-imap]
|
||||
|
||||
port = imap,imaps
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[uwimap-auth]
|
||||
|
||||
port = imap,imaps
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
# DNS servers
|
||||
#
|
||||
|
||||
|
||||
# !!! WARNING !!!
|
||||
# Since UDP is connection-less protocol, spoofing of IP and imitation
|
||||
# of illegal actions is way too simple. Thus enabling of this filter
|
||||
# might provide an easy way for implementing a DoS against a chosen
|
||||
# victim. See
|
||||
# http://nion.modprobe.de/blog/archives/690-fail2ban-+-dns-fail.html
|
||||
# Please DO NOT USE this jail unless you know what you are doing.
|
||||
#
|
||||
# IMPORTANT: see filter.d/named-refused for instructions to enable logging
|
||||
# This jail blocks UDP traffic for DNS requests.
|
||||
# [named-refused-udp]
|
||||
#
|
||||
# filter = named-refused
|
||||
# port = domain,953
|
||||
# protocol = udp
|
||||
# logpath = /var/log/named/security.log
|
||||
|
||||
# IMPORTANT: see filter.d/named-refused for instructions to enable logging
|
||||
# This jail blocks TCP traffic for DNS requests.
|
||||
|
||||
[named-refused]
|
||||
|
||||
port = domain,953
|
||||
logpath = /var/log/named/security.log
|
||||
|
||||
|
||||
[nsd]
|
||||
|
||||
port = 53
|
||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||
logpath = /var/log/nsd.log
|
||||
|
||||
|
||||
#
|
||||
# Miscellaneous
|
||||
#
|
||||
|
||||
[asterisk]
|
||||
|
||||
port = 5060,5061
|
||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||
logpath = /var/log/asterisk/messages
|
||||
maxretry = 10
|
||||
|
||||
|
||||
[freeswitch]
|
||||
|
||||
port = 5060,5061
|
||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||
logpath = /var/log/freeswitch.log
|
||||
maxretry = 10
|
||||
|
||||
|
||||
# enable adminlog; it will log to a file inside znc's directory by default.
|
||||
[znc-adminlog]
|
||||
|
||||
port = 6667
|
||||
logpath = /var/lib/znc/moddata/adminlog/znc.log
|
||||
|
||||
|
||||
# To log wrong MySQL access attempts add to /etc/my.cnf in [mysqld] or
|
||||
# equivalent section:
|
||||
# log-warnings = 2
|
||||
#
|
||||
# for syslog (daemon facility)
|
||||
# [mysqld_safe]
|
||||
# syslog
|
||||
#
|
||||
# for own logfile
|
||||
# [mysqld]
|
||||
# log-error=/var/log/mysqld.log
|
||||
[mysqld-auth]
|
||||
|
||||
port = 3306
|
||||
logpath = %(mysql_log)s
|
||||
backend = %(mysql_backend)s
|
||||
|
||||
|
||||
# Log wrong MongoDB auth (for details see filter 'filter.d/mongodb-auth.conf')
|
||||
[mongodb-auth]
|
||||
# change port when running with "--shardsvr" or "--configsvr" runtime operation
|
||||
port = 27017
|
||||
logpath = /var/log/mongodb/mongodb.log
|
||||
|
||||
|
||||
# Jail for more extended banning of persistent abusers
|
||||
# !!! WARNINGS !!!
|
||||
# 1. Make sure that your loglevel specified in fail2ban.conf/.local
|
||||
# is not at DEBUG level -- which might then cause fail2ban to fall into
|
||||
# an infinite loop constantly feeding itself with non-informative lines
|
||||
# 2. Increase dbpurgeage defined in fail2ban.conf to e.g. 648000 (7.5 days)
|
||||
# to maintain entries for failed logins for sufficient amount of time
|
||||
[recidive]
|
||||
|
||||
logpath = /var/log/fail2ban.log
|
||||
banaction = %(banaction_allports)s
|
||||
bantime = 1w
|
||||
findtime = 1d
|
||||
|
||||
|
||||
# Generic filter for PAM. Has to be used with action which bans all
|
||||
# ports such as iptables-allports, shorewall
|
||||
|
||||
[pam-generic]
|
||||
# pam-generic filter can be customized to monitor specific subset of 'tty's
|
||||
banaction = %(banaction_allports)s
|
||||
logpath = %(syslog_authpriv)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[xinetd-fail]
|
||||
|
||||
banaction = iptables-multiport-log
|
||||
logpath = %(syslog_daemon)s
|
||||
backend = %(syslog_backend)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
# stunnel - need to set port for this
|
||||
[stunnel]
|
||||
|
||||
logpath = /var/log/stunnel4/stunnel.log
|
||||
|
||||
|
||||
[ejabberd-auth]
|
||||
|
||||
port = 5222
|
||||
logpath = /var/log/ejabberd/ejabberd.log
|
||||
|
||||
|
||||
[counter-strike]
|
||||
|
||||
logpath = /opt/cstrike/logs/L[0-9]*.log
|
||||
tcpport = 27030,27031,27032,27033,27034,27035,27036,27037,27038,27039
|
||||
udpport = 1200,27000,27001,27002,27003,27004,27005,27006,27007,27008,27009,27010,27011,27012,27013,27014,27015
|
||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, port="%(tcpport)s", protocol="tcp"]
|
||||
%(default/action_)s[name=%(__name__)s-udp, port="%(udpport)s", protocol="udp"]
|
||||
|
||||
[softethervpn]
|
||||
port = 500,4500
|
||||
protocol = udp
|
||||
logpath = /usr/local/vpnserver/security_log/*/sec.log
|
||||
|
||||
[gitlab]
|
||||
port = http,https
|
||||
logpath = /var/log/gitlab/gitlab-rails/application.log
|
||||
|
||||
[grafana]
|
||||
port = http,https
|
||||
logpath = /var/log/grafana/grafana.log
|
||||
|
||||
[bitwarden]
|
||||
port = http,https
|
||||
logpath = /home/*/bwdata/logs/identity/Identity/log.txt
|
||||
|
||||
[centreon]
|
||||
port = http,https
|
||||
logpath = /var/log/centreon/login.log
|
||||
|
||||
# consider low maxretry and a long bantime
|
||||
# nobody except your own Nagios server should ever probe nrpe
|
||||
[nagios]
|
||||
|
||||
logpath = %(syslog_daemon)s ; nrpe.cfg may define a different log_facility
|
||||
backend = %(syslog_backend)s
|
||||
maxretry = 1
|
||||
|
||||
|
||||
[oracleims]
|
||||
# see "oracleims" filter file for configuration requirement for Oracle IMS v6 and above
|
||||
logpath = /opt/sun/comms/messaging64/log/mail.log_current
|
||||
banaction = %(banaction_allports)s
|
||||
|
||||
[directadmin]
|
||||
logpath = /var/log/directadmin/login.log
|
||||
port = 2222
|
||||
|
||||
[portsentry]
|
||||
logpath = /var/lib/portsentry/portsentry.history
|
||||
maxretry = 1
|
||||
|
||||
[pass2allow-ftp]
|
||||
# this pass2allow example allows FTP traffic after successful HTTP authentication
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
# knocking_url variable must be overridden to some secret value in jail.local
|
||||
knocking_url = /knocking/
|
||||
filter = apache-pass[knocking_url="%(knocking_url)s"]
|
||||
# access log of the website with HTTP auth
|
||||
logpath = %(apache_access_log)s
|
||||
blocktype = RETURN
|
||||
returntype = DROP
|
||||
action = %(action_)s[blocktype=%(blocktype)s, returntype=%(returntype)s,
|
||||
actionstart_on_demand=false, actionrepair_on_unban=true]
|
||||
bantime = 1h
|
||||
maxretry = 1
|
||||
findtime = 1
|
||||
|
||||
|
||||
[murmur]
|
||||
# AKA mumble-server
|
||||
port = 64738
|
||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||
logpath = /var/log/mumble-server/mumble-server.log
|
||||
|
||||
|
||||
[screensharingd]
|
||||
# For Mac OS Screen Sharing Service (VNC)
|
||||
logpath = /var/log/system.log
|
||||
logencoding = utf-8
|
||||
|
||||
[haproxy-http-auth]
|
||||
# HAProxy by default doesn't log to file you'll need to set it up to forward
|
||||
# logs to a syslog server which would then write them to disk.
|
||||
# See "haproxy-http-auth" filter for a brief cautionary note when setting
|
||||
# maxretry and findtime.
|
||||
logpath = /var/log/haproxy.log
|
||||
|
||||
[slapd]
|
||||
port = ldap,ldaps
|
||||
logpath = /var/log/slapd.log
|
||||
|
||||
[domino-smtp]
|
||||
port = smtp,ssmtp
|
||||
logpath = /home/domino01/data/IBM_TECHNICAL_SUPPORT/console.log
|
||||
|
||||
[phpmyadmin-syslog]
|
||||
port = http,https
|
||||
logpath = %(syslog_authpriv)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[zoneminder]
|
||||
# Zoneminder HTTP/HTTPS web interface auth
|
||||
# Logs auth failures to apache2 error log
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
|
||||
[traefik-auth]
|
||||
# to use 'traefik-auth' filter you have to configure your Traefik instance,
|
||||
# see `filter.d/traefik-auth.conf` for details and service example.
|
||||
port = http,https
|
||||
logpath = /var/log/traefik/access.log
|
||||
@@ -0,0 +1,2 @@
|
||||
[DEFAULT]
|
||||
backend = systemd
|
||||
@@ -0,0 +1,11 @@
|
||||
#sshd-START
|
||||
[sshd]
|
||||
enabled = true
|
||||
filter = sshd
|
||||
port = 2022,no
|
||||
maxretry = 5
|
||||
findtime = 300
|
||||
bantime = 86400
|
||||
action = %(action_mwl)s
|
||||
logpath = /var/log/auth.log
|
||||
#sshd-END
|
||||
@@ -16,6 +16,10 @@ fi
|
||||
git config --global credential.helper store
|
||||
git config --global pull.rebase false
|
||||
|
||||
if [ ! -d $GIT_PROJECT_DIR ];then
|
||||
git config --global --add safe.directory $GIT_PROJECT_DIR
|
||||
fi
|
||||
|
||||
# echo $GIT_PROJECT_DIR
|
||||
if [ ! -d $GIT_PROJECT_DIR ];then
|
||||
mkdir -p $GIT_USER_DIR && cd $GIT_USER_DIR
|
||||
@@ -24,6 +28,8 @@ fi
|
||||
|
||||
unset GIT_DIR
|
||||
|
||||
|
||||
|
||||
cd $GIT_PROJECT_DIR && git pull
|
||||
|
||||
# func 2
|
||||
|
||||
+13
-6
@@ -5,7 +5,7 @@ import time
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
|
||||
import subprocess
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
@@ -138,6 +138,8 @@ def initDreplace():
|
||||
git_dir = mw.getServerDir() + '/git'
|
||||
if not os.path.exists(git_dir):
|
||||
mw.execShell('mkdir -p ' + git_dir)
|
||||
mw.execShell('chown -R www:www ' + git_dir)
|
||||
|
||||
|
||||
initD_path = getServerDir() + '/init.d'
|
||||
if not os.path.exists(initD_path):
|
||||
@@ -218,7 +220,7 @@ def getDbConfValue():
|
||||
rep_scope = r"\[database\](.*?)\["
|
||||
tmp = re.findall(rep_scope, content, re.S)
|
||||
|
||||
rep = '(\w*)\s*=\s*(.*)'
|
||||
rep = '(\\w*)\\s*=\\s*(.*)'
|
||||
tmp = re.findall(rep, tmp[0])
|
||||
r = {}
|
||||
for x in range(len(tmp)):
|
||||
@@ -416,7 +418,7 @@ def getGogsConf():
|
||||
result = []
|
||||
|
||||
for g in gets:
|
||||
rep = g['name'] + '\s*=\s*(.*)'
|
||||
rep = g['name'] + '\\s*=\\s*(.*)'
|
||||
tmp = re.search(rep, conf)
|
||||
if not tmp:
|
||||
continue
|
||||
@@ -445,7 +447,7 @@ def submitGogsConf():
|
||||
conf = mw.readFile(filename)
|
||||
for g in gets:
|
||||
if g in args:
|
||||
rep = g + '\s*=\s*(.*)'
|
||||
rep = g + '\\s*=\\s*(.*)'
|
||||
val = g + ' = ' + args[g]
|
||||
conf = re.sub(rep, val, conf)
|
||||
mw.writeFile(filename, conf)
|
||||
@@ -762,8 +764,13 @@ def projectScriptRun():
|
||||
if not os.path.exists(commit_sh):
|
||||
return mw.returnJson(False, '脚本文件不存在!')
|
||||
|
||||
mw.execShell(script_run)
|
||||
mw.execShell('chown -R www:www ' + commit_log)
|
||||
repo_dir = mw.getServerDir()+'/git/'+ args['name']
|
||||
|
||||
# mw.execShell(script_run)
|
||||
subprocess.Popen(script_run, stdout=subprocess.PIPE, shell=True,
|
||||
bufsize=4096, stderr=subprocess.PIPE)
|
||||
subprocess.Popen('chown -R www:www ' + repo_dir, stdout=subprocess.PIPE, shell=True,
|
||||
bufsize=4096, stderr=subprocess.PIPE)
|
||||
return mw.returnJson(True, '脚本文件执行成功,观察日志!')
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"ps": "Gitea是一个开源社区驱动的轻量级代码托管解决方案。",
|
||||
"name": "gitea",
|
||||
"title": "Gitea",
|
||||
"versions": ["1.17.2","1.18.5"],
|
||||
"versions": ["1.17.2","1.18.5","1.22.1"],
|
||||
"tip": "soft",
|
||||
"install_pre_inspection":false,
|
||||
"uninstall_pre_inspection":true,
|
||||
|
||||
@@ -62,7 +62,7 @@ Install_App()
|
||||
fi
|
||||
fi
|
||||
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
echo '正在安装脚本文件...'
|
||||
version=$1
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ Install_App()
|
||||
cd ${rootPath} && python3 plugins/gitea/index.py initd_install
|
||||
fi
|
||||
|
||||
echo 'install success' > $install_tmp
|
||||
echo 'install success'
|
||||
}
|
||||
|
||||
Uninstall_App()
|
||||
|
||||
@@ -173,12 +173,12 @@ def initDreplace():
|
||||
|
||||
def getRootUrl():
|
||||
content = mw.readFile(getConf())
|
||||
rep = r'ROOT_URL\s*=\s*(.*)'
|
||||
rep = r'ROOT_URL\\s*=\\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
if tmp:
|
||||
return tmp.groups()[0]
|
||||
|
||||
rep = r'EXTERNAL_URL\s*=\s*(.*)'
|
||||
rep = r'EXTERNAL_URL\\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
if tmp:
|
||||
return tmp.groups()[0]
|
||||
@@ -187,7 +187,7 @@ def getRootUrl():
|
||||
|
||||
def getSshPort():
|
||||
content = mw.readFile(getConf())
|
||||
rep = r'SSH_PORT\s*=\s*(.*)'
|
||||
rep = r'SSH_PORT\\s*=\\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
if not tmp:
|
||||
return ''
|
||||
@@ -196,7 +196,7 @@ def getSshPort():
|
||||
|
||||
def getHttpPort():
|
||||
content = mw.readFile(getConf())
|
||||
rep = r'HTTP_PORT\s*=\s*(.*)'
|
||||
rep = r'HTTP_PORT\\s*=\\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
if not tmp:
|
||||
return ''
|
||||
@@ -205,7 +205,7 @@ def getHttpPort():
|
||||
|
||||
def getRootPath():
|
||||
content = mw.readFile(getConf())
|
||||
rep = r'ROOT\s*=\s*(.*)'
|
||||
rep = r'ROOT\\s*=\\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
if not tmp:
|
||||
return ''
|
||||
@@ -218,10 +218,10 @@ def getDbConfValue():
|
||||
return {}
|
||||
|
||||
content = mw.readFile(conf)
|
||||
rep_scope = r"\[database\](.*?)\["
|
||||
rep_scope = r"\\[database\\](.*?)\\["
|
||||
tmp = re.findall(rep_scope, content, re.S)
|
||||
|
||||
rep = r'(\w*)\s*=\s*(.*)'
|
||||
rep = r'(\\w*)\\s*=\\s*(.*)'
|
||||
tmp = re.findall(rep, tmp[0])
|
||||
r = {}
|
||||
for x in range(len(tmp)):
|
||||
@@ -419,7 +419,7 @@ def getGogsConf():
|
||||
result = []
|
||||
|
||||
for g in gets:
|
||||
rep = g['name'] + '\s*=\s*(.*)'
|
||||
rep = g['name'] + '\\s*=\\s*(.*)'
|
||||
tmp = re.search(rep, conf)
|
||||
if not tmp:
|
||||
continue
|
||||
@@ -448,7 +448,7 @@ def submitGogsConf():
|
||||
conf = mw.readFile(filename)
|
||||
for g in gets:
|
||||
if g in args:
|
||||
rep = g + '\s*=\s*(.*)'
|
||||
rep = g + '\\s*=\\s*(.*)'
|
||||
val = g + ' = ' + args[g]
|
||||
conf = re.sub(rep, val, conf)
|
||||
mw.writeFile(filename, conf)
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,6 @@
|
||||
# gorse
|
||||
推荐系统
|
||||
|
||||
|
||||
# 脚本安装
|
||||
cd /www/server/mdserver-web/plugins && rm -rf gorse && git clone https://github.com/mw-plugin/gorse && cd gorse && rm -rf .git && cd /www/server/mdserver-web/plugins/gorse && bash install.sh install 0.4.15
|
||||
@@ -0,0 +1,92 @@
|
||||
[database]
|
||||
cache_store = "{$CONFIG_REDIS}"
|
||||
data_store = "mongodb://127.0.0.1:27017/gorse"
|
||||
#data_store = "mysql://gorse:gorse@tcp(127.0.0.1:33206)/gorse"
|
||||
|
||||
|
||||
table_prefix = "gorse_"
|
||||
cache_table_prefix = "gorse_"
|
||||
data_table_prefix = "gorse_"
|
||||
|
||||
[master]
|
||||
port = 8086
|
||||
host = "0.0.0.0"
|
||||
http_port = 8088
|
||||
http_host = "0.0.0.0"
|
||||
http_cors_domains = []
|
||||
http_cors_methods = []
|
||||
n_jobs = 1
|
||||
meta_timeout = "10s"
|
||||
dashboard_user_name = "{$CONFIG_ADMIN}"
|
||||
dashboard_password = "{$CONFIG_PASS}"
|
||||
admin_api_key = ""
|
||||
|
||||
[server]
|
||||
default_n = 10
|
||||
api_key = ""
|
||||
clock_error = "5s"
|
||||
auto_insert_user = true
|
||||
auto_insert_item = true
|
||||
cache_expire = "10s"
|
||||
|
||||
[recommend]
|
||||
cache_size = 100
|
||||
cache_expire = "72h"
|
||||
|
||||
[recommend.data_source]
|
||||
positive_feedback_types = ["star","like"]
|
||||
read_feedback_types = ["read"]
|
||||
positive_feedback_ttl = 0
|
||||
item_ttl = 0
|
||||
|
||||
[recommend.popular]
|
||||
popular_window = "720h"
|
||||
|
||||
[recommend.user_neighbors]
|
||||
neighbor_type = "similar"
|
||||
enable_index = true
|
||||
index_recall = 0.8
|
||||
index_fit_epoch = 3
|
||||
|
||||
[recommend.item_neighbors]
|
||||
neighbor_type = "similar"
|
||||
enable_index = true
|
||||
index_recall = 0.8
|
||||
index_fit_epoch = 3
|
||||
|
||||
[recommend.collaborative]
|
||||
enable_index = true
|
||||
index_recall = 0.9
|
||||
index_fit_epoch = 3
|
||||
model_fit_period = "60m"
|
||||
model_search_period = "360m"
|
||||
model_search_epoch = 100
|
||||
model_search_trials = 10
|
||||
enable_model_size_search = false
|
||||
|
||||
[recommend.replacement]
|
||||
enable_replacement = false
|
||||
positive_replacement_decay = 0.8
|
||||
read_replacement_decay = 0.6
|
||||
|
||||
[recommend.offline]
|
||||
check_recommend_period = "1m"
|
||||
refresh_recommend_period = "24h"
|
||||
enable_latest_recommend = true
|
||||
enable_popular_recommend = false
|
||||
enable_user_based_recommend = true
|
||||
enable_item_based_recommend = false
|
||||
enable_collaborative_recommend = true
|
||||
enable_click_through_prediction = true
|
||||
explore_recommend = { popular = 0.1, latest = 0.2 }
|
||||
|
||||
[recommend.online]
|
||||
fallback_recommend = ["item_based", "latest"]
|
||||
num_feedback_fallback_item_based = 10
|
||||
|
||||
[tracing]
|
||||
enable_tracing = false
|
||||
exporter = "jaeger"
|
||||
collector_endpoint = "http://localhost:14268/api/traces"
|
||||
sampler = "always"
|
||||
ratio = 1
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.3 KiB |
Executable
+30
@@ -0,0 +1,30 @@
|
||||
<style>
|
||||
.overflow_hide {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="bt-form">
|
||||
<div class='plugin_version'></div>
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<p class="bgw" onclick="pluginService('gorse');">服务</p>
|
||||
<p onclick="pluginInitD('gorse');">自启动</p>
|
||||
<p onclick="pluginConfigTpl('gorse',$('.plugin_version').attr('version'));">配置修改</p>
|
||||
<p onclick="pluginLogs('gorse','','run_log');">运行日志</p>
|
||||
<p onclick="gorseReadme();">相关说明</p>
|
||||
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
<div class="soft-man-con" style="height: 520px; overflow: auto;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$.getScript( "/plugins/file?name=gorse&f=js/gorse.js", function(){
|
||||
pluginService('gorse', $('.plugin_version').attr('version'));
|
||||
});
|
||||
</script>
|
||||
Executable
+342
@@ -0,0 +1,342 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'gorse'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getInitDFile():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return '/tmp/' + getPluginName()
|
||||
|
||||
if current_os.startswith('freebsd'):
|
||||
return '/etc/rc.d/' + getPluginName()
|
||||
|
||||
return '/etc/init.d/' + getPluginName()
|
||||
|
||||
|
||||
def getConf():
|
||||
path = getServerDir() + "/gorse.toml"
|
||||
return path
|
||||
|
||||
|
||||
def getConfTpl():
|
||||
path = getPluginDir() + "/config/gorse.toml"
|
||||
return path
|
||||
|
||||
|
||||
def getInitDTpl():
|
||||
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
|
||||
return path
|
||||
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[3:]
|
||||
tmp = {}
|
||||
args_len = len(args)
|
||||
|
||||
if args_len == 1:
|
||||
t = args[0].strip('{').strip('}')
|
||||
if t.strip() == '':
|
||||
tmp = []
|
||||
else:
|
||||
t = t.split(':',1)
|
||||
tmp[t[0]] = t[1]
|
||||
tmp[t[0]] = t[1]
|
||||
elif args_len > 1:
|
||||
for i in range(len(args)):
|
||||
t = args[i].split(':',1)
|
||||
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 configTpl():
|
||||
path = getPluginDir() + '/tpl'
|
||||
pathFile = os.listdir(path)
|
||||
tmp = []
|
||||
for one in pathFile:
|
||||
file = path + '/' + one
|
||||
tmp.append(file)
|
||||
return mw.getJson(tmp)
|
||||
|
||||
|
||||
def readConfigTpl():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
content = mw.readFile(args['file'])
|
||||
content = contentReplace(content)
|
||||
return mw.returnJson(True, 'ok', content)
|
||||
|
||||
def getPidFile():
|
||||
file = getConf()
|
||||
content = mw.readFile(file)
|
||||
rep = r'pidfile\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
return tmp.groups()[0].strip()
|
||||
|
||||
def status():
|
||||
# pid_file = getPidFile()
|
||||
# if not os.path.exists(pid_file):
|
||||
# return 'stop'
|
||||
|
||||
cmd = "ps aux|grep gorse |grep -v grep | grep -v python | grep -v mdserver-web | awk '{print $2}'"
|
||||
data = mw.execShell(cmd)
|
||||
|
||||
if data[0] == '':
|
||||
return 'stop'
|
||||
return 'start'
|
||||
|
||||
|
||||
def initRedisConf():
|
||||
requirepass = ""
|
||||
conf = mw.getServerDir() + '/redis/redis.conf'
|
||||
content = mw.readFile(conf)
|
||||
rep = r"^(requirepass" + r')\s*([.0-9A-Za-z_& ~]+)'
|
||||
tmp = re.search(rep, content, re.M)
|
||||
if tmp:
|
||||
requirepass = tmp.groups()[1]
|
||||
|
||||
port = "6379"
|
||||
rep = r"^(port)\s*([.0-9A-Za-z_& ~]+)"
|
||||
tmp = re.search(rep, content, re.M)
|
||||
if tmp:
|
||||
port = tmp.groups()[1]
|
||||
|
||||
return 'redis://:'+requirepass+'@127.0.0.1:'+port+'/3'
|
||||
|
||||
def contentReplace(content):
|
||||
service_path = mw.getServerDir()
|
||||
content = content.replace('{$ROOT_PATH}', mw.getRootDir())
|
||||
content = content.replace('{$SERVER_PATH}', service_path)
|
||||
content = content.replace('{$CONFIG_ADMIN}', mw.getRandomString(6))
|
||||
content = content.replace('{$CONFIG_PASS}', mw.getRandomString(10))
|
||||
content = content.replace('{$CONFIG_REDIS}', initRedisConf())
|
||||
return content
|
||||
|
||||
|
||||
def initDreplace():
|
||||
|
||||
file_tpl = getInitDTpl()
|
||||
service_path = os.path.dirname(os.getcwd())
|
||||
|
||||
initD_path = getServerDir() + '/init.d'
|
||||
if not os.path.exists(initD_path):
|
||||
mw.execShell("mkdir -p " + initD_path)
|
||||
|
||||
file_bin = initD_path + '/' + getPluginName()
|
||||
|
||||
# initd replace
|
||||
if not os.path.exists(file_bin):
|
||||
content = mw.readFile(file_tpl)
|
||||
content = content.replace('{$SERVER_PATH}', service_path)
|
||||
mw.writeFile(file_bin, content)
|
||||
mw.execShell('chmod +x ' + file_bin)
|
||||
|
||||
# log
|
||||
dataLog = getServerDir() + '/data'
|
||||
if not os.path.exists(dataLog):
|
||||
mw.execShell('chmod +x ' + file_bin)
|
||||
|
||||
# config replace
|
||||
dst_conf = getServerDir() + '/gorse.toml'
|
||||
dst_conf_init = getServerDir() + '/init.pl'
|
||||
if not os.path.exists(dst_conf_init):
|
||||
content = mw.readFile(getConfTpl())
|
||||
content = content.replace('{$SERVER_PATH}', service_path)
|
||||
content = contentReplace(content)
|
||||
mw.writeFile(dst_conf, content)
|
||||
mw.writeFile(dst_conf_init, 'ok')
|
||||
|
||||
# systemd
|
||||
systemDir = mw.systemdCfgDir()
|
||||
systemService = systemDir + '/' + getPluginName() + '.service'
|
||||
if os.path.exists(systemDir) and not os.path.exists(systemService):
|
||||
systemServiceTpl = getPluginDir() + '/init.d/' + getPluginName() + '.service.tpl'
|
||||
service_path = mw.getServerDir()
|
||||
content = mw.readFile(systemServiceTpl)
|
||||
content = content.replace('{$SERVER_PATH}', service_path)
|
||||
mw.writeFile(systemService, content)
|
||||
mw.execShell('systemctl daemon-reload')
|
||||
|
||||
return file_bin
|
||||
|
||||
|
||||
def gorseOp(method):
|
||||
file = initDreplace()
|
||||
|
||||
# print(file)
|
||||
|
||||
current_os = mw.getOs()
|
||||
if current_os == "darwin":
|
||||
data = mw.execShell(file + ' ' + method)
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
if current_os.startswith("freebsd"):
|
||||
data = mw.execShell('service ' + getPluginName() + ' ' + method)
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
data = mw.execShell('systemctl ' + method + ' ' + getPluginName())
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
|
||||
def start():
|
||||
return gorseOp('start')
|
||||
|
||||
|
||||
def stop():
|
||||
return gorseOp('stop')
|
||||
|
||||
|
||||
def restart():
|
||||
status = gorseOp('restart')
|
||||
log_file = runLog()
|
||||
mw.execShell("echo '' > " + log_file)
|
||||
return status
|
||||
|
||||
|
||||
def reload():
|
||||
return gorseOp('reload')
|
||||
|
||||
|
||||
def getPort():
|
||||
conf = getServerDir() + '/gorse.conf'
|
||||
content = mw.readFile(conf)
|
||||
|
||||
rep = "^(" + 'port' + ')\\s*([.0-9A-Za-z_& ~]+)'
|
||||
tmp = re.search(rep, content, re.M)
|
||||
if tmp:
|
||||
return tmp.groups()[1]
|
||||
|
||||
return '6379'
|
||||
|
||||
|
||||
def initdStatus():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
|
||||
if current_os.startswith('freebsd'):
|
||||
initd_bin = getInitDFile()
|
||||
if os.path.exists(initd_bin):
|
||||
return 'ok'
|
||||
|
||||
shell_cmd = 'systemctl status ' + getPluginName() + ' | grep loaded | grep "enabled;"'
|
||||
data = mw.execShell(shell_cmd)
|
||||
if data[0] == '':
|
||||
return 'fail'
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdInstall():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
|
||||
# freebsd initd install
|
||||
if current_os.startswith('freebsd'):
|
||||
import shutil
|
||||
source_bin = initDreplace()
|
||||
initd_bin = getInitDFile()
|
||||
shutil.copyfile(source_bin, initd_bin)
|
||||
mw.execShell('chmod +x ' + initd_bin)
|
||||
mw.execShell('sysrc ' + getPluginName() + '_enable="YES"')
|
||||
return 'ok'
|
||||
|
||||
mw.execShell('systemctl enable ' + getPluginName())
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdUinstall():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
|
||||
if current_os.startswith('freebsd'):
|
||||
initd_bin = getInitDFile()
|
||||
os.remove(initd_bin)
|
||||
mw.execShell('sysrc ' + getPluginName() + '_enable="NO"')
|
||||
return 'ok'
|
||||
|
||||
mw.execShell('systemctl disable ' + getPluginName())
|
||||
return 'ok'
|
||||
|
||||
|
||||
def runLog():
|
||||
return getServerDir() + '/logs.pl'
|
||||
|
||||
def installPreInspection():
|
||||
redis_path = mw.getServerDir() + "/redis"
|
||||
if not os.path.exists(redis_path):
|
||||
return "默认需要安装Redis"
|
||||
|
||||
mongodb_path = mw.getServerDir() + "/mongodb"
|
||||
if not os.path.exists(mongodb_path):
|
||||
return "默认需要安装MongoDB"
|
||||
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 == 'initd_status':
|
||||
print(initdStatus())
|
||||
elif func == 'initd_install':
|
||||
print(initdInstall())
|
||||
elif func == 'initd_uninstall':
|
||||
print(initdUinstall())
|
||||
elif func == 'install_pre_inspection':
|
||||
print(installPreInspection())
|
||||
elif func == 'conf':
|
||||
print(getConf())
|
||||
elif func == 'run_log':
|
||||
print(runLog())
|
||||
elif func == 'config_tpl':
|
||||
print(configTpl())
|
||||
elif func == 'read_config_tpl':
|
||||
print(readConfigTpl())
|
||||
else:
|
||||
print('error')
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"sort": 7,
|
||||
"ps": "一款高效简单的推荐系统【单机】",
|
||||
"name": "gorse",
|
||||
"title": "Gorse",
|
||||
"shell": "install.sh",
|
||||
"versions":["0.4.15"],
|
||||
"tip": "soft",
|
||||
"install_pre_inspection":true,
|
||||
"checks": "server/gorse",
|
||||
"path": "server/gorse",
|
||||
"display": 1,
|
||||
"author": "midoks",
|
||||
"date": "2024-06-12",
|
||||
"home": "https://gorse.io/zh/docs/master/deploy/binary.html",
|
||||
"type": 0,
|
||||
"pid": "5"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=Gorse, an open source recommender system service written in Go.
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
ExecStart={$SERVER_PATH}/gorse/bin/gorse-in-one -c {$SERVER_PATH}/gorse/gorse.toml \
|
||||
--log-path {$SERVER_PATH}/gorse/gorse.log \
|
||||
--cache-path {$SERVER_PATH}/gorse/data/cache.data
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,57 @@
|
||||
#!/bin/sh
|
||||
# chkconfig: 2345 55 25
|
||||
# description: Gorse Service
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: Gorse
|
||||
# Required-Start: $all
|
||||
# Required-Stop: $all
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: starts Gorse
|
||||
# Description: starts the MDW-Web
|
||||
### END INIT INFO
|
||||
|
||||
# Simple Gorse init.d script conceived to work on Linux systems
|
||||
# as it does use of the /proc filesystem.
|
||||
|
||||
CONF="{$SERVER_PATH}/gorse/gorse.toml"
|
||||
|
||||
APP_DIR={$SERVER_PATH}/gorse
|
||||
|
||||
app_start(){
|
||||
echo "Starting Gorse server..."
|
||||
echo "$APP_DIR/bin/gorse-in-one -c $CONF"
|
||||
nohup $APP_DIR/bin/gorse-in-one -c $CONF >> {$SERVER_PATH}/gorse/logs.pl 2>&1 &
|
||||
}
|
||||
|
||||
app_stop(){
|
||||
echo "Stopping ..."
|
||||
|
||||
find_gorse=`ps -ef | grep gorse | grep -v grep | awk "{print $2}"`
|
||||
for p in ${find_gorse[@]}
|
||||
do
|
||||
kill -9 $p > /dev/null 2>&1
|
||||
done
|
||||
|
||||
echo "Gorse stopped"
|
||||
}
|
||||
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
app_start
|
||||
;;
|
||||
stop)
|
||||
app_stop
|
||||
;;
|
||||
restart|reload)
|
||||
app_stop
|
||||
sleep 0.3
|
||||
app_start
|
||||
;;
|
||||
*)
|
||||
echo "Please use start or stop as first argument"
|
||||
;;
|
||||
esac
|
||||
|
||||
Executable
+97
@@ -0,0 +1,97 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
sysName=`uname`
|
||||
sysArch=`arch`
|
||||
|
||||
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/gorse && bash install.sh install 0.4.15
|
||||
# cd /www/server/mdserver-web/plugins/gorse && bash install.sh install 0.4.15
|
||||
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=$2
|
||||
|
||||
Install_App()
|
||||
{
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
mkdir -p $serverPath/source
|
||||
mkdir -p $serverPath/source/gorse
|
||||
|
||||
SYSNAME=linux
|
||||
if [ "$sysName" == "Darwin" ];then
|
||||
SYSNAME=darwin
|
||||
fi
|
||||
|
||||
ARCH="amd64"
|
||||
if [ "$sysArch" == "x86_64" ];then
|
||||
ARCH="amd64"
|
||||
elif [ "$sysArch" == "aarch64" ];then
|
||||
ARCH="arm64"
|
||||
elif [ "$sysArch" == "arm64" ];then
|
||||
ARCH="arm64"
|
||||
else
|
||||
ARCH="amd64"
|
||||
fi
|
||||
|
||||
FILE_TGZ=gorse_${SYSNAME}_${ARCH}.zip
|
||||
GORSE_DIR=$serverPath/source/gorse
|
||||
|
||||
# https://github.com/gorse-io/gorse/releases/download/v0.4.15/gorse_linux_amd64.zip
|
||||
echo "https://github.com/gorse-io/gorse/releases/download/v${VERSION}/${FILE_TGZ}"
|
||||
|
||||
if [ ! -f $GORSE_DIR/${FILE_TGZ} ];then
|
||||
wget -O $GORSE_DIR/${FILE_TGZ} https://github.com/gorse-io/gorse/releases/download/v${VERSION}/${FILE_TGZ}
|
||||
fi
|
||||
|
||||
mkdir -p $serverPath/gorse/bin
|
||||
mkdir -p $serverPath/gorse/logs
|
||||
cd $GORSE_DIR && unzip -d $serverPath/gorse/bin ${FILE_TGZ}
|
||||
|
||||
mkdir -p $serverPath/gorse/data
|
||||
echo "${VERSION}" > $serverPath/gorse/version.pl
|
||||
echo '安装Gorse完成'
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/gorse/index.py start
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/gorse/index.py initd_install
|
||||
|
||||
if [ -d ${GORSE_DIR}/gorse-${VERSION} ];then
|
||||
rm -rf ${GORSE_DIR}/gorse-${VERSION}
|
||||
fi
|
||||
}
|
||||
|
||||
Uninstall_App()
|
||||
{
|
||||
app_name=gorse
|
||||
systemctl_dir=/lib/systemd/system
|
||||
if [ -d /usr/lib/systemd/system ];then
|
||||
systemctl_dir=/usr/lib/systemd/system
|
||||
fi
|
||||
|
||||
if [ -f ${systemctl_dir}/${app_name}.service ];then
|
||||
systemctl stop ${app_name}
|
||||
systemctl disable ${app_name}
|
||||
rm -rf ${systemctl_dir}/${app_name}.service
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
|
||||
if [ -f $serverPath/${app_name}/initd/${app_name} ];then
|
||||
$serverPath/${app_name}/initd/${app_name} stop
|
||||
fi
|
||||
|
||||
if [ -d $serverPath/${app_name} ];then
|
||||
rm -rf $serverPath/${app_name}
|
||||
fi
|
||||
|
||||
echo "卸载Gorse成功"
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_App
|
||||
else
|
||||
Uninstall_App
|
||||
fi
|
||||
Executable
+68
@@ -0,0 +1,68 @@
|
||||
function gorsePost(method, version, args,callback){
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
|
||||
var req_data = {};
|
||||
req_data['name'] = 'gorse';
|
||||
req_data['func'] = method;
|
||||
req_data['version'] = version;
|
||||
|
||||
if (typeof(args) == 'string'){
|
||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
req_data['args'] = JSON.stringify(args);
|
||||
}
|
||||
|
||||
$.post('/plugins/run', req_data, function(data) {
|
||||
layer.close(loadT);
|
||||
if (!data.status){
|
||||
//错误展示10S
|
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof(callback) == 'function'){
|
||||
callback(data);
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
|
||||
function gorsePostCallbak(method, version, args,callback){
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
|
||||
var req_data = {};
|
||||
req_data['name'] = 'gorse';
|
||||
req_data['func'] = method;
|
||||
args['version'] = version;
|
||||
|
||||
if (typeof(args) == 'string'){
|
||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
req_data['args'] = JSON.stringify(args);
|
||||
}
|
||||
|
||||
$.post('/plugins/callback', req_data, 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 gorseReadme(){
|
||||
|
||||
|
||||
var readme = '<ul class="help-info-text c7">';
|
||||
readme += '<li>参考官方</li>';
|
||||
readme += '<li><a target="_blank" href="https://gorse.io">https://gorse.io</a></li>';
|
||||
readme += '<li>mongodb初始化,是无认证的</li>';
|
||||
readme += '</ul>';
|
||||
|
||||
$('.soft-man-con').html(readme);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,252 @@
|
||||
[database]
|
||||
|
||||
# The database for caching, support Redis, MySQL, Postgres and MongoDB:
|
||||
# redis://<user>:<password>@<host>:<port>/<db_number>
|
||||
# rediss://<user>:<password>@<host>:<port>/<db_number>
|
||||
# redis+cluster://<user>:<password>@<host1>:<port1>,<host2>:<port2>,...,<hostN>:<portN>
|
||||
# postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full
|
||||
# postgresql://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full
|
||||
# mongodb://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb][?options]]
|
||||
# mongodb+srv://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb][?options]]
|
||||
cache_store = "redis://localhost:6379/0"
|
||||
|
||||
# The database for persist data, support MySQL, Postgres, ClickHouse and MongoDB:
|
||||
# mysql://[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN]
|
||||
# postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full
|
||||
# postgresql://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full
|
||||
# clickhouse://user:password@host[:port]/database?param1=value1&...¶mN=valueN
|
||||
# chhttp://user:password@host[:port]/database?param1=value1&...¶mN=valueN
|
||||
# chhttps://user:password@host[:port]/database?param1=value1&...¶mN=valueN
|
||||
# mongodb://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb][?options]]
|
||||
# mongodb+srv://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb][?options]]
|
||||
data_store = "mysql://gorse:gorse_pass@tcp(localhost:3306)/gorse"
|
||||
|
||||
# The naming prefix for tables (collections, keys) in databases. The default value is empty.
|
||||
table_prefix = ""
|
||||
|
||||
# The naming prefix for tables (collections, keys) in cache storage databases. The default value is `table_prefix`.
|
||||
cache_table_prefix = ""
|
||||
|
||||
# The naming prefix for tables (collections, keys) in data storage databases. The default value is `table_prefix`.
|
||||
data_table_prefix = ""
|
||||
|
||||
[master]
|
||||
|
||||
# GRPC port of the master node. The default value is 8086.
|
||||
port = 8086
|
||||
|
||||
# gRPC host of the master node. The default values is "0.0.0.0".
|
||||
host = "0.0.0.0"
|
||||
|
||||
# HTTP port of the master node. The default values is 8088.
|
||||
http_port = 8088
|
||||
|
||||
# HTTP host of the master node. The default values is "0.0.0.0".
|
||||
http_host = "0.0.0.0"
|
||||
|
||||
# AllowedDomains is a list of allowed values for Http Origin.
|
||||
# The list may contain the special wildcard string ".*" ; all is allowed
|
||||
# If empty all are allowed.
|
||||
http_cors_domains = []
|
||||
|
||||
# AllowedMethods is either empty or has a list of http methods names. Checking is case-insensitive.
|
||||
http_cors_methods = []
|
||||
|
||||
# Number of working jobs in the master node. The default value is 1.
|
||||
n_jobs = 1
|
||||
|
||||
# Meta information timeout. The default value is 10s.
|
||||
meta_timeout = "10s"
|
||||
|
||||
# Username for the master node dashboard.
|
||||
dashboard_user_name = ""
|
||||
|
||||
# Password for the master node dashboard.
|
||||
dashboard_password = ""
|
||||
|
||||
# Secret key for admin APIs (SSL required).
|
||||
admin_api_key = ""
|
||||
|
||||
[server]
|
||||
|
||||
# Default number of returned items. The default value is 10.
|
||||
default_n = 10
|
||||
|
||||
# Secret key for RESTful APIs (SSL required).
|
||||
api_key = ""
|
||||
|
||||
# Clock error in the cluster. The default value is 5s.
|
||||
clock_error = "5s"
|
||||
|
||||
# Insert new users while inserting feedback. The default value is true.
|
||||
auto_insert_user = true
|
||||
|
||||
# Insert new items while inserting feedback. The default value is true.
|
||||
auto_insert_item = true
|
||||
|
||||
# Server-side cache expire time. The default value is 10s.
|
||||
cache_expire = "10s"
|
||||
|
||||
[recommend]
|
||||
|
||||
# The cache size for recommended/popular/latest items. The default value is 10.
|
||||
cache_size = 100
|
||||
|
||||
# Recommended cache expire time. The default value is 72h.
|
||||
cache_expire = "72h"
|
||||
|
||||
[recommend.data_source]
|
||||
|
||||
# The feedback types for positive events.
|
||||
positive_feedback_types = ["star","like"]
|
||||
|
||||
# The feedback types for read events.
|
||||
read_feedback_types = ["read"]
|
||||
|
||||
# The time-to-live (days) of positive feedback, 0 means disabled. The default value is 0.
|
||||
positive_feedback_ttl = 0
|
||||
|
||||
# The time-to-live (days) of items, 0 means disabled. The default value is 0.
|
||||
item_ttl = 0
|
||||
|
||||
[recommend.popular]
|
||||
|
||||
# The time window of popular items. The default values is 4320h.
|
||||
popular_window = "720h"
|
||||
|
||||
[recommend.user_neighbors]
|
||||
|
||||
# The type of neighbors for users. There are three types:
|
||||
# similar: Neighbors are found by number of common labels.
|
||||
# related: Neighbors are found by number of common liked items.
|
||||
# auto: If a user have labels, neighbors are found by number of common labels.
|
||||
# If this user have no labels, neighbors are found by number of common liked items.
|
||||
# The default value is "auto".
|
||||
neighbor_type = "similar"
|
||||
|
||||
# Enable approximate user neighbor searching using vector index. The default value is true.
|
||||
enable_index = true
|
||||
|
||||
# Minimal recall for approximate user neighbor searching. The default value is 0.8.
|
||||
index_recall = 0.8
|
||||
|
||||
# Maximal number of fit epochs for approximate user neighbor searching vector index. The default value is 3.
|
||||
index_fit_epoch = 3
|
||||
|
||||
[recommend.item_neighbors]
|
||||
|
||||
# The type of neighbors for items. There are three types:
|
||||
# similar: Neighbors are found by number of common labels.
|
||||
# related: Neighbors are found by number of common users.
|
||||
# auto: If a item have labels, neighbors are found by number of common labels.
|
||||
# If this item have no labels, neighbors are found by number of common users.
|
||||
# The default value is "auto".
|
||||
neighbor_type = "similar"
|
||||
|
||||
# Enable approximate item neighbor searching using vector index. The default value is true.
|
||||
enable_index = true
|
||||
|
||||
# Minimal recall for approximate item neighbor searching. The default value is 0.8.
|
||||
index_recall = 0.8
|
||||
|
||||
# Maximal number of fit epochs for approximate item neighbor searching vector index. The default value is 3.
|
||||
index_fit_epoch = 3
|
||||
|
||||
[recommend.collaborative]
|
||||
|
||||
# Enable approximate collaborative filtering recommend using vector index. The default value is true.
|
||||
enable_index = true
|
||||
|
||||
# Minimal recall for approximate collaborative filtering recommend. The default value is 0.9.
|
||||
index_recall = 0.9
|
||||
|
||||
# Maximal number of fit epochs for approximate collaborative filtering recommend vector index. The default value is 3.
|
||||
index_fit_epoch = 3
|
||||
|
||||
# The time period for model fitting. The default value is "60m".
|
||||
model_fit_period = "60m"
|
||||
|
||||
# The time period for model searching. The default value is "360m".
|
||||
model_search_period = "360m"
|
||||
|
||||
# The number of epochs for model searching. The default value is 100.
|
||||
model_search_epoch = 100
|
||||
|
||||
# The number of trials for model searching. The default value is 10.
|
||||
model_search_trials = 10
|
||||
|
||||
# Enable searching models of different sizes, which consume more memory. The default value is false.
|
||||
enable_model_size_search = false
|
||||
|
||||
[recommend.replacement]
|
||||
|
||||
# Replace historical items back to recommendations. The default value is false.
|
||||
enable_replacement = false
|
||||
|
||||
# Decay the weights of replaced items from positive feedbacks. The default value is 0.8.
|
||||
positive_replacement_decay = 0.8
|
||||
|
||||
# Decay the weights of replaced items from read feedbacks. The default value is 0.6.
|
||||
read_replacement_decay = 0.6
|
||||
|
||||
[recommend.offline]
|
||||
|
||||
# The time period to check recommendation for users. The default values is 1m.
|
||||
check_recommend_period = "1m"
|
||||
|
||||
# The time period to refresh recommendation for inactive users. The default values is 120h.
|
||||
refresh_recommend_period = "24h"
|
||||
|
||||
# Enable latest recommendation during offline recommendation. The default value is false.
|
||||
enable_latest_recommend = true
|
||||
|
||||
# Enable popular recommendation during offline recommendation. The default value is false.
|
||||
enable_popular_recommend = false
|
||||
|
||||
# Enable user-based similarity recommendation during offline recommendation. The default value is false.
|
||||
enable_user_based_recommend = true
|
||||
|
||||
# Enable item-based similarity recommendation during offline recommendation. The default value is false.
|
||||
enable_item_based_recommend = false
|
||||
|
||||
# Enable collaborative filtering recommendation during offline recommendation. The default value is true.
|
||||
enable_collaborative_recommend = true
|
||||
|
||||
# Enable click-though rate prediction during offline recommendation. Otherwise, results from multi-way recommendation
|
||||
# would be merged randomly. The default value is false.
|
||||
enable_click_through_prediction = true
|
||||
|
||||
# The explore recommendation method is used to inject popular items or latest items into recommended result:
|
||||
# popular: Recommend popular items to cold-start users.
|
||||
# latest: Recommend latest items to cold-start users.
|
||||
# The default values is { popular = 0.0, latest = 0.0 }.
|
||||
explore_recommend = { popular = 0.1, latest = 0.2 }
|
||||
|
||||
[recommend.online]
|
||||
|
||||
# The fallback recommendation method is used when cached recommendation drained out:
|
||||
# item_based: Recommend similar items to cold-start users.
|
||||
# popular: Recommend popular items to cold-start users.
|
||||
# latest: Recommend latest items to cold-start users.
|
||||
# Recommenders are used in order. The default values is ["latest"].
|
||||
fallback_recommend = ["item_based", "latest"]
|
||||
|
||||
# The number of feedback used in fallback item-based similar recommendation. The default values is 10.
|
||||
num_feedback_fallback_item_based = 10
|
||||
|
||||
[tracing]
|
||||
|
||||
# Enable tracing for REST APIs. The default value is false.
|
||||
enable_tracing = false
|
||||
|
||||
# The type of tracing exporters should be one of "jaeger", "zipkin", "otlp" and "otlphttp". The default value is "jaeger".
|
||||
exporter = "jaeger"
|
||||
|
||||
# The endpoint of tracing collector.
|
||||
collector_endpoint = "http://localhost:14268/api/traces"
|
||||
|
||||
# The type of tracing sampler should be one of "always", "never" and "ratio". The default value is "always".
|
||||
sampler = "always"
|
||||
|
||||
# The ratio of ratio based sampler. The default value is 1.
|
||||
ratio = 1
|
||||
@@ -38,7 +38,7 @@ max_connections = 500
|
||||
max_connect_errors = 100
|
||||
open_files_limit = 65535
|
||||
|
||||
skip-name-resolve = 1
|
||||
skip-name-resolve
|
||||
#skip-networking
|
||||
#skip-external-locking
|
||||
#loose-skip-innodb
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"uninstall_pre_inspection":true,
|
||||
"checks": "server/mariadb",
|
||||
"path": "server/mariadb",
|
||||
"versions":["10.6","10.7","10.8","10.9","10.11","11.0","11.1","11.2","11.3","11.4"],
|
||||
"versions":["10.6","10.7","10.8","10.9","10.11","11.0","11.1","11.2","11.3","11.4","11.5"],
|
||||
"shell":"install.sh",
|
||||
"checks":"server/mariadb",
|
||||
"path":"server/mariadb",
|
||||
|
||||
@@ -14,7 +14,7 @@ sysName=`uname`
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
mariadbDir=${serverPath}/source/mariadb
|
||||
|
||||
MY_VER=11.4.2
|
||||
MY_VER=11.4.3
|
||||
|
||||
Install_app()
|
||||
{
|
||||
|
||||
Executable
+121
@@ -0,0 +1,121 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
|
||||
#https://dev.mysql.com/downloads/mysql/5.5.html#downloads
|
||||
#https://dev.mysql.com/downloads/file/?id=480541
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
sysName=`uname`
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
mariadbDir=${serverPath}/source/mariadb
|
||||
|
||||
MY_VER=11.5.2
|
||||
|
||||
Install_app()
|
||||
{
|
||||
mkdir -p ${mariadbDir}
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
|
||||
if [ "$sysName" != "Darwin" ];then
|
||||
mkdir -p /var/log/mariadb
|
||||
touch /var/log/mariadb/mariadb.log
|
||||
fi
|
||||
|
||||
# ----- cpu start ------
|
||||
if [ -z "${cpuCore}" ]; then
|
||||
cpuCore="1"
|
||||
fi
|
||||
|
||||
if [ -f /proc/cpuinfo ];then
|
||||
cpuCore=`cat /proc/cpuinfo | grep "processor" | wc -l`
|
||||
fi
|
||||
|
||||
MEM_INFO=$(free -m|grep Mem|awk '{printf("%.f",($2)/1024)}')
|
||||
if [ "${cpuCore}" != "1" ] && [ "${MEM_INFO}" != "0" ];then
|
||||
if [ "${cpuCore}" -gt "${MEM_INFO}" ];then
|
||||
cpuCore="${MEM_INFO}"
|
||||
fi
|
||||
else
|
||||
cpuCore="1"
|
||||
fi
|
||||
|
||||
if [ "$cpuCore" -gt "2" ];then
|
||||
cpuCore=`echo "$cpuCore" | awk '{printf("%.f",($1)*0.8)}'`
|
||||
else
|
||||
cpuCore="1"
|
||||
fi
|
||||
# ----- cpu end ------
|
||||
|
||||
# if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
|
||||
# wget --no-check-certificate -O ${mariadbDir}/mariadb-${MY_VER}.tar.gz --tries=3 https://mirrors.aliyun.com/mariadb/mariadb-${MY_VER}/source/mariadb-${MY_VER}.tar.gz
|
||||
# fi
|
||||
|
||||
# https://downloads.mariadb.org/interstitial/mariadb-10.9.1/source/mariadb-10.9.1.tar.gz
|
||||
if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
|
||||
wget --no-check-certificate -O ${mariadbDir}/mariadb-${MY_VER}.tar.gz --tries=3 https://archive.mariadb.org/mariadb-${MY_VER}/source/mariadb-${MY_VER}.tar.gz
|
||||
fi
|
||||
|
||||
if [ ! -d ${mariadbDir}/mariadb-${MY_VER} ];then
|
||||
cd ${mariadbDir} && tar -zxvf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
|
||||
fi
|
||||
|
||||
INSTALL_CMD=cmake
|
||||
# check cmake version
|
||||
CMAKE_VERSION=`cmake -version | grep version | awk '{print $3}' | awk -F '.' '{print $1}'`
|
||||
if [ "$CMAKE_VERSION" -eq "2" ];then
|
||||
mkdir -p /var/log/mariadb
|
||||
touch /var/log/mariadb/mariadb.log
|
||||
INSTALL_CMD=cmake3
|
||||
fi
|
||||
|
||||
if [ ! -d $serverPath/mariadb ];then
|
||||
cd ${mariadbDir}/mariadb-${MY_VER} && ${INSTALL_CMD} \
|
||||
-DCMAKE_INSTALL_PREFIX=$serverPath/mariadb \
|
||||
-DMYSQL_DATADIR=$serverPath/mariadb/data/ \
|
||||
-DMYSQL_USER=mysql \
|
||||
-DMYSQL_UNIX_ADDR=$serverPath/mariadb/mysql.sock \
|
||||
-DWITH_MYISAM_STORAGE_ENGINE=1 \
|
||||
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
|
||||
-DWITH_MEMORY_STORAGE_ENGINE=1 \
|
||||
-DENABLED_LOCAL_INFILE=1 \
|
||||
-DWITH_PARTITION_STORAGE_ENGINE=1 \
|
||||
-DEXTRA_CHARSETS=all \
|
||||
-DDEFAULT_CHARSET=utf8mb4 \
|
||||
-DDEFAULT_COLLATION=utf8mb4_general_ci \
|
||||
-DCMAKE_C_COMPILER=/usr/bin/gcc \
|
||||
-DCMAKE_CXX_COMPILER=/usr/bin/g++
|
||||
make -j${cpuCore} && make install && make clean
|
||||
|
||||
if [ -d $serverPath/mariadb ];then
|
||||
echo '11.4' > $serverPath/mariadb/version.pl
|
||||
echo '安装完成'
|
||||
else
|
||||
echo '安装失败'
|
||||
echo 'install fail'>&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -d ${mariadbDir}/mariadb-${MY_VER} ];then
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
Uninstall_app()
|
||||
{
|
||||
rm -rf $serverPath/mariadb
|
||||
echo '卸载完成' > $install_tmp
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_app
|
||||
else
|
||||
Uninstall_app
|
||||
fi
|
||||
@@ -209,10 +209,10 @@ def runInfo():
|
||||
|
||||
conf = mw.readFile(getServerDir() + '/memcached.env')
|
||||
result['bind'] = re.search('IP=(.+)', conf).groups()[0]
|
||||
result['port'] = int(re.search('PORT=(\d+)', conf).groups()[0])
|
||||
result['maxconn'] = int(re.search('MAXCONN=(\d+)', conf).groups()[0])
|
||||
result['port'] = int(re.search('PORT=(\\d+)', conf).groups()[0])
|
||||
result['maxconn'] = int(re.search('MAXCONN=(\\d+)', conf).groups()[0])
|
||||
result['cachesize'] = int(
|
||||
re.search('CACHESIZE=(\d+)', conf).groups()[0])
|
||||
re.search('CACHESIZE=(\\d+)', conf).groups()[0])
|
||||
return mw.getJson(result)
|
||||
except Exception as e:
|
||||
return mw.getJson({})
|
||||
|
||||
@@ -15,14 +15,14 @@ echo $sys_os
|
||||
|
||||
Install_mem(){
|
||||
mkdir -p $serverPath/source
|
||||
# mkdir -p $serverPath/memcached
|
||||
mkdir -p $serverPath/source/memcached
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
|
||||
if [ ! -f $serverPath/source/memcached.tar.gz ];then
|
||||
wget --no-check-certificate -O $serverPath/source/memcached.tar.gz http://www.memcached.org/files/memcached-${VERSION}.tar.gz
|
||||
wget --no-check-certificate -O $serverPath/source/memcached/memcached.tar.gz https://www.memcached.org/files/memcached-${VERSION}.tar.gz
|
||||
fi
|
||||
|
||||
cd $serverPath/source && tar -zxvf memcached.tar.gz
|
||||
cd $serverPath/source/memcached && tar -zxvf memcached.tar.gz
|
||||
|
||||
OPTIONS=''
|
||||
if [ ${sys_os} == "Darwin" ]; then
|
||||
@@ -31,7 +31,7 @@ Install_mem(){
|
||||
fi
|
||||
|
||||
echo "./configure --prefix=${serverPath}/memcached && make && make install"
|
||||
cd $serverPath/source/memcached-${VERSION}
|
||||
cd $serverPath/source/memcached/memcached-${VERSION}
|
||||
./configure --prefix=$serverPath/memcached \
|
||||
$OPTIONS
|
||||
|
||||
@@ -39,12 +39,12 @@ Install_mem(){
|
||||
|
||||
if [ -d $serverPath/memcached ];then
|
||||
echo '1.6' > $serverPath/memcached/version.pl
|
||||
echo 'install ok' > $install_tmp
|
||||
echo '安装memcached成功'
|
||||
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/memcached/index.py start
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/memcached/index.py initd_install
|
||||
|
||||
rm -rf $serverPath/source/memcached-${VERSION}
|
||||
rm -rf $serverPath/source/memcached/memcached-${VERSION}
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ Uninstall_mem()
|
||||
$serverPath/memcached/initd/memcached stop
|
||||
fi
|
||||
rm -rf $serverPath/memcached
|
||||
echo '卸载memcached成功'
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -662,6 +662,27 @@ def delDb():
|
||||
except Exception as ex:
|
||||
return mw.returnJson(False, '删除失败!' + str(ex))
|
||||
|
||||
|
||||
def delDbTable():
|
||||
client = mongdbClient()
|
||||
db = client.admin
|
||||
sqlite_db = pSqliteDb('databases')
|
||||
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['table_name', 'name'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
name = args['name']
|
||||
table_name = args['table_name']
|
||||
|
||||
try:
|
||||
cur_db = client[name]
|
||||
cur_db[table_name].drop()
|
||||
return mw.returnJson(True, '删除成功!')
|
||||
except Exception as ex:
|
||||
return mw.returnJson(False, '删除失败!' + str(ex))
|
||||
|
||||
def setRootPwd(version=''):
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['password'])
|
||||
@@ -1289,6 +1310,10 @@ def getListBson(dbname=''):
|
||||
r.append(x)
|
||||
return r
|
||||
|
||||
def rootPwd():
|
||||
return pSqliteDb('config').where(
|
||||
'id=?', (1,)).getField('mg_root')
|
||||
|
||||
def importDbExternal():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['file', 'name'])
|
||||
@@ -1568,12 +1593,16 @@ if __name__ == "__main__":
|
||||
print(saveConfig())
|
||||
elif func == 'set_config_auth':
|
||||
print(setConfigAuth())
|
||||
elif func == 'root_pwd':
|
||||
print(rootPwd())
|
||||
elif func == 'get_db_list':
|
||||
print(getDbList())
|
||||
elif func == 'add_db':
|
||||
print(addDb())
|
||||
elif func == 'del_db':
|
||||
print(delDb())
|
||||
elif func == 'del_db_table':
|
||||
print(delDbTable())
|
||||
elif func == 'set_root_pwd':
|
||||
print(setRootPwd())
|
||||
elif func == 'set_user_pwd':
|
||||
|
||||
@@ -36,7 +36,7 @@ if [ -f ${rootPath}/bin/activate ];then
|
||||
fi
|
||||
Install_app()
|
||||
{
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
echo '正在安装脚本文件...'
|
||||
mkdir -p $serverPath/source
|
||||
|
||||
# if id mongodb &> /dev/null ;then
|
||||
@@ -66,7 +66,7 @@ Install_app()
|
||||
if [ -f $shell_file ];then
|
||||
bash -x $shell_file
|
||||
else
|
||||
echo '不支持...' > $install_tmp
|
||||
echo '不支持...'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
@@ -767,6 +767,18 @@ function delDb(id, name){
|
||||
});
|
||||
}
|
||||
|
||||
function delDbTable( name, table_name){
|
||||
safeMessage('删除['+name+']','您真的要删除['+table_name+']吗?',function(){
|
||||
var data='name='+name+'&table_name='+table_name;
|
||||
mgPost('del_db_table', '', data, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
repTools(name);
|
||||
},{icon: rdata.status ? 1 : 2}, 600);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function delDbBatch(){
|
||||
var arr = [];
|
||||
$('input[type="checkbox"].check:checked').each(function () {
|
||||
@@ -835,22 +847,10 @@ function setDbPass(id, username, password){
|
||||
}
|
||||
|
||||
function repTools(db_name, res){
|
||||
|
||||
mgPost('get_db_info', '', {name:db_name}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
var rdata = rdata.data;
|
||||
// console.log(rdata.collection_list);
|
||||
var tbody = '';
|
||||
for (var i = 0; i < rdata.collection_list.length; i++) {
|
||||
tbody += '<tr>\
|
||||
<td><span style="width:220px;"> ' + rdata.collection_list[i].collection_name + '</span></td>\
|
||||
<td><span style="width:220px;"> ' + rdata.collection_list[i].count + '</span></td>\
|
||||
<td>' + toSize(rdata.collection_list[i].size) + '</td>\
|
||||
<td><span style="width:90px;"> ' + toSize(rdata.collection_list[i].avg_obj_size) + '</span></td>\
|
||||
<td>' + toSize(rdata.collection_list[i].storage_size) + '</td>\
|
||||
<td>' + rdata.collection_list[i].nindexes + '</td>\
|
||||
<td>' + toSize(rdata.collection_list[i].total_index_size) + '</td>\
|
||||
</tr> '
|
||||
}
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
@@ -858,7 +858,7 @@ function repTools(db_name, res){
|
||||
area: ['780px', '480px'],
|
||||
closeBtn: 1,
|
||||
shadeClose: false,
|
||||
content: '<div class="pd15">\
|
||||
content: '<div class="pd15" id="mongodb_list">\
|
||||
<div class="db_list">\
|
||||
<span><a>数据库名称:'+ db_name + '</a>\
|
||||
<a>集合:'+ rdata.collections + '</a>\
|
||||
@@ -879,13 +879,51 @@ function repTools(db_name, res){
|
||||
<th>存储大小</th>\
|
||||
<th>索引数量</th>\
|
||||
<th>索引大小</th>\
|
||||
<th>操作</th>\
|
||||
</tr>\
|
||||
</thead>\
|
||||
<tbody class="gztr">' + tbody + '</tbody>\
|
||||
<tbody class="gztr"></tbody>\
|
||||
</table>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>'
|
||||
</div>',
|
||||
success:function(layer_id, layer_index){
|
||||
|
||||
var tbody = '';
|
||||
for (var i = 0; i < rdata.collection_list.length; i++) {
|
||||
tbody += '<tr>\
|
||||
<td><span style="width:220px;"> ' + rdata.collection_list[i].collection_name + '</span></td>\
|
||||
<td><span style="width:220px;"> ' + rdata.collection_list[i].count + '</span></td>\
|
||||
<td>' + toSize(rdata.collection_list[i].size) + '</td>\
|
||||
<td><span style="width:90px;"> ' + toSize(rdata.collection_list[i].avg_obj_size) + '</span></td>\
|
||||
<td>' + toSize(rdata.collection_list[i].storage_size) + '</td>\
|
||||
<td>' + rdata.collection_list[i].nindexes + '</td>\
|
||||
<td>' + toSize(rdata.collection_list[i].total_index_size) + '</td>\
|
||||
<td>' + '<a href="javascript:;" data-index="'+i+'" class="delete btlink" title="删除">删除</a>'+'</td>\
|
||||
</tr>';
|
||||
}
|
||||
|
||||
$('#mongodb_list tbody').html(tbody);
|
||||
|
||||
$('#mongodb_list .delete').click(function(){
|
||||
var index = $(this).data('index');
|
||||
|
||||
var name = db_name;
|
||||
var table_name = rdata.collection_list[index].collection_name;
|
||||
|
||||
safeMessage('删除['+name+']','您真的要删除['+table_name+']吗?',function(){
|
||||
var data='name='+name+'&table_name='+table_name;
|
||||
mgPost('del_db_table', '', data, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
layer.close(layer_index);
|
||||
repTools(name);
|
||||
},{icon: rdata.status ? 1 : 2}, 600);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
tableFixed('database_fix');
|
||||
});
|
||||
|
||||
@@ -172,7 +172,7 @@ class backupTools:
|
||||
if auth != 'disabled':
|
||||
uoption =' --authenticationDatabase admin -u root -p '+mg_root
|
||||
|
||||
cmd = db_path + "/bin/mongodump "+uoption+" --port "+str(port)+" -d test -o "+backup_path
|
||||
cmd = db_path + "/bin/mongodump "+uoption+" --port "+str(port)+" -d "+name+" -o "+backup_path
|
||||
# print(cmd)
|
||||
mw.execShell(cmd)
|
||||
cmd_gz = "cd "+backup_path+"/"+name+" && tar -zcvf "+filename + " ./"
|
||||
|
||||
@@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=5.0.20
|
||||
VERSION=5.0.29
|
||||
SYS_ARCH=`arch`
|
||||
|
||||
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
|
||||
|
||||
@@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=5.0.20
|
||||
VERSION=5.0.29
|
||||
SYS_ARCH=`arch`
|
||||
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
|
||||
SYS_NAME=${SYS_VERSION_ID/./}
|
||||
|
||||
@@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=5.0.20
|
||||
VERSION=5.0.29
|
||||
|
||||
MG_DIR=$serverPath/source/mongodb
|
||||
mkdir -p $MG_DIR
|
||||
|
||||
@@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=5.0.20
|
||||
VERSION=5.0.29
|
||||
SYS_ARCH=`arch`
|
||||
|
||||
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}' | awk -F . '{print $1}'`
|
||||
|
||||
@@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=5.0.20
|
||||
VERSION=5.0.29
|
||||
SYS_ARCH=`arch`
|
||||
|
||||
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
|
||||
|
||||
@@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=6.0.9
|
||||
VERSION=6.0.18
|
||||
SYS_ARCH=`arch`
|
||||
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
|
||||
SYS_NAME=${SYS_VERSION_ID/./}
|
||||
|
||||
@@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=6.0.9
|
||||
VERSION=6.0.18
|
||||
|
||||
MG_DIR=$serverPath/source/mongodb
|
||||
mkdir -p $MG_DIR
|
||||
|
||||
@@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=6.0.9
|
||||
VERSION=6.0.18
|
||||
SYS_ARCH=`arch`
|
||||
|
||||
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}' | awk -F . '{print $1}'`
|
||||
|
||||
@@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=6.0.9
|
||||
VERSION=6.0.18
|
||||
SYS_ARCH=`arch`
|
||||
|
||||
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user