Files
yakpanel-core/class_v2/overviewV2/base.py
2026-04-07 02:04:22 +05:30

507 lines
18 KiB
Python

# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2014-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: yakpanel
# -------------------------------------------------------------------
# ------------------------------
# overview app base
# ------------------------------
import json
import os
import time
from datetime import datetime, timedelta, date
import public
public.sys_path_append("class_v2/")
COLORS = {
"red": "text-error",
"gray": "text-desc",
"green": "text-primary",
"orange": "text-warning",
}
DISPLAY = {
"sites": {
"icon": "i-dashicons:admin-site-alt3",
"desc": public.lang("Manage and monitor the status of your website")
},
"ftps": {
"icon": "i-carbon:ibm-cloud-direct-link-1-dedicated",
"desc": public.lang("Monitor FTP accounts and transfer status")
},
"databases": {
"icon": "i-carbon:data-base",
"desc": public.lang("Monitor database operation and performance metrics")
},
"security": {
"icon": "i-carbon:security",
"desc": public.lang("View the current security threats and risks of the system")
},
"monitor": {
"icon": "i-carbon:meter",
"desc": public.lang("Comprehensive resource usage monitoring overview")
},
"btwaf": {
"icon": " i-hugeicons:firewall",
"desc": public.lang("WAF firewall interception and protection details")
},
"tamper_core": {
"icon": "i-carbon:locked",
"desc": public.lang("Prevent core operation and protection status")
},
"ssh_log": {
"icon": "i-carbon:terminal",
"desc": public.lang("Monitor SSH login attempts and security status")
},
"ssl": {
"icon": "i-carbon:certificate",
"desc": public.lang("SSL certificate status")
},
"cron": {
"icon": "i-carbon:time",
"desc": public.lang("Scheduled task status")
},
"alarm_logs": {
"icon": "i-carbon:reminder",
"desc": public.lang("Real-time monitoring and alarm tasks")
},
}
# noinspection PyUnusedLocal
class OverViewBase:
__db_objs = {}
def _base(self, name: str, params_list: list) -> list:
if not params_list:
params_list = []
value_list = []
if name == "sites":
for params in params_list:
where = ""
if params["source"] != "all":
where = "LOWER(project_type)=LOWER('{}')".format(params["source"])
if where:
start_num = public.M("sites").where(where + " and status='1'", ()).count()
stop_num = public.M("sites").where(where + " and status='0'", ()).count()
else:
start_num = public.M("sites").where("status='1'", ()).count()
stop_num = public.M("sites").where("status='0'", ()).count()
value_list = [
{
"desc": public.lang("Running"),
"data": start_num,
"color": COLORS["green"]
},
{
"desc": public.lang("Stopped"),
"data": stop_num,
"color": COLORS["red"]
},
{
"desc": public.lang("ALL"),
"data": public.M("sites").where(where, ()).count(),
"color": COLORS["gray"]
}
]
elif name == "ftps":
data = public.M("ftps").count()
if not isinstance(data, int):
data = 0
value_list = [{
"desc": public.lang("Accounts"),
"data": data,
"color": COLORS["green"]
}]
elif name == "databases":
for params in params_list:
if params["source"] != "redis":
if params["source"] == "all":
data = public.M("databases").count()
else:
data = public.M("databases").where(
"LOWER(type)=LOWER(?)", (params["source"],)
).count()
else:
from databaseModelV2.redisModel import panelRedisDB
data = panelRedisDB().get_options(None).get("databases", 16)
value_list = [
{
"desc": params["name"],
"data": data,
"color": COLORS["green"]
}
]
else:
value_list = []
return value_list
def _corn(self, name: str, params_list: list) -> list:
return []
def _security(self, name: str, params_list: list) -> list:
from projectModelV2.safecloudModel import main
cloud_safe_info = main().get_pending_alarm_trend(None)
if cloud_safe_info.get("status") != 0:
return []
trend_list = public.find_value_by_key(
cloud_safe_info, "trend_list", default=[]
)
last_scan_ts = ""
if trend_list:
last_scan_ts = trend_list[-1].get("timestamp", "")
last_scan_time = time.strftime(
"%Y/%m/%d %H:%M:%S", time.localtime(last_scan_ts)
) if last_scan_ts else public.lang("Never Scanned")
try:
last_total = public.find_value_by_key(cloud_safe_info, "total", default=0)
except:
last_total = 0
return [
{
"desc": public.lang("Security Risk"),
"data": last_total,
"color": COLORS["gray"] if last_total == 0 else COLORS["red"]
},
{
"desc": public.lang("Last Scan"),
"data": last_scan_time,
"color": COLORS["gray"]
}
]
def _btwaf(self, name: str, params_list: list) -> list:
default = [
{
"desc": public.lang("Today Intercept"),
"data": 0,
"color": COLORS["orange"]
},
{},
{
"desc": public.lang("Yesterday Intercept"),
"data": 0,
"color": COLORS["orange"]
}
]
waf_db_path = "/www/server/btwaf/totla_db/totla_db.db"
if not os.path.exists(waf_db_path):
return default
today_time = int(datetime.now().replace(hour=0, minute=0, second=0, microsecond=0).timestamp())
yesterday_time = today_time - 86400
result = []
try:
today_data = public.M("totla_log").dbfile(waf_db_path).field('time').where(
"time>=?", (today_time,)
).order('id desc').count()
if not isinstance(today_data, int):
raise Exception
except Exception as e:
public.print_log("Failed to get WAF today intercept data")
today_data = 0
result.append({
"desc": public.lang("Today Intercept"),
"data": 0,
"color": COLORS["orange"]
})
result.append({})
try:
yesterday_data = public.M("totla_log").dbfile(waf_db_path).field('time').where(
"time>=? and time<=?", (yesterday_time, today_time)
).order('id desc').count()
if not isinstance(yesterday_data, int):
raise Exception
except Exception:
yesterday_data = 0
result.append({
"desc": public.lang("Yesterday Intercept"),
"data": yesterday_data,
"color": COLORS["orange"]
})
return result if result else default
def _tamper_core(self, name: str, params_list: list) -> list:
tamper_core_dir = "/www/server/tamper/total"
default = [
{
"desc": public.lang("Today Intercept"),
"data": 0,
"color": COLORS["gray"]
},
{},
{
"desc": public.lang("Yesterday Intercept"),
"data": 0,
"color": COLORS["gray"]
}
]
if not os.path.exists(tamper_core_dir):
return default
result = []
today_time = date.today()
yesterday_time = today_time - timedelta(days=1)
listdirs = os.listdir(tamper_core_dir)
if not listdirs:
return default
for p_name in os.listdir(tamper_core_dir):
dir_path = os.path.join(tamper_core_dir, str(p_name))
today_path = os.path.join(dir_path, "{}.json".format(today_time))
if os.path.isfile(today_path):
today_info = public.readFile(today_path)
today_info = json.loads(today_info)
for info in today_info.values():
result.append({
"desc": public.lang("Today Intercept"),
"data": sum(info.values()),
"color": COLORS["orange"]
})
else:
result.append({
"desc": public.lang("Today Intercept"),
"data": 0,
"color": COLORS["gray"]
})
result.append({})
yesterday_path = os.path.join(dir_path, "{}.json".format(yesterday_time))
if os.path.isfile(yesterday_path):
yesterday_info = public.readFile(yesterday_path)
yesterday_info = json.loads(yesterday_info)
for info in yesterday_info.values():
result.append({
"desc": public.lang("Yesterday Intercept"),
"data": sum(info.values()),
"color": COLORS["orange"]
})
else:
result.append({
"desc": public.lang("Yesterday Intercept"),
"data": 0,
"color": COLORS["gray"]
})
for r in result:
if int(r.get("data", 0)) > 0:
r["color"] = COLORS["orange"]
elif int(r.get("data", 0)) == 0:
r["color"] = COLORS["gray"]
return result if result else default
def _ssh_log(self, name: str, params_list: list) -> list:
try:
params_map = {
"all": "all",
"Accepted": "success",
"Failed": "error"
}
from mod.project.ssh.comMod import main
params = public.find_value_by_key(params_list, "source", default="all")
params = params_map.get(params, "all")
ssh_info = main().get_ssh_intrusion(None)
if ssh_info.get("status") != 0:
return []
ssh = ssh_info.get("message", {})
error = int(ssh.get("today_error", 0))
success = int(ssh.get("today_success", 0))
if params == "error":
return [
{
"desc": public.lang("Failed"),
"data": error,
"color": COLORS["gray"] if error == 0 else COLORS["red"]
}
]
elif params == "success":
return [
{
"desc": public.lang("Success"),
"data": success,
"color": COLORS["green"]
}
]
else:
return [
{
"desc": public.lang("Success"),
"data": success,
"color": COLORS["green"]
},
{
"desc": public.lang("Failed"),
"data": error,
"color": COLORS["gray"] if error == 0 else COLORS["red"]
},
{
"desc": public.lang("ALL"),
"data": error + success,
"color": COLORS["gray"]
}
]
except Exception:
public.print_log("Failed to get SSH log information")
return []
def _monitor(self, name: str, params_list: list) -> list:
try:
params_data = {
"pv": "SUM(pv_number) as pv",
"uv": "SUM(uv_number) as uv",
"ip": "SUM(ip_number) as ip",
"spider": "SUM(spider_count) as spider",
}
params_desc = {
"pv": public.lang("Page Views"),
"uv": public.lang("Visitors"),
"ip": public.lang("IPs"),
"spider": public.lang("Spiders"),
}
site_name = params_list[0]['source']
param = params_list[1]['source']
run_path = "{}/monitor".format(public.get_setup_path())
db_file = "{}/data/dbs/{}/{}.db".format(run_path, site_name, "request_total")
if db_file not in self.__db_objs:
if not os.path.exists(db_file) or os.path.getsize(db_file) == 0:
return [
{
"desc": site_name,
},
{},
{
"desc": f'{public.lang("Today")}',
"data": 0,
"color": COLORS["gray"]
},
{
"desc": f'{public.lang("Yesterday")}',
"data": 0,
"color": COLORS["gray"]
}
]
else:
import db
db_obj = db.Sql()
db_obj._Sql__DB_FILE = db_file
self.__db_objs[db_file] = db_obj
else:
db_obj = self.__db_objs[db_file]
now_time = datetime.now().strftime('%Y%m%d')
last_time = (datetime.now() - timedelta(days=1)).strftime('%Y%m%d')
result = [
{
"desc": site_name,
},
{},
]
for i in [now_time, last_time]:
sql = f'select {params_data[param]} from request_total where date="{i}";'
data = db_obj.table("request_total").query(sql)
try:
data = data[0][0]
if data is None:
data = 0
except:
data = 0
desc = public.lang("Today") if i == now_time else public.lang("Yesterday")
result.append(
{
"desc": f"{desc}",
"data": data,
"color": COLORS["gray"]
}
)
return result
except Exception as e:
import traceback
public.print_log(traceback.format_exc())
return []
def _alarm_logs(self, name: str, params_list: list) -> list:
today = datetime.now().strftime("%Y-%m-%d 00:00:00")
task_logs = public.M("logs").where(
"type=? AND addtime >=?", ("Alarm notification", today)
).count()
return [
{
"desc": public.lang("Today"),
"data": task_logs,
"color": COLORS["gray"] if task_logs == 0 else COLORS["orange"]
}
]
def _base_ssl(self, select: str) -> list:
from ssl_domainModelV2.model import DnsDomainSSL, Q
f_fields = ("hash", "subject", "not_after", "not_after_ts")
data = []
now = round((time.time() + 86400 * 30) * 1000)
ip_ts = round((time.time() + 86400 * 3) * 1000)
ip = public.GetLocalIp()
if select == "normal":
# 上次续签为成功, 且证书未过期
data = DnsDomainSSL.objects.filter(
Q(renew_status=1) & (
Q(subject__ne=ip, not_after_ts__gt=now) | Q(subject=ip, not_after_ts__gt=ip_ts)
)
).fields(*f_fields).as_list()
elif select == "expirin_soon":
# 上次续签为成功, 但证书即将过期
data = DnsDomainSSL.objects.filter(
Q(renew_status=1) & (
Q(subject__ne=ip, not_after_ts__lte=now) | Q(subject=ip, not_after_ts__lte=ip_ts)
)
).fields(*f_fields).as_list()
elif select == "renew_fail":
# 上次续签为失败
data = DnsDomainSSL.objects.filter(
renew_status=0
).fields(*f_fields).as_list()
data = [{**d, "tag": select} for d in data]
return data
def _ssl(self, name: str, params_list: list) -> list:
try:
from ssl_domainModelV2.model import DnsDomainSSL
expirin_soon = len(self._base_ssl("expirin_soon")) or 0
renew_fail = len(self._base_ssl("renew_fail")) or 0
return [
{
"desc": public.lang("Expirin Soon"),
"data": expirin_soon,
"color": COLORS["orange"] if expirin_soon > 0 else COLORS["gray"]
},
{
"desc": public.lang("Renew Fail"),
"data": renew_fail,
"color": COLORS["red"] if renew_fail > 0 else COLORS["gray"]
},
{
"desc": public.lang("ALL"),
"data": DnsDomainSSL.objects.all().count() or 0,
"color": COLORS["gray"]
}
]
except Exception:
import traceback
public.print_log("Failed to get SSL information: {}".format(traceback.format_exc()))
return []