Initial YakPanel commit
This commit is contained in:
313
class/push/tamper_push.py
Normal file
313
class/push/tamper_push.py
Normal file
@@ -0,0 +1,313 @@
|
||||
#coding: utf-8
|
||||
# +-------------------------------------------------------------------
|
||||
# | YakPanel
|
||||
# +-------------------------------------------------------------------
|
||||
# | Copyright (c) 2015-2020 YakPanel(https://www.yakpanel.com) All rights reserved.
|
||||
# +-------------------------------------------------------------------
|
||||
# | Author: baozi <baozi@yakpanel.com>
|
||||
# | Author: baozi
|
||||
# +-------------------------------------------------------------------
|
||||
import sys,os,re,json
|
||||
|
||||
import public,panelPush, time
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
try:
|
||||
from YakPanel import cache
|
||||
except :
|
||||
from cachelib import SimpleCache
|
||||
cache = SimpleCache()
|
||||
|
||||
class base_push:
|
||||
|
||||
# 版本信息 目前无作用
|
||||
def get_version_info(self, get=None):
|
||||
raise NotImplementedError
|
||||
|
||||
# 格式化返回执行周期, 目前无作用
|
||||
def get_push_cycle(self, data: dict):
|
||||
return data
|
||||
|
||||
# 获取模块推送参数
|
||||
def get_module_config(self, get: public.dict_obj):
|
||||
raise NotImplementedError
|
||||
|
||||
# 获取模块配置项
|
||||
def get_push_config(self, get: public.dict_obj):
|
||||
# 其实就是配置信息,没有也会从全局配置文件push.json中读取
|
||||
raise NotImplementedError
|
||||
|
||||
# 写入推送配置文件
|
||||
def set_push_config(self, get: public.dict_obj):
|
||||
raise NotImplementedError
|
||||
|
||||
# 删除推送配置
|
||||
def del_push_config(self, get: public.dict_obj):
|
||||
# 从配置中删除信息,并做一些您想做的事,如记日志
|
||||
raise NotImplementedError
|
||||
|
||||
# 无意义???
|
||||
def get_total(self):
|
||||
return True
|
||||
|
||||
# 检查并获取推送消息,返回空时,不做推送, 传入的data是配置项
|
||||
def get_push_data(self, data, total):
|
||||
# data 内容
|
||||
# index : 时间戳 time.time()
|
||||
# 消息 以类型为key, 以内容为value, 内容中包含title 和msg
|
||||
# push_keys: 列表,发送了信息的推送任务的id,用来验证推送任务次数() 意义不大
|
||||
raise NotImplementedError
|
||||
|
||||
class tamper_push(base_push):
|
||||
__tamper_path = "{}/tamper".format(public.get_setup_path())
|
||||
__total_path = "{}/total/total.json".format(__tamper_path)
|
||||
__config_file = "{}/tamper.conf".format(__tamper_path)
|
||||
__push_conf = "{}/class/push/push.json".format(public.get_panel_path())
|
||||
__logs_path = "{}/logs".format(__tamper_path)
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.__push = panelPush.panelPush()
|
||||
try:
|
||||
config = public.readFile(self.__config_file)
|
||||
config_dict = json.loads(config)
|
||||
self.__config = {}
|
||||
for i in config_dict["paths"]:
|
||||
self.__config[i["pid"]] = i
|
||||
except:
|
||||
self.__config = None
|
||||
|
||||
|
||||
# 版本信息 目前无作用
|
||||
def get_version_info(self, get=None):
|
||||
data = {}
|
||||
data['ps'] = 'Tamper-proof for Enterprise'
|
||||
data['version'] = '1.0'
|
||||
data['date'] = '2023-03-24'
|
||||
data['author'] = 'YakPanel'
|
||||
data['help'] = 'http://www.yakpanel.com/bbs'
|
||||
return data
|
||||
|
||||
# 获取模块推送参数
|
||||
def get_module_config(self, get: public.dict_obj):
|
||||
data = []
|
||||
item = self.__push.format_push_data(push = ["mail",'dingding','weixin',"feishu", "wx_account", "tg"], project = 'tamper',type = '')
|
||||
item['cycle'] = 30
|
||||
item['title'] = 'Tamper-proof for Enterprise'
|
||||
data.append(item)
|
||||
return data
|
||||
|
||||
|
||||
# 获取模块配置项
|
||||
def get_push_config(self, get: public.dict_obj):
|
||||
id = get.id
|
||||
# 其实就是配置信息,没有也会从全局配置文件push.json中读取
|
||||
push_list = self.__push._get_conf()
|
||||
|
||||
if not id in push_list["tamper_push"]:
|
||||
res_data = public.returnMsg(False, 'The specified configuration was not found.')
|
||||
res_data['code'] = 100
|
||||
return res_data
|
||||
result = push_list["tamper_push"][id]
|
||||
return result
|
||||
|
||||
|
||||
# 写入推送配置文件
|
||||
def set_push_config(self, get: public.dict_obj):
|
||||
if self.__config is None:
|
||||
return public.returnMsg(False, public.lang('Configuration error, cannot be set, please try use the command fix: "bash /www/server/panel/plugin/tamper_core/install.sh install"')
|
||||
)
|
||||
try:
|
||||
id = int(get.id)
|
||||
if id != 0 and id not in self.__config:
|
||||
return public.returnMsg(False, public.lang("No protection directory specified"))
|
||||
except ValueError:
|
||||
return public.returnMsg(False, public.lang("No protection directory specified"))
|
||||
|
||||
pdata = json.loads(get.data)
|
||||
data = self.__push._get_conf()
|
||||
if "tamper_push" not in data: data["tamper_push"] = {}
|
||||
if not str(id) in data["tamper_push"]:
|
||||
if id != 0:
|
||||
public.WriteLog("Tamper-proof for Enterprise","Protected directory: {} set tampering alarm ".format(self.__config[id]["path"]))
|
||||
else:
|
||||
public.WriteLog("Tamper-proof for Enterprise","All directory is set, tampering alarm ")
|
||||
else:
|
||||
if id != 0:
|
||||
public.WriteLog("Tamper-proof for Enterprise","Protected directory: {} Changed alert config".format(self.__config[id]["path"]))
|
||||
else:
|
||||
public.WriteLog("Tamper-proof for Enterprise"," All directory alarm config changed")
|
||||
self._del_today_push_count(id)
|
||||
pdata["status"] = True
|
||||
pdata["pid"] = id
|
||||
pdata["project"] = "tamper_core"
|
||||
data["tamper_push"][str(id)] = pdata
|
||||
return data
|
||||
|
||||
# 删除推送配置
|
||||
def del_push_config(self, get: public.dict_obj):
|
||||
# 从配置中删除信息,并做一些您想做的事,如记日志
|
||||
id = get.id
|
||||
data = self.__push._get_conf()
|
||||
if str(id).strip() in data["tamper_push"]:
|
||||
del data["tamper_push"][id]
|
||||
public.writeFile(self.__push_conf,json.dumps(data))
|
||||
return public.returnMsg(True, public.lang("successfully deleted."))
|
||||
|
||||
# 无意义???
|
||||
def get_total(self):
|
||||
return True
|
||||
|
||||
# 检查并获取推送消息,返回空时,不做推送, 传入的data是配置项
|
||||
def get_push_data(self, data, total):
|
||||
# 返回内容
|
||||
# index : 时间戳 time.time()
|
||||
# 消息 以类型为key, 以内容为value, 内容中包含title 和msg
|
||||
# push_keys: 列表,发送了信息的推送任务的id,用来验证推送任务次数() 意义不大
|
||||
"""
|
||||
@检测推送数据
|
||||
@data dict 推送数据
|
||||
title:标题
|
||||
count:触发次数
|
||||
cycle:周期 天、小时
|
||||
keys:检测键值
|
||||
"""
|
||||
if not self._log_check(data["id"], data["cycle"], data["count"]): return None
|
||||
if data["push_count"] <= self._get_today_push_count(data["id"]):return None
|
||||
result = {'index': time.time(), }
|
||||
tamper_path = "All protected directory " if not int(data["id"]) else "Protected Directory:{}".format(self.__config[int(data["id"])]["path"])
|
||||
for m_module in data['module'].split(','):
|
||||
if m_module == 'sms': continue
|
||||
s_list = [">Notification: Tamper-proof for Enterprise alarm", ">Alarm content: <font color=#ff0000>Last {} minutes, {} has been tampered with more than {} times, and it has been successfully intercepted, please pay attention to the website situation , and deal with it in timely manner.</font> ".format(data['cycle'], tamper_path, data['count'])]
|
||||
sdata = public.get_push_info('Tamper-proof for Enterprise alarm', s_list)
|
||||
result[m_module] = sdata
|
||||
self._set_total()
|
||||
self._set_today_push_count(data["id"])
|
||||
return result
|
||||
|
||||
def _log_check(self, id, cycle, count):
|
||||
target_time = datetime.now() - timedelta(minutes=cycle)
|
||||
tday, yday = datetime.now().strftime('%Y-%m-%d'), (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d')
|
||||
files = []
|
||||
if id == "0":
|
||||
for i in self.__config.keys():
|
||||
files.append("{}/{}/{}.log".format(self.__logs_path,i,tday))
|
||||
files.append("{}/{}/{}.log".format(self.__logs_path,i,yday))
|
||||
else:
|
||||
files.append("{}/{}/{}.log".format(self.__logs_path,id,tday))
|
||||
files.append("{}/{}/{}.log".format(self.__logs_path,id,yday))
|
||||
|
||||
_count = 0
|
||||
public.print_log(files)
|
||||
_f = '%Y-%m-%d %H:%M:%S'
|
||||
for i in self._get_logs(files):
|
||||
if _count >= count:
|
||||
return True
|
||||
if datetime.strptime(i, _f) > target_time:
|
||||
_count += 1
|
||||
else:
|
||||
return _count >= count
|
||||
return _count >= count
|
||||
|
||||
def _get_logs(self, files):
|
||||
def the_generator(self):
|
||||
_buf = b""
|
||||
for fp in self._get_fp():
|
||||
is_start = True
|
||||
while is_start:
|
||||
buf = b''
|
||||
while True:
|
||||
pos = fp.tell()
|
||||
read_size = pos if pos <= 38 else 38
|
||||
fp.seek(-read_size, 1)
|
||||
_buf = fp.read(read_size) + _buf
|
||||
fp.seek(-read_size, 1)
|
||||
nl_idx = _buf.rfind(ord('\n'))
|
||||
if nl_idx == -1:
|
||||
if pos <= 38:
|
||||
buf, _buf = _buf, b''
|
||||
is_start = False
|
||||
break
|
||||
else:
|
||||
buf = _buf[nl_idx+1:]
|
||||
_buf = _buf[:nl_idx]
|
||||
break
|
||||
yield self._get_time(buf.decode("utf-8"))
|
||||
|
||||
def the_init(self,log_files):
|
||||
self.log_files = log_files
|
||||
|
||||
def the_get_fp(self):
|
||||
for i in self.log_files:
|
||||
if not os.path.exists(i): continue
|
||||
with open(i, 'rb') as fp:
|
||||
fp.seek(-1, 2)
|
||||
yield fp
|
||||
|
||||
def the_get_time(self, log: str):
|
||||
return log.split("] [", 1)[0].strip("[").strip()
|
||||
|
||||
attr = {
|
||||
"__init__": the_init,
|
||||
"_get_fp": the_get_fp,
|
||||
"__iter__": the_generator,
|
||||
"_get_time": the_get_time,
|
||||
}
|
||||
return type("LogContent", (object, ), attr)(files)
|
||||
|
||||
def _set_total(self):
|
||||
try:
|
||||
total = json.loads(public.readFile(self.__total_path))
|
||||
if "warning_msg" not in total:
|
||||
total["warning_msg"] = 1
|
||||
else:
|
||||
total["warning_msg"] += 1
|
||||
public.writeFile(self.__total_path, json.dumps(total))
|
||||
except:
|
||||
pass
|
||||
|
||||
def _get_today_push_count(self, id):
|
||||
t_day = datetime.now().strftime('%Y-%m-%d')
|
||||
today_tip = '{}/data/push/tips/tamper_today.json'.format(public.get_panel_path())
|
||||
if os.path.exists(today_tip):
|
||||
tip = json.loads(public.readFile(today_tip))
|
||||
if tip["t_day"] != t_day:
|
||||
tip = {"t_day": t_day}
|
||||
res = 0
|
||||
elif id in tip:
|
||||
res = tip[id]
|
||||
else:
|
||||
res = 0
|
||||
else:
|
||||
tip = {"t_day": t_day}
|
||||
res = 0
|
||||
|
||||
public.writeFile(today_tip, json.dumps(tip))
|
||||
setattr(self, "_tip_", tip)
|
||||
return res
|
||||
|
||||
|
||||
def _set_today_push_count(self, id):
|
||||
today_tip = '{}/data/push/tips/tamper_today.json'.format(public.get_panel_path())
|
||||
if hasattr(self, "_tip_"):
|
||||
tip = getattr(self, "_tip_")
|
||||
else:
|
||||
tip = json.loads(public.readFile(today_tip))
|
||||
if id in tip:
|
||||
tip[id] += 1
|
||||
else:
|
||||
tip[id] = 1
|
||||
|
||||
public.writeFile(today_tip, json.dumps(tip))
|
||||
|
||||
def _del_today_push_count(self, id):
|
||||
t_day = datetime.now().strftime('%Y-%m-%d')
|
||||
today_tip = '{}/data/push/tips/tamper_today.json'.format(public.get_panel_path())
|
||||
if os.path.exists(today_tip):
|
||||
tip = json.loads(public.readFile(today_tip))
|
||||
if tip["t_day"] != t_day:
|
||||
tip = {"t_day": t_day}
|
||||
elif id in tip:
|
||||
del tip[id]
|
||||
|
||||
public.writeFile(today_tip, json.dumps(tip))
|
||||
|
||||
Reference in New Issue
Block a user