This repository has been archived on 2026-10-02. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
NeteaseUrl/auth_system/__init__.py
T
snowy-yang 70ca21974b refactor: 拆掉 auth_system 包内循环依赖,路径常量收敛到 db 单一来源
为什么:auth_system 的 11 个子模块此前构成一个强连通分量——db.py 与 backup.py
为了「动态读取路径常量」而在模块级 `import auth_system`(包自身),而包 __init__
又再导出这两个子模块的全部符号,互相指成环。

这个环当前并不崩(实测 8/8 种导入姿势全通过),它的代价是**双绑定**:
`auth_system.DB_PATH is auth_system.db.DB_PATH` 初始为 True,但只 patch 其一
另一处不跟随。于是测试不得不把 4 个路径常量**两处都 patch**
(setattr(auth,...) + setattr(db,...))——而漏 patch 的后果是静默写生产库,
commit fc7fc21 修的那次「黄金测试写进生产库」正是这么来的。

改法:让路径常量回归**模块属性单一来源**。
- db.py:删掉 `import auth_system`,内部改用本模块常量(DATA_DIR / DB_PATH /
  SECRET_KEY_PATH)。这些常量本就定义在本模块,绕道包属性纯属多余。
- backup.py:改用 `import auth_system.db as db` 做模块限定访问,路径走
  db.BACKUP_DIR / db.DB_PATH——保留动态读取能力,来源从「包属性」换成
  「db 模块」,与唯一来源一致。
  注意**不能**写成 `from . import db`:该形式在静态图里同时指向包本身与子模块,
  会把这个环重新连上(实测确实如此,SCC 从 11 降到 2 就卡住了)。
- admin_site.py:5 处 `auth.DB_PATH` / `auth.BACKUP_DIR`(auth 是包别名)同样
  改为经 db 模块访问。**这处不修就会出事**——它读的是包属性快照,而测试已改为
  patch db 模块,于是备份上传会静默落到生产 data/backups/(本次实测真的发生了,
  2 个 upload_*.db 已清理,副本留在临时目录)。
- 测试:7 个文件的 patch 目标从包属性迁到 auth_system.db.*。
- __init__.py:补注释说明这些常量在此只是 import 快照,禁止经包属性重定向。

验证:
- Tarjan 重算:非平凡强连通分量 11 → **0**(import 图已是 DAG)
- AST 全仓扫描:经包属性访问路径常量的点 **0 处残留**
- 行为:子进程内 patch auth_system.db.* 后,get_conn 连的库 / create_backup
  落盘目录 / get_secret_key 目标路径**三者全部跟随**
- 导入姿势回归 8/8 通过
- 门禁:ruff 0 · pyright 0 errors 0 warnings · pytest 175 passed
2026-09-26 14:37:58 +08:00

248 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.
# -*- coding: utf-8 -*-
"""站点认证与管理系统
提供网站级用户体系:
- 用户注册(邮箱验证码)/ 登录 / 登出 / 注册即赠下载次数(试用领取已并入注册)
- 按次计费(一首歌 = 1 次)、卡密(次数卡)充值
- 管理员后台:用户管理 / SMTP 配置 / 卡密生成 / 公告 / 日志 / 数据库备份
- 接口装饰器:login_required(强制登录 + 按次扣费)/ admin_required(仅管理员)
数据存储:SQLite(data/site.db),会话:Flask 签名 Cookie(secret_key 持久化)
"""
# 兼容门面:实现已按职责拆分到同包各子模块,此处原样再导出。
# 用 `__all__` 声明再导出(ruff F401 与 pyright 均据此认定「有意再导出」),
# 使既有调用点(auth_system.xxx / from auth_system import Y)零改动。
#
# ⚠️ 路径常量(DATA_DIR / DB_PATH / BACKUP_DIR / SECRET_KEY_PATH)在此只是
# **import 时的值快照**:它们是再导出的绑定,运行时改 auth_system.DB_PATH
# 不会影响 db / backup 的实际读写路径(那只会静默失效,且看起来"改成功了")。
# 一律不要经由包属性做重定向:
# - 测试:patch `auth_system.db.<NAME>`(唯一来源,db 与 backup 都随动)
# - 部署:设置环境变量 SITE_DATA_DIR(须在进程启动前)
# 此处保留再导出仅为不破坏既有 `auth_system.DB_PATH` 读取方(如黄金测试)。
from .backup import (
_BACKUP_ERR_TS,
_BACKUP_NAME_LOCK,
_auto_backup_loop,
_backup_is_valid_db,
_backup_thread_started,
_before_restore_hook,
backup_path,
create_backup,
delete_backup,
list_backups,
prune_backups,
register_before_restore_hook,
restore_backup,
start_auto_backup,
)
from .cards import (
delete_card,
generate_cards,
list_cards,
redeem_card,
set_card_disabled,
)
from .credits import (
add_credits,
charge_credits,
format_credits,
refund_credits,
reserve_credits,
)
from .db import (
_DB_LOCK,
BACKUP_DIR,
DATA_DIR,
DB_PATH,
DEFAULT_ADMIN_USER,
DEFAULT_REGISTER_CREDITS,
SECRET_KEY_PATH,
SESSION_KEY,
_q,
_x,
get_conn,
get_secret_key,
init_db,
)
from .geo import (
_PROVINCE_CACHE,
PROVINCE_BAN_LIMIT,
PROVINCE_WINDOW,
_is_private_ip,
query_ip_province,
record_login_location,
)
from .ledger import (
ledger_cleanup_settled,
ledger_get,
ledger_open,
ledger_recover_orphans,
ledger_rename,
ledger_settle,
ledger_supplement,
reserve_and_open,
)
from .logs import (
_LOG_WRITE_COUNTER,
add_log,
clear_logs,
query_logs,
)
from .mail import (
_CODE_EMAIL_TEMPLATES,
_CODE_FAILS,
_CODE_FAILS_MAX,
_CODE_PURPOSES,
_EMAIL_SENT_24H,
_SMTP_ENC_PREFIX,
_code_fails_trim,
_smtp_connect,
_smtp_password_decrypt,
_smtp_password_encrypt,
check_verify_code,
get_smtp_config,
restore_verify_code,
save_smtp_config,
send_email,
send_verify_code,
smtp_configured,
)
from .security import (
_PBKDF2_ITERS,
_hash,
_hash_new,
_normalize_email,
_verify_password,
)
from .settings import (
get_announcement,
get_setting,
save_announcement,
set_setting,
)
from .users import (
_last_province,
_user_public,
ban_user,
create_user,
delete_user,
device_used,
get_user_by_email,
get_user_by_id,
get_user_by_name,
list_users,
register_ip_exceeded,
reset_password,
set_user_credits,
set_user_netease_cookie,
set_user_password,
set_user_status,
unban_user,
verify_login,
)
__all__ = [
'BACKUP_DIR',
'DATA_DIR',
'DB_PATH',
'DEFAULT_ADMIN_USER',
'DEFAULT_REGISTER_CREDITS',
'PROVINCE_BAN_LIMIT',
'PROVINCE_WINDOW',
'SECRET_KEY_PATH',
'SESSION_KEY',
'_BACKUP_ERR_TS',
'_BACKUP_NAME_LOCK',
'_CODE_EMAIL_TEMPLATES',
'_CODE_FAILS',
'_CODE_FAILS_MAX',
'_CODE_PURPOSES',
'_DB_LOCK',
'_EMAIL_SENT_24H',
'_LOG_WRITE_COUNTER',
'_PBKDF2_ITERS',
'_PROVINCE_CACHE',
'_SMTP_ENC_PREFIX',
'_auto_backup_loop',
'_backup_is_valid_db',
'_backup_thread_started',
'_before_restore_hook',
'_code_fails_trim',
'_hash',
'_hash_new',
'_is_private_ip',
'_last_province',
'_normalize_email',
'_q',
'_smtp_connect',
'_smtp_password_decrypt',
'_smtp_password_encrypt',
'_user_public',
'_verify_password',
'_x',
'add_credits',
'add_log',
'backup_path',
'ban_user',
'charge_credits',
'check_verify_code',
'clear_logs',
'create_backup',
'create_user',
'delete_backup',
'delete_card',
'delete_user',
'device_used',
'format_credits',
'generate_cards',
'get_announcement',
'get_conn',
'get_secret_key',
'get_setting',
'get_smtp_config',
'get_user_by_email',
'get_user_by_id',
'get_user_by_name',
'init_db',
'ledger_cleanup_settled',
'ledger_get',
'ledger_open',
'ledger_recover_orphans',
'ledger_rename',
'ledger_settle',
'ledger_supplement',
'list_backups',
'list_cards',
'list_users',
'prune_backups',
'query_ip_province',
'query_logs',
'record_login_location',
'redeem_card',
'refund_credits',
'register_before_restore_hook',
'register_ip_exceeded',
'reserve_and_open',
'reserve_credits',
'reset_password',
'restore_backup',
'restore_verify_code',
'save_announcement',
'save_smtp_config',
'send_email',
'send_verify_code',
'set_card_disabled',
'set_setting',
'set_user_credits',
'set_user_netease_cookie',
'set_user_password',
'set_user_status',
'smtp_configured',
'start_auto_backup',
'unban_user',
'verify_login',
]