Files
yakpanel-core/mod/project/ssh/base.py
2026-04-07 02:04:22 +05:30

160 lines
5.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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