Files
yakpanel-core/mod/project/ssh/base.py

160 lines
5.8 KiB
Python
Raw Normal View History

2026-04-07 02:04:22 +05:30
import json
import os
import sys
from datetime import datetime
if "/www/server/panel/class" not in sys.path:
sys.path.insert(0, "/www/server/panel/class")
os.chdir("/www/server/panel")
import public
class SSHbase:
def __init__(self):
pass
@staticmethod
def return_area(result, key):
"""
@name 格式化返回带IP归属地的数组
@param result<list> 数据数组
@param key<str> ip所在字段
@return list
"""
if not result:
return result
# 添加IP查询缓存
ip_cache_file = 'data/ip_location_cache.json'
ip_cache = {}
# 确保缓存目录存在
cache_dir = os.path.dirname(ip_cache_file)
if not os.path.exists(cache_dir):
os.makedirs(cache_dir, exist_ok=True)
# 读取IP缓存
try:
if os.path.exists(ip_cache_file):
ip_cache = json.loads(public.readFile(ip_cache_file))
except Exception as e:
public.print_log('Failed to read IP cache: {}'.format(str(e)))
ip_cache = {}
# 只查询未缓存的IP
new_ips = set()
for data in result:
ip = data.get(key)
if not ip or public.is_ipv6(ip):
continue
if ip not in ip_cache:
new_ips.add(ip)
# 批量查询新IP
for ip in new_ips:
try:
if "127.0.0" in ip:
ip_cache[ip] = {"info": "Local address (e.g. left terminal)"}
continue
ip_area = public.get_ip_location(ip)
if not ip_area:
ip_cache[ip] = {"info": "unknown area"}
continue
ip_area = ip_area.raw
country = ip_area.get("country", {})
ip_area["info"] = "{} {} {}".format(
country.get('country', 'unknown'),
country.get('province', 'unknown'),
country.get('city', 'unknown')
) if country else "unknown area"
ip_cache[ip] = ip_area
except Exception as e:
public.print_log('Query IP {} Failed: {}'.format(ip, str(e)))
ip_cache[ip] = {"info": "unknown area"}
# 只有当有新IP被查询时才更新缓存文件
if new_ips:
try:
public.writeFile(ip_cache_file, json.dumps(ip_cache))
except Exception as e:
public.print_log('Failed to update IP cache: {}'.format(str(e)))
pass
# 使用缓存数据,确保不修改原始数据
result_with_area = []
for data in result:
data_copy = data.copy() # 创建数据副本
ip = data_copy.get(key, '')
data_copy['area'] = ip_cache.get(ip, {"info": "unknown area"})
result_with_area.append(data_copy)
return result_with_area
@staticmethod
def journalctl_system():
try:
if os.path.exists('/etc/os-release'):
f = public.readFile('/etc/os-release')
f = f.split('\n')
ID = ''
VERSION_ID = 0
for line in f:
if line.startswith('VERSION_ID'):
VERSION_ID = int(line.split('=')[1].split('.')[0].strip('"'))
if line.startswith('ID'):
if ID != '': continue
ID = line.strip().split('=')[1].strip('"')
try:
ID = ID.split('.')[0]
except:
pass
if (ID.lower() == 'debian' and VERSION_ID >= 11) or (ID.lower() == 'ubuntu' and VERSION_ID >= 20):
return True
return False
except:
return False
@staticmethod
def parse_login_entry(parts, year):
"""解析登录条目"""
try:
# 判断日志格式类型
if 'T' in parts[0]: # centos7以外的格式
# 解析ISO格式时间戳
dt = datetime.fromisoformat(parts[0].replace('Z', '+00:00'))
user_index = parts.index('user') + 1 if 'user' in parts else parts.index('for') + 1
ip_index = parts.index('from') + 1
port_index = parts.index('port') + 1 if 'port' in parts else -1
else:
# 解析传统格式时间
month = parts[0]
day = parts[1]
time_str = parts[2]
# 如果月份大于当前月说明年份不对直接把year修改成1970年
if datetime.strptime("{} {}".format(month, day), "%b %d").month > datetime.now().month:
year = "1970"
dt_str = "{} {} {} {}".format(month, day, year, time_str)
dt = datetime.strptime(dt_str, "%b %d %Y %H:%M:%S")
user_index = parts.index('for') + 1 if "invalid" not in parts else -6
ip_index = parts.index('from') + 1
port_index = parts.index('port') + 1 if 'port' in parts else -1
entry = {
"timestamp": int(dt.timestamp()),
"time": dt.strftime("%Y-%m-%d %H:%M:%S"),
"type": "success" if ("Accepted" in parts) else "failed",
"status": 1 if ("Accepted" in parts) else 0,
"user": parts[user_index],
"address": parts[ip_index],
"port": parts[port_index] if port_index != -1 else "",
"deny_status": 0,
"login_type": "publickey" if "publickey" in parts else "password" # 添加登录类型
}
return entry
except Exception as e:
public.print_log(public.get_error_info())
return None