846 lines
31 KiB
Python
846 lines
31 KiB
Python
#coding: utf-8
|
||
# +-------------------------------------------------------------------
|
||
# | yakpanel Windows面板
|
||
# +-------------------------------------------------------------------
|
||
# | Copyright (c) 2015-2020 yakpanel(https://www.yakpanel.com) All rights reserved.
|
||
# +-------------------------------------------------------------------
|
||
# | Author: 沐落 <cjx@yakpanel.com>
|
||
# +-------------------------------------------------------------------
|
||
import sys, os, time, json, re, psutil
|
||
|
||
panelPath = "/www/server/panel"
|
||
os.chdir(panelPath)
|
||
sys.path.append("class/")
|
||
import public,db,time,html,panelPush
|
||
import config
|
||
|
||
try:
|
||
from YakPanel import cache
|
||
except :
|
||
from cachelib import SimpleCache
|
||
cache = SimpleCache()
|
||
|
||
class site_push:
|
||
|
||
__push = None
|
||
__push_model = ['dingding','weixin','mail','sms','wx_account','feishu']
|
||
__conf_path = "{}/class/push/push.json".format(panelPath)
|
||
pids = None
|
||
|
||
def __init__(self):
|
||
self.__push = panelPush.panelPush()
|
||
|
||
#-----------------------------------------------------------start 添加推送 ------------------------------------------------------
|
||
def get_version_info(self,get):
|
||
"""
|
||
获取版本信息
|
||
"""
|
||
data = {}
|
||
data['ps'] = ''
|
||
data['version'] = '1.0'
|
||
data['date'] = '2020-08-10'
|
||
data['author'] = 'YakPanel'
|
||
data['help'] = 'http://www.yakpanel.com'
|
||
return data
|
||
|
||
"""
|
||
@获取推送模块配置
|
||
"""
|
||
def get_module_config(self,get):
|
||
|
||
stype = None
|
||
if 'type' in get:
|
||
stype = get.type
|
||
|
||
data = []
|
||
#证书到期提醒
|
||
item = self.__push.format_push_data()
|
||
item['cycle'] = 30
|
||
item['type'] = 'ssl'
|
||
item['push'] = self.__push_model
|
||
item['title'] = 'Website SSL Expiration Reminder'
|
||
item['helps'] = ['SSL expiration reminders are sent only once a day']
|
||
data.append(item)
|
||
|
||
#网站到期提醒
|
||
item = self.__push.format_push_data(push = ['dingding','weixin','mail'])
|
||
item['cycle'] = 15
|
||
item['type'] = 'site_endtime'
|
||
item['title'] = 'Website Expiration Reminder'
|
||
item['helps'] = ['Site expiration reminders are sent only once a day']
|
||
data.append(item)
|
||
|
||
for data_item in data:
|
||
if stype == data_item['type']:
|
||
return data_item
|
||
return data
|
||
|
||
|
||
def get_push_cycle(self,data):
|
||
"""
|
||
@获取执行周期
|
||
"""
|
||
result = {}
|
||
for skey in data:
|
||
result[skey] = data[skey]
|
||
|
||
m_cycle =[]
|
||
m_type = data[skey]['type']
|
||
if m_type in ['endtime','ssl','site_endtime']:
|
||
m_cycle.append('1 time per day when {} days remain'.format(data[skey]['cycle']))
|
||
|
||
if len(m_cycle) > 0:
|
||
result[skey]['m_cycle'] = ''.join(m_cycle)
|
||
return result
|
||
|
||
def get_server_status(self, server_name):
|
||
status = self.check_run(server_name)
|
||
if status:
|
||
return 1
|
||
return 0
|
||
|
||
# 检测指定进程是否存活
|
||
|
||
def checkProcess(self, pid):
|
||
try:
|
||
if not self.pids: self.pids = psutil.pids()
|
||
if int(pid) in self.pids: return True
|
||
return False
|
||
except Exception as e:
|
||
return False
|
||
|
||
# 名取PID
|
||
|
||
def getPid(self, pname):
|
||
try:
|
||
if not self.pids: self.pids = psutil.pids()
|
||
for pid in self.pids:
|
||
if psutil.Process(pid).name() == pname: return True
|
||
return False
|
||
except:
|
||
return True
|
||
|
||
# 检查是否启动
|
||
|
||
def check_run(self, name):
|
||
if name == "php-fpm":
|
||
status = False
|
||
base_path = "/www/server/php"
|
||
if not os.path.exists(base_path):
|
||
return status
|
||
for p in os.listdir(base_path):
|
||
pid_file = os.path.join(base_path, p, "var/run/php-fpm.pid")
|
||
if os.path.exists(pid_file):
|
||
php_pid = int(public.readFile(pid_file))
|
||
status = self.checkProcess(php_pid)
|
||
if status:
|
||
return status
|
||
return status
|
||
elif name == 'nginx':
|
||
status = False
|
||
if os.path.exists('/etc/init.d/nginx'):
|
||
pidf = '/www/server/nginx/logs/nginx.pid'
|
||
if os.path.exists(pidf):
|
||
try:
|
||
pid = public.readFile(pidf)
|
||
status = self.checkProcess(pid)
|
||
except:
|
||
pass
|
||
return status
|
||
elif name == 'apache':
|
||
status = False
|
||
if os.path.exists('/etc/init.d/httpd'):
|
||
pidf = '/www/server/apache/logs/httpd.pid'
|
||
if os.path.exists(pidf):
|
||
pid = public.readFile(pidf)
|
||
status = self.checkProcess(pid)
|
||
#public.print_log(status)
|
||
return status
|
||
elif name == 'mysql':
|
||
res = public.ExecShell("service mysqld status")
|
||
if res and not re.search(r"not\s+running", res[0]):
|
||
return True
|
||
return False
|
||
elif name == 'tomcat':
|
||
status = False
|
||
if os.path.exists('/www/server/tomcat/logs/catalina-daemon.pid'):
|
||
if self.getPid('jsvc'): status = True
|
||
if not status:
|
||
if self.getPid('java'): status = True
|
||
return status
|
||
elif name == 'pure-ftpd':
|
||
pidf = '/var/run/pure-ftpd.pid'
|
||
status = False
|
||
if os.path.exists(pidf):
|
||
pid = public.readFile(pidf)
|
||
status = self.checkProcess(pid)
|
||
return status
|
||
elif name == 'redis':
|
||
status = False
|
||
pidf = '/www/server/redis/redis.pid'
|
||
if os.path.exists(pidf):
|
||
pid = public.readFile(pidf)
|
||
status = self.checkProcess(pid)
|
||
return status
|
||
elif name == 'memcached':
|
||
status = False
|
||
pidf = '/var/run/memcached.pid'
|
||
if os.path.exists(pidf):
|
||
pid = public.readFile(pidf)
|
||
status = self.checkProcess(pid)
|
||
return status
|
||
return True
|
||
|
||
def clear_push_count(self,id):
|
||
"""
|
||
@清除推送次数
|
||
"""
|
||
try:
|
||
#编辑后清理推送次数标记
|
||
tip_file = '{}/data/push/tips/{}'.format(public.get_panel_path(),id)
|
||
if os.path.exists(tip_file):
|
||
os.remove(tip_file)
|
||
except:pass
|
||
|
||
|
||
def set_push_config(self,get):
|
||
"""
|
||
@name 设置推送配置
|
||
"""
|
||
id = get.id
|
||
module = get.name
|
||
pdata = json.loads(get.data)
|
||
|
||
data = self.__push._get_conf()
|
||
if not module in data:data[module] = {}
|
||
|
||
self.clear_push_count(id)
|
||
|
||
is_create = True
|
||
if pdata['type'] in ['ssl']:
|
||
for x in data[module]:
|
||
item = data[module][x]
|
||
if item['type'] == pdata['type'] and item['project'] == pdata['project']:
|
||
is_create = False
|
||
data[module][x] = pdata
|
||
elif pdata['type'] in ['panel_login']:
|
||
p_module = pdata['module'].split(',')
|
||
if len(p_module) > 1:
|
||
return public.returnMsg(False, public.lang("The panel login alarm only supports one alarm mode."))
|
||
|
||
if not pdata['status']:
|
||
return public.returnMsg(False, public.lang("It does not support suspending the panel login alarm, if you need to suspend, please delete it directly."))
|
||
|
||
import config
|
||
c_obj = config.config()
|
||
|
||
args = public.dict_obj()
|
||
args.type = pdata['module'].strip()
|
||
|
||
res = c_obj.set_login_send(args)
|
||
if not res['status']: return res
|
||
|
||
elif pdata['type'] in ['ssh_login']:
|
||
|
||
p_module = pdata['module'].split(',')
|
||
if len(p_module) > 1:
|
||
return public.returnMsg(False, public.lang("SSH login alarm only supports one alarm mode."))
|
||
|
||
if not pdata['status']:
|
||
return public.returnMsg(False, public.lang("It does not support suspending the SSH login alarm. If you need to suspend, please delete it directly."))
|
||
|
||
import ssh_security
|
||
c_obj = ssh_security.ssh_security()
|
||
|
||
args = public.dict_obj()
|
||
args.type = pdata['module'].strip()
|
||
|
||
res = c_obj.set_login_send(args)
|
||
if not res['status']: return res
|
||
|
||
elif pdata['type'] in ['ssh_login_error']:
|
||
|
||
res = public.get_ips_area(['127.0.0.1'])
|
||
if 'status' in res:
|
||
return res
|
||
|
||
elif pdata['type'] in ['panel_safe_push']:
|
||
pdata['interval'] = 30
|
||
|
||
if is_create: data[module][id] = pdata
|
||
public.set_module_logs('site_push_ssl','set_push_config',1)
|
||
return data
|
||
|
||
def del_push_config(self,get):
|
||
"""
|
||
@name 删除推送记录
|
||
@param get
|
||
id = 告警记录标识
|
||
module = 告警模块, site_push,panel_push
|
||
"""
|
||
id = get.id
|
||
module = get.name
|
||
self.clear_push_count(id)
|
||
|
||
data = self.__push.get_push_list(get)
|
||
info = data[module][id]
|
||
if id in ['panel_login']:
|
||
|
||
c_obj = config.config()
|
||
args = public.dict_obj()
|
||
args.type = info['module'].strip()
|
||
res = c_obj.clear_login_send(args)
|
||
# public.print_log(json.dumps(res))
|
||
if not res['status']: return res
|
||
elif id in ['ssh_login']:
|
||
|
||
import ssh_security
|
||
c_obj = ssh_security.ssh_security()
|
||
res = c_obj.clear_login_send(None)
|
||
|
||
if not res['status']: return res
|
||
|
||
try:
|
||
data = self.__push._get_conf()
|
||
del data[module][id]
|
||
public.writeFile(self.__conf_path,json.dumps(data))
|
||
except: pass
|
||
return public.returnMsg(True, public.lang("successfully deleted."))
|
||
|
||
|
||
#-----------------------------------------------------------end 添加推送 ------------------------------------------------------
|
||
def get_unixtime(self,data,format = "%Y-%m-%d %H:%M:%S"):
|
||
import time
|
||
timeArray = time.strptime(data,format )
|
||
timeStamp = int(time.mktime(timeArray))
|
||
return timeStamp
|
||
|
||
def get_site_ssl_info(self,webType,siteName,project_type = ''):
|
||
"""
|
||
@获取SSL详细信息
|
||
@webType string web类型 /nginx /apache /iis
|
||
@siteName string 站点名称
|
||
"""
|
||
result = False
|
||
if webType in ['nginx','apache']:
|
||
path = public.get_setup_path()
|
||
if public.get_os('windows'):
|
||
conf_file = '{}/{}/conf/vhost/{}.conf'.format(path,webType,siteName)
|
||
ssl_file = '{}/{}/conf/ssl/{}/fullchain.pem'.format(path,webType,siteName)
|
||
else:
|
||
conf_file ='{}/vhost/{}/{}{}.conf'.format(public.get_panel_path(),webType,project_type,siteName)
|
||
ssl_file = '{}/vhost/cert/{}/fullchain.pem'.format(public.get_panel_path(),siteName)
|
||
|
||
conf = public.readFile(conf_file)
|
||
|
||
if not conf:
|
||
return result
|
||
|
||
if conf.find('SSLCertificateFile') >=0 or conf.find('ssl_certificate') >= 0:
|
||
|
||
if os.path.exists(ssl_file):
|
||
cert_data = public.get_cert_data(ssl_file)
|
||
return cert_data
|
||
return result
|
||
|
||
|
||
def get_total(self):
|
||
return True
|
||
|
||
def get_ssl_push_data(self,data):
|
||
"""
|
||
@name 获取SSL推送数据
|
||
@param data
|
||
type = ssl
|
||
project = 项目名称
|
||
siteName = 站点名称
|
||
"""
|
||
|
||
if time.time() < data['index'] + 86400:
|
||
return public.returnMsg(False, public.lang("SSL is pushed once a day, skipped."))
|
||
|
||
push_keys = []
|
||
ssl_list = []
|
||
sql = public.M('sites')
|
||
if data['project'] == 'all':
|
||
#过滤单独设置提醒的网站
|
||
n_list = []
|
||
try:
|
||
push_list = self.__push._get_conf()['site_push']
|
||
for skey in push_list:
|
||
p_name = push_list[skey]['project']
|
||
if p_name != 'all': n_list.append(p_name)
|
||
except : pass
|
||
|
||
#所有正常网站
|
||
web_list = sql.where('status=1',()).select()
|
||
for web in web_list:
|
||
project_type = ''
|
||
if web['name'] in n_list: continue
|
||
if web['name'] in data['tips_list']: continue
|
||
|
||
if not web['project_type'] in ['PHP']:
|
||
project_type = web['project_type'].lower() + '_'
|
||
|
||
nlist = []
|
||
info = self.__check_endtime(web['name'],data['cycle'],project_type)
|
||
if type(info) != list:
|
||
nlist.append(info)
|
||
else:
|
||
nlist = info
|
||
|
||
for info in nlist:
|
||
if not info: continue
|
||
info['siteName'] = web['name']
|
||
push_keys.append(web['name'])
|
||
ssl_list.append(info)
|
||
else:
|
||
project_type = ''
|
||
find = sql.where('name=? and status=1',(data['project'],)).find()
|
||
if not find: return public.returnMsg(False, public.lang("no site available."))
|
||
|
||
if not find['project_type'] in ['PHP']:
|
||
project_type = find['project_type'].lower() + '_'
|
||
|
||
nlist = []
|
||
info = self.__check_endtime(find['name'],data['cycle'],project_type)
|
||
if type(info) != list:
|
||
nlist.append(info)
|
||
else:
|
||
nlist = info
|
||
|
||
for info in nlist:
|
||
if not info: continue
|
||
info['siteName'] = find['name']
|
||
ssl_list.append(info)
|
||
|
||
return self.__get_ssl_result(data,ssl_list,push_keys)
|
||
|
||
def get_panel_update_data(self,data):
|
||
"""
|
||
@name 获取面板更新推送
|
||
@param push_keys array 推送次数缓存key
|
||
"""
|
||
stime = time.time()
|
||
result = {'index': stime ,'push_keys':[data['id']]}
|
||
|
||
#面板更新提醒
|
||
if stime < data['index'] + 86400:
|
||
return public.returnMsg(False, public.lang("push once a day, skip."))
|
||
|
||
if public.is_self_hosted():
|
||
return public.returnMsg(False, public.lang("Panel update push is disabled in self-hosted mode."))
|
||
|
||
s_url = '{}/api/panel/updateLinuxEn'
|
||
if public.get_os('windows'): s_url = '{}/api/wpanel/updateWindows'
|
||
s_url = s_url.format(public.OfficialApiBase())
|
||
|
||
try:
|
||
res = json.loads(public.httpPost(s_url,{}))
|
||
if not res: return public.returnMsg(False, public.lang("Failed to get update information."))
|
||
except:pass
|
||
|
||
n_ver = res['version']
|
||
if res['is_beta']:
|
||
n_ver = res['beta']['version']
|
||
|
||
old_ver = public.get_cache_func(data['type'])['data']
|
||
if not old_ver:
|
||
public.set_cache_func(data['type'],n_ver)
|
||
else:
|
||
if old_ver == n_ver:
|
||
#处理推送次数逻辑
|
||
if data['id'] in data['tips_list']:
|
||
print('Notifications exceeded, skip.')
|
||
return result
|
||
else:
|
||
#清除缓存
|
||
data['tips_list'] = []
|
||
try:
|
||
tips_path = '{}/data/push/tips/{}'.format(public.get_panel_path(),data['id'])
|
||
os.remove(tips_path)
|
||
print('New version found, recount notifications.')
|
||
except:pass
|
||
public.set_cache_func(data['type'],n_ver)
|
||
|
||
if public.version() != n_ver:
|
||
for m_module in data['module'].split(','):
|
||
if m_module == 'sms': continue
|
||
|
||
s_list = ["> Notification Type: Panel Version Update",">current version:{} ".format(public.version()),">The latest version of:{}".format(n_ver)]
|
||
sdata = public.get_push_info('Panel Update Reminder',s_list)
|
||
result[m_module] = sdata
|
||
|
||
return result
|
||
|
||
def get_panel_safe_push(self,data,result):
|
||
s_list = []
|
||
#面板登录用户安全
|
||
t_add,t_del,total = self.get_records_calc('login_user_safe',public.M('users'))
|
||
if t_add > 0 or t_del > 0:
|
||
s_list.append(">Login user change:<font color=#ff0000> total {}, add {}, delete {}</font>.".format(total,t_add,t_del))
|
||
|
||
#面板日志发生删除
|
||
t_add,t_del,total = self.get_records_calc('panel_logs_safe',public.M('logs'),1)
|
||
if t_del > 0:
|
||
s_list.append(">The panel log is deleted, the number of deleted items:<font color=#ff0000>{} </font>".format(t_del))
|
||
|
||
debug_str = 'Disable'
|
||
debug_status = 'False'
|
||
#面板开启开发者模式告警
|
||
if os.path.exists('{}/data/debug.pl'.format(public.get_panel_path())):
|
||
debug_status = 'True'
|
||
debug_str = 'Enable'
|
||
|
||
skey = 'panel_debug_safe'
|
||
tmp = public.get_cache_func(skey)['data']
|
||
if not tmp:
|
||
public.set_cache_func(skey,debug_status)
|
||
else:
|
||
if str(debug_status) != tmp:
|
||
s_list.append(">Panel developer mode changed, current status:{}".format(debug_str))
|
||
public.set_cache_func(skey,debug_status)
|
||
|
||
# #面板开启api告警
|
||
# api_str = 'False'
|
||
# s_path = '{}/config/api.json'.format(public.get_panel_path())
|
||
# if os.path.exists(s_path):
|
||
# api_str = public.readFile(s_path).strip()
|
||
# if not api_str: api_str = 'False'
|
||
|
||
# api_str = public.md5(api_str)
|
||
# skey = 'panel_api_safe'
|
||
# tmp = public.get_cache_func(skey)['data']
|
||
# if not tmp:
|
||
# public.set_cache_func(skey,api_str)
|
||
# else:
|
||
# if api_str != tmp:
|
||
# s_list.append(">面板API配置发生改变,请及时确认是否本人操作.")
|
||
# public.set_cache_func(skey,api_str)
|
||
|
||
|
||
#面板用户名和密码发生变更
|
||
find = public.M('users').where('id=?',(1,)).find()
|
||
|
||
if find:
|
||
skey = 'panel_user_change_safe'
|
||
user_str = public.md5(find['username']) + '|' + public.md5(find['password'])
|
||
tmp = public.get_cache_func(skey)['data']
|
||
if not tmp:
|
||
public.set_cache_func(skey,user_str)
|
||
else:
|
||
if user_str != tmp:
|
||
s_list.append(">YakPanel login account or password changed")
|
||
public.set_cache_func(skey,user_str)
|
||
|
||
|
||
if len(s_list) > 0:
|
||
sdata = public.get_push_info('YakPanel security warning',s_list)
|
||
for m_module in data['module'].split(','):
|
||
if m_module == 'sms': continue
|
||
result[m_module] = sdata
|
||
|
||
return result
|
||
|
||
def get_push_data(self,data,total):
|
||
"""
|
||
@检测推送数据
|
||
@data dict 推送数据
|
||
title:标题
|
||
project:项目
|
||
type:类型 ssl:证书提醒
|
||
cycle:周期 天、小时
|
||
keys:检测键值
|
||
"""
|
||
stime = time.time()
|
||
if not 'tips_list' in data: data['tips_list'] = []
|
||
if not 'project' in data: data['project'] = ''
|
||
|
||
#优先处理面板更新
|
||
if data['type'] in ['panel_update']:
|
||
return self.get_panel_update_data(data)
|
||
|
||
result = {'index': stime ,'push_keys':[data['id']]}
|
||
if data['project']:
|
||
result['push_keys'] = [data['project']]
|
||
|
||
#检测推送次数,超过次数不再推送
|
||
if data['project'] in data['tips_list'] or data['id'] in data['tips_list']:
|
||
return result
|
||
|
||
if data['type'] in ['ssl']:
|
||
return self.get_ssl_push_data(data)
|
||
|
||
elif data['type'] in ['site_endtime']:
|
||
result['push_keys'] = []
|
||
|
||
if stime < data['index'] + 86400:
|
||
return public.returnMsg(False, public.lang("push once a day, skip."))
|
||
|
||
mEdate = public.format_date(format='%Y-%m-%d',times = stime + 86400 * int(data['cycle']))
|
||
web_list = public.M('sites').where('edate>? AND edate<? AND (status=? OR status=?)',('0000-00-00',mEdate,1,u'Running')).field('id,name,edate').select()
|
||
|
||
if len(web_list) > 0:
|
||
for m_module in data['module'].split(','):
|
||
if m_module == 'sms': continue
|
||
|
||
s_list = ['>Expiring:<font color=#ff0000>{} website</font>'.format(len(web_list))]
|
||
for x in web_list:
|
||
if x['name'] in data['tips_list']: continue
|
||
result['push_keys'].append(x['name'])
|
||
|
||
s_list.append(">Website: {} Expires: {}".format(x['name'],x['edate']))
|
||
|
||
sdata = public.get_push_info('YakPanel Website Expiration Reminder',s_list)
|
||
result[m_module] = sdata
|
||
return result
|
||
|
||
elif data['type'] in ['panel_pwd_endtime']:
|
||
if stime < data['index'] + 86400:
|
||
return public.returnMsg(False, public.lang("push once a day, skip."))
|
||
|
||
import config
|
||
c_obj = config.config()
|
||
res = c_obj.get_password_config(None)
|
||
|
||
if res['expire'] > 0 and res['expire_day'] < data['cycle']:
|
||
for m_module in data['module'].split(','):
|
||
if m_module == 'sms': continue
|
||
|
||
s_list = [">Alarm type: Login password is about to expire",">Days remaining: <font color=#ff0000>{} days</font>".format(res['expire_day'])]
|
||
sdata = public.get_push_info('YakPanel password expiration reminder',s_list)
|
||
result[m_module] = sdata
|
||
return result
|
||
elif data['type'] in ['clear_bash_history']:
|
||
stime = time.time()
|
||
|
||
result = {'index': stime}
|
||
|
||
elif data['type'] in ['panel_bind_user_change']:
|
||
#面板绑定帐号发生变更
|
||
uinfo = public.get_user_info()
|
||
|
||
user_str = public.md5(uinfo['username'])
|
||
old_str = public.get_cache_func(data['type'])['data']
|
||
if not old_str:
|
||
public.set_cache_func(data['type'],user_str)
|
||
else:
|
||
if user_str != old_str:
|
||
|
||
for m_module in data['module'].split(','):
|
||
if m_module == 'sms': continue
|
||
|
||
s_list = [">Alarm type: panel binding account change",">Currently bound account:{}****{}".format(uinfo['username'][:3],uinfo['username'][-4:])]
|
||
sdata = public.get_push_info('Panel binding account change reminder',s_list)
|
||
result[m_module] = sdata
|
||
|
||
public.set_cache_func(data['type'],user_str)
|
||
return result
|
||
|
||
elif data['type'] in ['panel_safe_push']:
|
||
return self.get_panel_safe_push(data,result)
|
||
|
||
elif data['type'] in ['panel_oneav_push']:
|
||
#微步在线木马扫描提醒
|
||
sfile = '{}/plugin/oneav/oneav_main.py'.format(public.get_panel_path())
|
||
if not os.path.exists(sfile): return
|
||
|
||
_obj = public.get_script_object(sfile)
|
||
_main = getattr(_obj,'oneav_main',None)
|
||
if not _main: return
|
||
|
||
args = public.dict_obj()
|
||
args.p = 1
|
||
args.count = 1000
|
||
|
||
f_list = []
|
||
s_day = public.getDate(format='%Y-%m-%d')
|
||
|
||
for line in _main().get_logs(args):
|
||
|
||
#未检测到当天日志,跳出
|
||
if public.format_date(times=line['time']).find(s_day) == -1:
|
||
break
|
||
if line['file'] in f_list: continue
|
||
|
||
f_list.append(line['file'])
|
||
|
||
if not f_list: return
|
||
|
||
for m_module in data['module'].split(','):
|
||
if m_module == 'sms': continue
|
||
|
||
s_list = [">alert type:Trojan detects alarms",">Content of notification: <font color=#ff0000> Found suspected Trojan files {}</font>".format(len(f_list)),">listed files:[{}]".format('、'.join(f_list))]
|
||
sdata = public.get_push_info('YakPanel trojan detects alarms',s_list)
|
||
result[m_module] = sdata
|
||
return result
|
||
|
||
# 登录失败次数
|
||
elif data['type'] in ['ssh_login_error']:
|
||
import PluginLoader
|
||
|
||
args = public.dict_obj()
|
||
args.model_index = 'safe'
|
||
args.count = data['count']
|
||
args.p = 1
|
||
res = PluginLoader.module_run("syslog","get_ssh_error",args)
|
||
if 'status' in res:
|
||
return
|
||
|
||
if type(res) == list:
|
||
last_info = res[data['count'] -1]
|
||
if public.to_date(times=last_info['time']) >= time.time() - data['cycle'] * 60:
|
||
for m_module in data['module'].split(','):
|
||
if m_module == 'sms': continue
|
||
|
||
s_list = [">Notification type: SSH login failure alarm",">Alarm content: <font color=#ff0000>login failed more than {} times within {} minutes</font> ".format(data['cycle'],data['count'])]
|
||
sdata = public.get_push_info('SSH login failure alarm',s_list)
|
||
result[m_module] = sdata
|
||
return result
|
||
|
||
elif data['type'] in ['services']:
|
||
ser_name = data['project']
|
||
|
||
status = self.get_server_status(ser_name)
|
||
if status > 0:
|
||
return public.returnMsg(False, public.lang("normal status,Skip."))
|
||
else:
|
||
if status == 0:
|
||
return self.__get_service_result(data)
|
||
return public.returnMsg(False, public.lang("service not installed,Skip."))
|
||
|
||
return public.returnMsg(False, public.lang("Threshold not reached,Skip."))
|
||
|
||
|
||
def get_records_calc(self,skey,table,stype = 0):
|
||
'''
|
||
@name 获取指定表数据是否发生改变
|
||
@param skey string 缓存key
|
||
@param table db 表对象
|
||
@param stype int 0:计算总条数 1:只计算删除
|
||
@return array
|
||
total int 总数
|
||
|
||
'''
|
||
total_add = 0
|
||
total_del = 0
|
||
|
||
#获取当前总数和最大索引值
|
||
u_count = table.count()
|
||
u_max = table.order('id desc').getField('id')
|
||
|
||
n_data = {'count': u_count,'max': u_max}
|
||
tmp = public.get_cache_func(skey)['data']
|
||
if not tmp:
|
||
public.set_cache_func(skey,n_data)
|
||
else:
|
||
n_data = tmp
|
||
|
||
#检测上一次记录条数是否被删除
|
||
pre_count = table.where('id<=?',(n_data['max'])).count()
|
||
if stype == 1:
|
||
if pre_count < n_data['count']: #有数据被删除,记录被删条数
|
||
total_del += n_data['count'] - pre_count
|
||
|
||
n_count = u_max - pre_count #上次记录后新增的条数
|
||
n_idx = u_max - n_data['max'] #上次记录后新增的索引差
|
||
if n_count < n_idx:
|
||
total_del += n_idx - n_count
|
||
else:
|
||
|
||
if pre_count < n_data['count']: #有数据被删除,记录被删条数
|
||
total_del += n_data['count'] - pre_count
|
||
elif pre_count > n_data['count']:
|
||
total_add += pre_count - n_data['count']
|
||
|
||
t1_del = 0
|
||
t1_add = 0
|
||
n_count = u_count - pre_count #上次记录后新增的条数
|
||
|
||
if u_max > n_data['max']:
|
||
n_idx = u_max - n_data['max'] #上次记录后新增的索引差
|
||
if n_count < n_idx: t1_del = n_idx - n_count
|
||
|
||
#新纪录除开删除,全部计算为新增
|
||
t1_add = n_count - t1_del
|
||
if t1_add > 0: total_add += t1_add
|
||
|
||
total_del += t1_del
|
||
|
||
public.set_cache_func(skey,{'count': u_count,'max': u_max})
|
||
return total_add,total_del,u_count
|
||
|
||
def __check_endtime(self,siteName,cycle,project_type = ''):
|
||
"""
|
||
@name 检测到期时间
|
||
@param siteName str 网站名称
|
||
@param cycle int 提前提醒天数
|
||
@param project_type str 网站类型
|
||
"""
|
||
info = self.get_site_ssl_info(public.get_webserver(),siteName,project_type)
|
||
if info:
|
||
endtime = self.get_unixtime(info['notAfter'],'%Y-%m-%d')
|
||
day = int((endtime - time.time()) / 86400)
|
||
if day <= cycle: return info
|
||
|
||
return False
|
||
|
||
def __get_ssl_result(self,data,clist,push_keys = []):
|
||
"""
|
||
@ssl到期返回
|
||
@data dict 推送数据
|
||
@clist list 证书列表
|
||
@return dict
|
||
"""
|
||
if len(clist) == 0:
|
||
return public.returnMsg(False, public.lang("Expired certificate not found, skipping."))
|
||
|
||
result = {'index':time.time(),'push_keys':push_keys }
|
||
for m_module in data['module'].split(','):
|
||
if m_module in self.__push_model:
|
||
|
||
sdata = self.__push.format_msg_data()
|
||
if m_module in ['sms']:
|
||
|
||
sdata['sm_type'] = 'ssl_end|YakPanel SSL Expiration Reminder'
|
||
sdata['sm_args'] = public.check_sms_argv({
|
||
'name':public.get_push_address(),
|
||
'website':public.push_argv(clist[0]["siteName"]),
|
||
'time':clist[0]["notAfter"],
|
||
'total':len(clist)
|
||
})
|
||
else:
|
||
s_list = ['>Expiring soon: <font color=#ff0000>{} copies</font>'.format(len(clist))]
|
||
for x in clist:
|
||
s_list.append(">Website: {} Expires: {}".format(x['siteName'],x['notAfter']))
|
||
|
||
sdata = public.get_push_info('YakPanel SSL expiration reminder',s_list)
|
||
|
||
result[m_module] = sdata
|
||
return result
|
||
|
||
# 服务停止返回
|
||
def __get_service_result(self, data):
|
||
s_idx = int(time.time())
|
||
if s_idx < data['index'] + data['interval']:
|
||
return public.returnMsg(False, public.lang("Interval not reached,Skip."))
|
||
|
||
result = {'index': s_idx}
|
||
|
||
for m_module in data['module'].split(','):
|
||
result[m_module] = self.__push.format_msg_data()
|
||
|
||
if m_module in ['dingding', 'weixin', 'mail', 'wx_account', 'feishu']:
|
||
s_list = [
|
||
">Service type:" + data["project"],
|
||
">Service Status: Stopped"]
|
||
sdata = public.get_push_info('service stop warning', s_list)
|
||
result[m_module] = sdata
|
||
|
||
elif m_module in ['sms']:
|
||
result[m_module]['sm_type'] = 'servcies'
|
||
result[m_module]['sm_args'] = {'name': '{}'.format(public.GetConfigValue('title')),
|
||
'product': data["project"], 'product1': data["project"]}
|
||
|
||
return result
|