update to 6.8.37

This commit is contained in:
zhw
2024-04-29 15:35:04 +08:00
parent fa9a865beb
commit ed34994f45
474 changed files with 125711 additions and 34665 deletions
+469
View File
@@ -0,0 +1,469 @@
#coding: utf-8
# + -------------------------------------------------------------------
# | 宝塔Linux面板
# + -------------------------------------------------------------------
# | Copyright (c) 2015-2016 宝塔软件(http:#bt.cn) All rights reserved.
# + -------------------------------------------------------------------
# | Author: hezhihong <272267659@@qq.cn>
# + -------------------------------------------------------------------
import public, os, time
from logsModel.base import logsBase
try:
from BTPanel import session
except:
pass
#英文转月份缩写
month_list = {
"Jan": "1",
"Feb": "2",
"Mar": "3",
"Apr": "4",
"May": "5",
"Jun": "6",
"Jul": "7",
"Aug": "8",
"Sept": "9",
"Sep": "9",
"Oct": "10",
"Nov": "11",
"Dec": "12"
}
class main(logsBase):
def __init__(self):
self.__messages_file = "/var/log/"
self.__ftp_backup_path = public.get_backup_path() + '/pure-ftpd/'
if not os.path.isdir(self.__ftp_backup_path):
public.ExecShell('mkdir -p {}'.format(self.__ftp_backup_path))
self.__script_py = public.get_panel_path() + '/script/ftplogs_cut.py'
def get_file_list(self, path, is_bakcup=False):
"""
@name 取所有messages日志文件
@param path: 日志文件路径
@return: 返回日志文件列表
"""
files = os.listdir(path)
if is_bakcup:
file_name_list = [{
"file": "/var/log/pure-ftpd.log",
"time": int(time.time())
}]
else:
file_name_list = []
for i in files:
tmp_dict = {}
if not i: continue
file_path = path + i
tmp_dict['file'] = file_path
if is_bakcup:
if os.path.isfile(file_path) and i.find('pure-ftpd.log') != -1:
tmp_dict['time'] = int(
public.to_date(
times=os.path.basename(file_path).split('_')[0] +
' 00:00:00'))
file_name_list.append(tmp_dict)
else:
if os.path.isfile(file_path) and i.find('messages') != -1:
tmp_dict['time'] = int(
public.to_date(
times=os.path.basename(file_path).split('-')[1] +
' 00:00:00'))
file_name_list.append(tmp_dict)
file_name_list = sorted(file_name_list,
key=lambda x: x['time'],
reverse=False)
return file_name_list
def set_ftp_log(self, get):
"""
@name 开启、关闭、获取日志状态
@author hezhihong
@param get.exec_name 执行的动作
"""
if not hasattr(get, 'exec_name'):
return public.returnMsg(False, 'The parameter is incorrect')
conf_path = '/etc/rsyslog.conf'
conf = public.readFile(conf_path)
import re
search_str = r"ftp\.\*.*\t*.*\t*.*-/var/log/pure-ftpd.log"
search_str_two = "ftp.none"
rep_str = '\nftp.*\t\t-/var/log/pure-ftpd.log\n'
result = re.search(search_str, conf)
#获取日志状态
if get.exec_name == 'getlog':
if result:
return_result = 'start'
else:
return_result = 'stop'
return public.returnMsg(True, return_result)
#开启日志审计
elif get.exec_name == 'start':
if result:
conf = conf.replace(search_str, rep_str)
else:
conf += rep_str
#禁止ftp日志写入/var/log/messages
d_conf = conf[conf.rfind('info;'):]
d_conf = d_conf[:d_conf.find('/')]
s_conf = d_conf.replace(',', ';')
if s_conf.find(search_str_two) == -1:
str_index = s_conf.rfind(';')
s_conf = s_conf[:str_index +
1] + search_str_two + s_conf[str_index + 1:]
conf = conf.replace(d_conf, s_conf)
self.add_crontab()
#关闭日志审计
elif get.exec_name == 'stop':
if result:
conf = re.sub(search_str, '', conf)
#取消禁止ftp日志写入/var/log/messages
if conf.find(search_str_two) != -1:
conf = conf.replace(search_str_two, '')
for i in [';;', ',,', ';,', ',;']:
if conf.find(i) != -1: conf = conf.replace(i, '')
self.del_crontab()
public.writeFile(conf_path, conf)
public.ExecShell('systemctl restart rsyslog')
return public.returnMsg(True, 'successfully set')
def get_format_time(self, englist_time):
"""
@name 时间英文转换
"""
chinanese_time = ''
try:
for i in month_list.keys():
if i in englist_time:
tmp_time = englist_time.replace(i, month_list[i])
tmp_time = tmp_time.split()
chinanese_time = '{}-{} {}'.format(tmp_time[0], tmp_time[1],
tmp_time[2])
break
return chinanese_time
except:
return chinanese_time
def get_login_log(self, get):
"""
@name 取登录日志
@author hezhihong
@param get.user_name ftp用户名
return
"""
search_str = 'pure-ftpd:'
search_str2 = 'pure-ftpd['
if not hasattr(get, 'user_name'):
return public.returnMsg(False, 'The parameter is incorrect')
args = public.dict_obj()
args.exec_name = 'getlog'
file_name = self.__ftp_backup_path
is_backup = True
if self.set_ftp_log(get) == 'stop':
file_name = self.__messages_file
is_backup = False
file_list = self.get_file_list(file_name, is_backup)
data = []
sortid = 0
tmp_dict = {}
login_all = []
for file in file_list:
if not os.path.isfile(file['file']): continue
conf = public.readFile(file['file'])
lines = conf.split('\n')
for line in lines:
if not line: continue
login_info = {}
if search_str not in line and search_str2 not in line:
continue
tmp_value = ' is now logged in'
info = line[:line.find(search_str)].strip()
if not info:
info = line[:line.find(search_str2)].strip()
hostname = info.split()[-1]
exec_time = info.split(hostname)[0].strip()
exec_time = self.get_format_time(exec_time)
ip = line[line.find('(') + 1:line.find(')')].split('@')[1]
#取登录成功日志
if tmp_value in line:
user = line.split(tmp_value)[0].strip().split()[-1]
if user == '?' or user != get.user_name: continue
dict_index = '{}__{}'.format(user, ip)
if dict_index not in tmp_dict:
tmp_dict[dict_index] = []
tmp_dict[dict_index].append(exec_time)
#取登出日志
tmp_value = '[INFO] Logout.'
tmp_value_two = 'Timeout - try typing a little faster next time'
if tmp_value in line or tmp_value_two in line:
user = line[line.find('(') +
1:line.find(')')].split('@')[0]
if user == '?' or user != get.user_name: continue
dict_index = '{}__{}'.format(user, ip)
try:
login_info['out_time'] = exec_time
login_info['in_time'] = tmp_dict[dict_index][0]
login_info['user'] = user
login_info['ip'] = ip
login_info['status'] = 'Success' #0为登录失败,1为登录成功
login_info['sortid'] = sortid
login_all.append(login_info)
tmp_dict[dict_index] = []
sortid += 1
except:
pass
#取登录失败日志
tmp_value = 'Authentication failed for user'
if tmp_value in line:
user = line.split(tmp_value)[-1].replace('[', '').replace(
']', '').strip()
if user == '?' or user != get.user_name: continue
login_info['user'] = user
login_info['ip'] = ip
login_info['status'] = 'Failure' #0为登录失败,1为登录成功
login_info['in_time'] = exec_time
login_info['out_time'] = exec_time
login_info['sortid'] = sortid
login_all.append(login_info)
sortid += 1
if tmp_dict:
for item in tmp_dict.keys():
if not tmp_dict[item]: continue
info = {
"status": "login successful",
"in_time": tmp_dict[item][0],
"out_time": "connecting",
"user": item.split('__')[0],
"ip": item.split('__')[1],
"sortid": sortid
}
sortid += 1
login_all.append(info)
#搜索过滤
if login_all and 'search' in get and get.search and get.search.strip():
for info in login_all:
try:
search_str = str(get.search).strip().lower()
# public.writeFile('/tmp/aa.aa', get.search)
if info['ip'].find(search_str) != -1 or info['user'].lower(
).find(search_str) != -1 or info['status'].find(
search_str) != -1 or info['in_time'].find(
search_str) != -1:
data.append(info)
elif info['out_time'] and info['out_time'].find(
search_str) != -1:
data.append(info)
except:
pass
else:
for info2 in login_all:
data.append(info2)
data = sorted(data, key=lambda x: x['sortid'], reverse=True)
return self.get_page(data, get)
def get_page(self, data, get):
"""
@name 取分页
@author hezhihong
@param data 需要分页的数据 list
@param get.p 第几页
@return 指定分页数据
"""
# 包含分页类
import page
# 实例化分页类
page = page.Page()
info = {}
info['count'] = len(data)
info['row'] = 10
info['p'] = 1
if hasattr(get, 'p'):
info['p'] = int(get['p'])
info['uri'] = {}
info['return_js'] = ''
# 获取分页数据
result = {}
result['page'] = page.GetPage(info, limit='1,2,3,4,5,8')
n = 0
result['data'] = []
for i in range(info['count']):
if n >= page.ROW: break
if i < page.SHIFT: continue
n += 1
result['data'].append(data[i])
return result
def get_action_log(self, get):
"""
@name 取操作日志
@author hezhihong
@param get.user_name ftp用户名
return {"upload":[],"download":[],"rename":[],"delete":[]}
"""
search_str = 'pure-ftpd:'
args = public.dict_obj()
args.exec_name = 'getlog'
file_name = self.__ftp_backup_path
is_backup = True
if self.set_ftp_log(get) == 'stop':
file_name = self.__messages_file
is_backup = False
file_list = self.get_file_list(file_name, is_backup)
if not hasattr(get, 'user_name'):
return public.returnMsg(False, 'The parameter is incorrect')
data = []
tmp_data = []
sortid = 0
for file in file_list:
if not os.path.isfile(file['file']): continue
conf = public.readFile(file['file'])
lines = conf.split('\n')
for line in lines:
if not line: continue
action_info = {}
if search_str not in line: continue
tmp_v = line.split(search_str)
hostname = tmp_v[0].strip().split()[3].strip()
action_time = tmp_v[0].replace(hostname, '').strip()
action_info['time'] = self.get_format_time(action_time)
upload_value = ' uploaded '
download_value = ' downloaded '
rename_value = 'successfully renamed or moved:'
delete_value = ' Deleted '
ip = line[line.find('(') + 1:line.find(')')].split('@')[1]
action_info['ip'] = ip
action_info['type'] = ''
#取操作用户
user = ''
if upload_value in line or download_value in line or rename_value in line or delete_value in line:
user = line[line.find('(') +
1:line.find(')')].split('@')[0]
action_info['sortid'] = sortid
sortid = sortid + 1
if not user or user != get.user_name: continue
#取上传日志
if (get.type == 'all'
or get.type == 'upload') and upload_value in line:
line_list = line.split()
upload_index = line_list.index('uploaded')
# action_info['file'] = line_list[upload_index - 1].replace(
# '//', '/')
action_info['file'] = line[line.find(']') +
1:line.rfind('(')].replace(
'uploaded',
'').replace('//',
'/').strip()
action_info['type'] = 'upload'
tmp_data.append(action_info)
#取下载日志
if (get.type == 'all'
or get.type == 'download') and download_value in line:
line_list = line.split()
upload_index = line_list.index('downloaded')
action_info['file'] = line_list[upload_index - 1].replace(
'//', '/')
action_info['type'] = 'download'
tmp_data.append(action_info)
#取重命名日志
if (get.type == 'all'
or get.type == 'rename') and rename_value in line:
action_info['file'] = line.split(rename_value)[1].replace(
'->', 'Renamed to').strip().replace('//', '/')
action_info['type'] = 'rename'
tmp_data.append(action_info)
#取删除日志
if (get.type == 'all'
or get.type == 'delete') and delete_value in line:
action_info['file'] = line.split()[-1].strip().replace(
'//', '/')
action_info['type'] = 'delete'
tmp_data.append(action_info)
# f.close
#搜索过滤
if tmp_data and 'search' in get and get.search and get.search.strip():
for info in tmp_data:
search_str = str(get.search).strip().lower()
if info['ip'].find(search_str) != -1 or info['file'].lower(
).find(search_str) != -1 or info['type'].find(
search_str) != -1 or info['time'].find(
search_str) != -1 or get.user_name.lower().find(
search_str) != -1:
data.append(info)
else:
for info2 in tmp_data:
data.append(info2)
data = sorted(data, key=lambda x: x['sortid'], reverse=True)
return self.get_page(data, get)
def del_crontab(self):
"""
@name 删除项目定时清理任务
@auther hezhihong<2022-10-31>
@return
"""
cron_name = '[Do not delete] FTP audit log cutting task'
cron_path = public.GetConfigValue('setup_path') + '/cron/'
cron_list = public.M('crontab').where("name=?", (cron_name, )).select()
if cron_list:
for i in cron_list:
if not i: continue
cron_echo = public.M('crontab').where(
"id=?", (i['id'], )).getField('echo')
args = {"id": i['id']}
import crontab
crontab.crontab().DelCrontab(args)
del_cron_file = cron_path + cron_echo
public.ExecShell(
"crontab -u root -l| grep -v '{}'|crontab -u root -".
format(del_cron_file))
def add_crontab(self):
"""
@name 构造日志切割任务
"""
python_path = ''
try:
python_path = public.ExecShell('which btpython')[0].strip("\n")
except:
try:
python_path = public.ExecShell('which python')[0].strip("\n")
except:
pass
if not python_path: return False
if not public.M('crontab').where('name=?',
('[Do not delete] FTP audit log cutting task', )).count():
cmd = '{} {}'.format(python_path, self.__script_py)
args = {
"name": "[Do not delete] FTP audit log cutting task",
"type": 'day',
"where1": '',
"hour": '0',
"minute": '1',
"sName": "",
"sType": 'toShell',
"notice": '0',
"notice_channel": '',
"save": '',
"save_local": '1',
"backupTo": '',
"sBody": cmd,
"urladdress": ''
}
import crontab
res = crontab.crontab().AddCrontab(args)
if res and "id" in res.keys():
return True
return False
return True