Files
zsglpt/database.py
yuyx 46253337eb feat: 实现完整安全防护系统
Phase 1 - 威胁检测引擎:
- security/threat_detector.py: JNDI/SQL/XSS/路径遍历/命令注入检测
- security/constants.py: 威胁检测规则和评分常量
- 数据库表: threat_events, ip_risk_scores, user_risk_scores, ip_blacklist

Phase 2 - 风险评分与黑名单:
- security/risk_scorer.py: IP/用户风险评分引擎,支持分数衰减
- security/blacklist.py: 黑名单管理,自动封禁规则

Phase 3 - 响应策略:
- security/honeypot.py: 蜜罐响应生成器
- security/response_handler.py: 渐进式响应策略

Phase 4 - 集成:
- security/middleware.py: Flask安全中间件
- routes/admin_api/security.py: 管理后台安全仪表板API
- 36个测试用例全部通过

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-27 01:28:38 +08:00

219 lines
6.0 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.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
数据库模块(稳定 API 门面)- SQLite
P2 / O-07拆分 `database.py` 为稳定门面 + `db/` 分域实现。
约束:
- 外部仍通过 `import database` 调用(函数名/参数/返回结构保持不变)
- schema/migration 入口统一,避免 scattered ALTER TABLE
"""
from __future__ import annotations
import os
import threading
import time
from typing import Optional
import db_pool
from app_config import get_config
from db.schema import ensure_schema
from db.migrations import migrate_database as _migrate_database
from db.admin import (
admin_reset_user_password,
approve_password_reset,
clean_old_operation_logs,
create_password_reset_request,
ensure_default_admin,
get_hourly_registration_count,
get_pending_password_resets,
get_system_config_raw as _get_system_config_raw,
get_system_stats,
reject_password_reset,
update_admin_password,
update_admin_username,
update_system_config as _update_system_config,
verify_admin,
)
from db.accounts import (
create_account,
delete_account,
delete_user_accounts,
get_account,
get_account_status,
get_user_accounts,
increment_account_login_fail,
reset_account_login_status,
update_account_remark,
)
from db.announcements import (
create_announcement,
delete_announcement,
dismiss_announcement_for_user,
get_active_announcement_for_user,
get_announcement_by_id,
get_announcements,
set_announcement_active,
)
from db.email import (
get_user_by_email,
get_user_email_notify,
update_user_email,
update_user_email_notify,
)
from db.feedbacks import (
close_feedback,
create_bug_feedback,
delete_feedback,
get_bug_feedbacks,
get_feedback_by_id,
get_feedback_stats,
get_user_feedbacks,
reply_feedback,
)
from db.schedules import (
clean_old_schedule_logs,
create_schedule_execution_log,
create_user_schedule,
delete_schedule_logs,
delete_user_schedule,
get_due_user_schedules,
get_enabled_user_schedules,
get_schedule_by_id,
get_schedule_execution_logs,
get_user_all_schedule_logs,
get_user_schedules,
recompute_schedule_next_run,
toggle_user_schedule,
update_schedule_next_run,
update_schedule_execution_log,
update_schedule_last_run,
update_user_schedule,
)
from db.tasks import create_task_log, delete_old_task_logs, get_task_logs, get_task_stats, get_user_run_stats
from db.users import (
approve_user,
create_user,
delete_user,
extend_user_vip,
get_all_users,
get_pending_users,
get_user_by_id,
get_user_by_username,
get_user_stats,
get_user_vip_info,
get_vip_config,
is_user_vip,
reject_user,
remove_user_vip,
set_default_vip_days,
set_user_vip,
verify_user,
)
from db.security import record_login_context
config = get_config()
# 数据库文件路径
DB_FILE = config.DB_FILE
# 数据库版本 (用于迁移管理)
DB_VERSION = 14
# ==================== 系统配置缓存P1 / O-03 ====================
_system_config_cache_lock = threading.Lock()
_system_config_cache_value: Optional[dict] = None
_system_config_cache_loaded_at = 0.0
try:
_SYSTEM_CONFIG_CACHE_TTL_SECONDS = float(os.environ.get("SYSTEM_CONFIG_CACHE_TTL_SECONDS", "3"))
except Exception:
_SYSTEM_CONFIG_CACHE_TTL_SECONDS = 3.0
_SYSTEM_CONFIG_CACHE_TTL_SECONDS = max(0.0, _SYSTEM_CONFIG_CACHE_TTL_SECONDS)
def invalidate_system_config_cache() -> None:
global _system_config_cache_value, _system_config_cache_loaded_at
with _system_config_cache_lock:
_system_config_cache_value = None
_system_config_cache_loaded_at = 0.0
def init_database():
"""初始化数据库表结构 + 迁移(入口统一)。"""
db_pool.init_pool(DB_FILE, pool_size=config.DB_POOL_SIZE)
with db_pool.get_db() as conn:
ensure_schema(conn)
_migrate_database(conn, DB_VERSION)
ensure_default_admin()
def migrate_database():
"""数据库迁移(对外保留接口)。"""
with db_pool.get_db() as conn:
ensure_schema(conn)
_migrate_database(conn, DB_VERSION)
# ==================== 系统配置管理(缓存门面) ====================
def get_system_config():
"""获取系统配置(带进程内缓存)。"""
global _system_config_cache_value, _system_config_cache_loaded_at
now_ts = time.time()
with _system_config_cache_lock:
if _system_config_cache_value is not None:
if _SYSTEM_CONFIG_CACHE_TTL_SECONDS <= 0 or (now_ts - _system_config_cache_loaded_at) < _SYSTEM_CONFIG_CACHE_TTL_SECONDS:
return dict(_system_config_cache_value)
value = _get_system_config_raw()
with _system_config_cache_lock:
_system_config_cache_value = dict(value)
_system_config_cache_loaded_at = now_ts
return dict(value)
def update_system_config(
max_concurrent=None,
schedule_enabled=None,
schedule_time=None,
schedule_browse_type=None,
schedule_weekdays=None,
max_concurrent_per_account=None,
max_screenshot_concurrent=None,
proxy_enabled=None,
proxy_api_url=None,
proxy_expire_minutes=None,
auto_approve_enabled=None,
auto_approve_hourly_limit=None,
auto_approve_vip_days=None,
):
"""更新系统配置(写入后立即失效缓存)。"""
ok = _update_system_config(
max_concurrent=max_concurrent,
schedule_enabled=schedule_enabled,
schedule_time=schedule_time,
schedule_browse_type=schedule_browse_type,
schedule_weekdays=schedule_weekdays,
max_concurrent_per_account=max_concurrent_per_account,
max_screenshot_concurrent=max_screenshot_concurrent,
proxy_enabled=proxy_enabled,
proxy_api_url=proxy_api_url,
proxy_expire_minutes=proxy_expire_minutes,
auto_approve_enabled=auto_approve_enabled,
auto_approve_hourly_limit=auto_approve_hourly_limit,
auto_approve_vip_days=auto_approve_vip_days,
)
if ok:
invalidate_system_config_cache()
return ok