Nexus Agent
b46922fe92
feat(watch): 4 槽实时监测 — 5s 探针、WS、历史页与告警联动
...
宝塔式自选子机监测:Pin CRUD、全指标 SSH/Redis 探针、探针落库、
/ws/watch 推送、监测历史与进程抽屉;Agent 可选附带 net/disk IO。
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-06-12 02:56:37 +08:00
Nexus Agent
540712500f
fix: 移除 iframe 浏览器并优化推送页服务器展示
...
删除内置浏览器前后端;推送页支持卡片/列表切换、点击名称复制与长名称展示。
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-06-12 01:43:51 +08:00
Nexus Agent
8356425814
feat: 全局浮动浏览器、记录持久化与角落快捷入口
...
浮动面板可最小化至右下角、左下角随时展开;标签与浏览记录写入 MySQL,切换菜单保持活动。
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-06-11 20:10:57 +08:00
Nexus Agent
dc4593f8b5
Remove browser RDP (guacd/Guacamole) feature entirely.
...
Product decision: drop 3389 remote desktop page, API, guacd sidecar, and related tests after unresolved target-side black screen issues.
2026-06-10 23:23:09 +08:00
Nexus Agent
f127f07ab2
feat(rdp): 3389 页独立管理 RDP 主机
...
rdp_hosts 表与专用 API,在 3389远程页添加/连接,不再依赖子机列表。
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-06-10 20:58:46 +08:00
Nexus Agent
dabfc128b3
feat: 浏览器 RDP、推送提示音与子机指标等多项功能
...
- 3389远程页 + guacd 侧车 WebSocket 桥(无 RDP 会话审计)
- 文件推送完成独立提示音,至少一台成功即播放
- 子机列表展开 CPU/内存/磁盘 sparkline 与指标采样落库
- 终端全量服务器列表、连接中状态;告警 Telegram 公网 IP
- SSH 密钥凭据 UI 简化;子机搜索未设路径筛选
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-06-10 01:37:32 +08:00
Nexus Agent
7209f53af9
feat: 子机离线 Telegram 告警与仪表盘统计/趋势增强
...
离线边沿检测推送一次 Telegram(设置开关 notify_alert_offline);对齐仪表盘与服务器页统计卡、舰队趋势交互与告警叠加。
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-06-09 17:16:48 +08:00
Nexus Agent
3ba78cd10a
feat(api): translate HTTPException detail to Chinese for admin routes
...
Add a global detail translator for common 4xx messages (Server not found,
auth headers, settings not found, etc.) while keeping /api/agent/* in English.
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-06-09 08:42:43 +08:00
Nexus Agent
69068e2e39
feat(ops): server_batch 回收、sync_logs 清理与 Agent 安装跳过
...
部署对齐三项后端能力:启动/周期收尾僵尸批量任务、30 天推送日志 purge、已安装且版本不低于主站时跳过批量安装 Agent。
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-06-08 15:23:03 +08:00
Nexus Agent
632891e6e5
fix(settings): 表单校验与 422 中文错误信息
...
v-form 保存前 validate;validation_errors_zh 翻译 Pydantic msg;value 数字 coerce。
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-06-08 14:52:59 +08:00
Nexus Agent
27da842a20
fix: Telegram 开关多 worker 同步与服务器行内详情展开
...
关闭 notify_* 后通过 Redis 广播同步各 worker 内存设置;修复 expanded id 类型不匹配导致点击名称无法展开详情。
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-06-08 13:05:22 +08:00
Nexus Agent
08a0157c95
feat: 调度表单重构、登录门控、批量任务与页面缓存对齐
...
调度页执行周期可视化/单次执行/分类选机/推送源对齐;登录 IP 门控与无缝导航;
服务器批量后台任务、执行记录、凭据合并、各页激活刷新与错误提示修复。
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-06-08 11:17:21 +08:00
Nexus Agent
05006cb5df
feat(auth): refresh token 先 Redis 后 MySQL 双写
...
登录 30 天会话 hash 持久化到 admin_refresh_tokens;启动从 MySQL 回填 Redis,
Redis 重启后会话仍可 refresh。
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-06-07 21:56:56 +08:00
Nexus Agent
e5e2582743
fix(security): 外网攻击面加固 BL-01~05
...
收紧 PUBLIC 路径误匹配、强制 health/detail 与壁纸 sync 鉴权、默认关闭 OpenAPI;
安装锁定后 /api/install/* 统一 404;附探测脚本、测试与审计文档。
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-06-07 01:45:10 +08:00
Nexus Deploy
b866e944ab
fix: Code Review P0/P1 batches 1-3 and single-operator risk acceptance
...
Apply sync/install/auth/schedule/retry/agent/settings fixes from full
code review; document accepted WS and Agent legacy risks for solo ops.
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-06-04 15:57:49 +08:00
Your Name
4b5602a719
feat(files): fix editor freeze, EOL gates, server form and session UX
...
- FilesPage storeToRefs + remotePath coercion; Monaco preload; list action buttons
- text_io for UTF-8/LF; install/sync EOL; check_shell_eol + check_text_eol gates
- ServerFormDialog, hash login redirect, AppAuth keep-session; design docs and audits
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-06-03 00:42:55 +08:00
Your Name
78798e3630
feat(push): refactor B0-B6, /ws/sync channel, staging cleanup
...
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-06-02 08:14:09 +08:00
Your Name
c6f1d73ff5
feat(files): P4 GET browse with ETag and P5 zero-flicker loading
...
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-06-02 05:59:55 +08:00
Your Name
8935081ac5
feat: full-site acceptance automation and health/detail fix
...
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-06-01 15:22:42 +08:00
Your Name
8311821590
fix: 全量修复批量选择、JWT 60min、script-callback 认证与心跳数据流
...
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-06-01 12:17:47 +08:00
Your Name
facc1e8ae4
feat: TerminalPage全面迭代 + 快捷命令MySQL持久化
...
P0: Ctrl+L清屏、命令历史恢复、重连per-session、onopen不忽略、ping per-session
P1: 空catch处理、termRefs用session.id、错误透传、剪贴板权限、webssh-token错误
P2: 全选菜单、指数退避重连、快捷命令编辑、uptime per-session
新功能: quick_commands MySQL表 + CRUD API、Shell语法高亮输入栏
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-05-31 23:12:18 +08:00
Your Name
d0308aaef6
fix: allow /app/wallpapers/ through AppAuthMiddleware
...
- Added /app/wallpapers/ to _APP_PUBLIC_PREFIXES so cached wallpaper images
are served without requiring login auth
- Wallpaper files are now saved to web/app/wallpapers/ by bing_wallpaper() endpoint
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-05-31 20:30:46 +08:00
Your Name
7a6479dbfa
fix: remove stale login.html from public paths, clean up prefixes
...
Old Tailwind HTML pages removed from server — Vuetify SPA is now
the sole entry at /app/. Only install.html remains for setup wizard.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-05-31 15:44:56 +08:00
Your Name
0fdae981cf
fix: add ttf/eot/otf to static asset whitelist in AppAuthMiddleware
...
Vuetify/Monaco fonts return 404 without these extensions whitelisted.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-05-31 15:42:43 +08:00
Your Name
f745714530
fix: allow Vuetify SPA index.html through AppAuthMiddleware
...
The new Vuetify SPA uses hash routing — all pages served from single
index.html. The old middleware only whitelisted individual HTML page
paths (login.html etc.), blocking the SPA entry point with 404.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-05-31 13:13:13 +08:00
Your Name
de8d860244
fix: handle legacy agent heartbeat without server_id + migrate on_event to lifespan
...
- AgentHeartbeat.server_id changed to Optional[int] — missing server_id
now returns 200 (discarded) instead of 422, stopping retry loops
- web/agent/agent.py: on_event("startup") → FastAPI lifespan pattern
- Added exponential backoff on consecutive heartbeat failures (cap 5min)
- Agent stops heartbeat loop on "discarded" response from central
- main.py: promoted temporary debug 422 handler to production-grade
- uninstall.sh: added legacy agent cleanup (pkill patterns, crontab,
/opt/multisync-agent path)
- Confirmed servers.html batch buttons work correctly (disabled state
is correct when no agents installed)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-30 18:20:14 +08:00
Your Name
deffa8a8f4
fix: AppAuthMiddleware 验证 refresh token 格式而非 JWT 解码
...
refresh token 是 opaque 格式 (token:admin_id:token_version),不是 JWT。
之前用 pyjwt.decode() 验证必然失败,导致所有登录用户访问 /app/ 都返回 404。
改为验证格式合法性(3段、admin_id>0、token_version>=0)。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-30 05:10:39 +08:00
Your Name
cc0ca47d61
debug: 422 handler 简化 — 只记录 errors 和 content_type,不读 body
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-30 03:09:30 +08:00
Your Name
449373f24f
debug: 添加 422 验证错误日志 — 记录请求体和验证错误详情
...
诊断 Agent 心跳 422 问题,临时捕获请求体内容。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-30 03:05:30 +08:00
Your Name
730b665306
fix: AppAuthMiddleware 类定义移到 add_middleware 调用之前
...
Nexus CI/CD / test (push) Waiting to run
Nexus CI/CD / deploy (push) Blocked by required conditions
Nexus Pre-commit Checks / quick-check (push) Waiting to run
Python 模块级代码顺序执行,类必须先定义再引用。
之前 add_middleware(AppAuthMiddleware) 在第404行但类定义在第495行,
导致 NameError 服务启动失败。同时修复 _is_install_mode → is_install_mode。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-30 03:01:08 +08:00
Your Name
f5bea6f0d2
fix: AppAuthMiddleware add_middleware 重新加回
2026-05-30 02:46:11 +08:00
Your Name
c808c28edf
fix: 移除错误的 AppAuthMiddleware add_middleware(类定义在后面)
...
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-30 02:45:19 +08:00
Your Name
d53309e37e
fix: AppAuthMiddleware 类定义移到 add_middleware 之前
...
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-30 02:43:29 +08:00
Your Name
a8fe7fed0a
fix: 添加 REFRESH_COOKIE_NAME import,修复 AppAuthMiddleware NameError
...
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-30 02:41:12 +08:00
Your Name
f91cd847a9
feat: AppAuth 中间件 — 未登录时 /app/ 页面返回空白 HTML 404
...
通过 nexus_refresh cookie 验证身份,无有效 token 返回空白 HTML,
不暴露系统存在。白名单路径: login/install/vendor/static assets。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-30 02:39:48 +08:00
Your Name
ae22db4b3e
fix: Nginx 重定向 + 自定义 404 — 隐藏 FastAPI 后端信息
...
Nexus CI/CD / test (push) Waiting to run
Nexus CI/CD / deploy (push) Blocked by required conditions
Nexus Pre-commit Checks / quick-check (push) Waiting to run
nginx_https.conf 新增注释化重定向规则,将裸页面路径 301 到 /app/ 前缀;
main.py 添加 StarletteHTTPExceptionHandler,404 返回空白 HTML 而非 JSON,
避免泄露后端框架标识。
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com >
2026-05-30 02:03:57 +08:00
Your Name
ad2e7667d3
Merge branch 'claude/condescending-ishizaka-3cff3a'
2026-05-28 21:02:09 +08:00
Your Name
77b332c037
fix: 远程安装按钮修复 + install.sh sudo/venv兼容 + api_base_url管理
...
- 修复详情面板"远程安装"按钮始终禁用:s._base_url 改为从新API获取全局API_BASE_URL
- 新增 GET /api/servers/meta/api_base_url 端点
- api_base_url 加入 DB_OVERRIDE_MAP + 启动迁移逻辑
- install.sh 非 root 用户自动 sudo 检测 + NOPASSWD 配置
- 后端 _sudo_wrap 辅助函数应用于 4 个 Agent 操作端点
- install.sh venv 创建加 || true 兼容 set -e(缺 python3-venv 不再直接退出)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-27 14:33:19 +08:00
Your Name
eadf7254a1
Merge remote-tracking branch 'origin/claude/condescending-ishizaka-3cff3a'
2026-05-26 22:59:14 +08:00
Your Name
1c70e597a3
Fix Agent install 404 + add command input bar + fix install pipe error hiding
...
1. Mount /agent/ static files for install.sh/agent.py (was 404)
2. Replace curl|bash pipe with temp-file download to catch curl errors
3. Add command input bar to terminal.html bottom
4. Fix terminal CSS layout for flex with command bar
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-26 22:57:32 +08:00
Your Name
867e2aa552
Merge branch 'claude/condescending-ishizaka-3cff3a'
...
# Conflicts:
# server/infrastructure/database/setting_repo.py
2026-05-26 21:58:38 +08:00
Your Name
ccb78ed980
feat: SSH key preset system — dropdown + backend auto-resolve
...
- Add SshKeyPreset model + repo (encrypted_private_key, public_key)
- Add ssh_key_preset_id to Server model + schemas
- Add CRUD + reveal API routes (/api/ssh-key-presets/)
- servers.py: auto-resolve ssh_key_preset_id → decrypt → set ssh_key_private
- servers.html: key preset dropdown in key auth section, hides path/textarea on select
- Mirror password preset pattern: zero frontend credential exposure
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com >
2026-05-25 22:49:57 +08:00
Your Name
99201f48fd
fix: MissingGreenlet error — convert all middleware to pure ASGI
...
Root cause: BaseHTTPMiddleware.call_next() runs the endpoint in a
separate async task, which breaks SQLAlchemy's greenlet context.
After session.commit(), the connection is released to the pool.
When session.refresh() tries to acquire a new connection for a
SELECT, it fails with MissingGreenlet because the greenlet spawn
context is not available in the call_next() task.
Fix (two-part):
1. Convert all 4 middleware classes from BaseHTTPMiddleware to pure
ASGI middleware — eliminates call_next() entirely so the entire
request chain runs in the same async context.
2. Set expire_on_commit=False on the session factory — after commit,
objects retain their in-memory values instead of being expired.
This removes the need for session.refresh() entirely.
All session.refresh() calls removed from 11 repository files.
With expire_on_commit=False, post-commit attribute access no longer
triggers lazy loads that would also fail with MissingGreenlet.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com >
2026-05-25 15:24:15 +08:00
Your Name
c72631a293
merge: 安装脚本+PHP移除+宝塔适配 合并到main
...
合并 claude/condescending-ishizaka-3cff3a 分支:
- deploy/install.sh: 一键安装脚本(宝塔/标准模式自适应)
- deploy/upgrade.sh + uninstall.sh
- docs/install-guide.md: 完整中文安装教程
- PHP完全移除: install.php删除, config.php→config.json
- crypto.py: 移除PHP AES-CBC兼容, 纯Fernet
- install.py: 宝塔Supervisor路径自适应, Fernet密钥生成
- install.html: Step 5宝塔/标准模式条件渲染
- 44个冲突文件使用worktree分支版本(全部最新代码)
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com >
2026-05-25 08:25:29 +08:00
Your Name
a1276f38ad
feat: 一键安装脚本 + PHP完全移除 + config.php→config.json
...
新增文件:
- deploy/install.sh: 7步一键安装(自动检测宝塔/标准模式)
- deploy/upgrade.sh: git pull + pip install + restart + 健康检查
- deploy/uninstall.sh: 停服务+删配置, 可选--purge删部署目录
- docs/install-guide.md: 完整中文安装教程(宝塔+手动)
核心改动:
- install.py: 宝塔Supervisor路径自适应, init-db返回bt_panel标记,
config.php→config.json, 移除PHP锁文件, 生成Fernet加密密钥
- install.html: Step 5根据btPanel显示不同Supervisor/Nginx/SSL指引
- crypto.py: 移除PHP AES-CBC兼容层, 纯Fernet加密
- 删除 web/install.php (1192行PHP, 功能已完全迁移到Python)
PHP清理:
- Nginx配置: config\.php→config\.json deny规则
- config.py/main.py/migrations.py: install.php注释→install wizard
- CLAUDE.md/AGENTS.md: config.php→config.json, 移除PHP引用
- firefox_server.py: login.php→login.html默认URL
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com >
2026-05-25 08:23:37 +08:00
Your Name
cdd0be328a
fix: 六轮深度扫描 — 47项Bug修复、安全加固、死代码清理
...
Critical runtime bugs:
- terminal.html WebSSH完全不可用(URL前缀/JSON解析/Content-Type三处错误)
- servers.py路由遮蔽:/logs被/{id}拦截,3个前端页面同步日志查询失败
- scripts.html startExecPoll()→startExecPolling(),长任务快速执行崩溃
- agent.py {value!r!s:.50}格式串非法,agent发非数值时ValueError
- alerts.html d.daily.reduce()无null检查,API返回空数据时TypeError
Resource leak / stability:
- websocket.py僵尸连接未关闭TCP,文件描述符泄漏
- websocket.py _last_alert_time字典无限增长(加1小时过期清理)
- asyncssh_pool.py全忙时超过MAX_CONNECTIONS无限增长
- self_monitor.py Telegram告警无冷却,宕机时每30秒刷屏
- schedule_runner.py一次性调度执行超60秒会重复触发
- 限速脚本EXPIRE每次重置窗口可绕过(改用Lua原子脚本)
Security:
- JWT access token加token_version声明,改密码后旧token立失效(零宽限)
- INSTALL_MODE导入时常量→动态函数,安装后JWT认证不再残留禁用
- install.py /lock端点加管理员存在性验证,防止阻断安装
- ServerUpdate schema移除connectivity只读字段,防止伪造连接状态
Frontend fixes:
- doExec()缺r.ok检查、commands.html null检查
- _server_to_dict()补last_checked_at+ssh_key_public
- _field_match()逗号cron表达式修复
- alerts类型显示、SSH会话名称、搜索高亮定位
- 一次性/循环定时任务(run_mode+fire_at+自动禁用)
Dead code removed (400+ lines):
- SyncService batch_push/_push_single等5个方法(零调用者)
- 5个未使用schema(SyncCommands/SyncConfig/SyncSftp/FileDeploy/PaginatedResponse)
- 6个零调用service方法、3个无前端API端点
- 4个未使用import
Schema migrations:
- push_schedules: run_mode + fire_at列,cron_expr改NULL
- servers: 7个新列 + ssh_key_private/public VARCHAR(500)→TEXT
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com >
2026-05-24 16:26:40 +08:00
Your Name
fbf5eadcf2
fix(security): R2+R3 全面代码审计修复 — 3 CRITICAL / 9 HIGH / 15 MEDIUM / 10 LOW
...
CRITICAL:
- C-1: sync_service.py rsync命令shlex.quote防Shell注入回归
- C-2: agent.py exec端点危险命令正则拦截+compare_digest+僵尸进程修复
- C-3: WebSSH JWT token绑定server_id防IDOR
HIGH:
- H-1: 所有PUT/POST端点setattr改为字段白名单防任意字段注入
- H-2: settings/assets/scripts端点添加JWT认证
- H-3: refresh_token invalidate-then-generate防并发重放
- H-4: servers.py Redis pipeline解决N+1查询
- H-7: settings API Key/Secret掩码+禁止修改
- H-8: TOTP暴力破解速率限制(5次/5分钟)
- H-9: get_optional_admin改用request-scoped session
MEDIUM:
- M-2: X-Real-IP优先+X-Forwarded-For取末值防IP伪造
- M-4: asyncssh异常信息脱敏(只含server_id)
- M-5: 分页limit上限(500/200/500/500)
- M-9: API层Redis依赖抽象至dependencies.py
- M-10: WebSocket ConnectionManager多worker Redis聚合
- M-13: login_attempts复合索引
- M-14: ServerRepository.get_by_ids批量查询
- M-15: API错误消息统一中文
R3追加:
- sysctl命令注入防护+regex验证
- $DB_PASS明文存储→masked_command双命令方案
- MYSQL_PWD环境变量替代-p flag
- health端点拆分(公开/需认证)
- repo层**kwargs→字段白名单
- 全局str(e)信息泄露修复(API/Telegram/WebSocket)
- SSRF私有IP拦截
- Nginx HTTPS配置+DB备份脚本
- 前端CDN SRI哈希+XSS修复
- __import__替换为正常import
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-24 10:58:33 +08:00
Your Name
9bba58a529
feat: Telegram test+ChatID, Agent IP allowlist/upgrade, alert history page
...
Telegram:
- POST /api/settings/telegram/test: send test message (checks token+chat_id)
- GET /api/settings/telegram/chats: call getUpdates, return up to 5 chats
- settings.html: test button + detect chat IDs with click-to-fill
Agent IP allowlist (web/agent/agent.py):
- allowed_ips config: list of trusted IPs/CIDRs from config.json
- _ip_allowed(): checks exact IP, CIDR (ipaddress module), hostname
- verify_api_key(): now checks IP allowlist before API key
- /health: also checks IP allowlist
- install.sh: auto-extracts central server IP from --url, adds to allowed_ips
Agent auto-upgrade (server/api/servers.py):
- POST /api/servers/{id}/upgrade-agent: SSH → curl new agent.py → systemctl restart
- servers.html: 升级 Agent button in Agent tab (only when online)
Alert history (new page):
- domain/models: AlertLog table (server_id, type, value, is_recovery, created_at)
- migrations.py: CREATE TABLE IF NOT EXISTS alert_logs
- websocket.py: _save_alert_log() called from broadcast_alert/recovery
- settings.py: GET /api/alert-history/ (paginated, filters), GET /stats
- main.py: register alert_history_router
- alerts.html: new page with stats cards, top-servers bar chart, alert list
- layout.js: 🔔 告警中心 added to sidebar nav
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-05-23 18:27:12 +08:00
Your Name
da43960f38
feat: subscription URL stored in settings, auto-refresh allowlist every 2h
...
config.py:
- LOGIN_SUBSCRIPTION_URL: stored in DB, configurable from UI
- LOGIN_MANUAL_IPS: manually added IPs (preserved across auto-refresh)
background/ip_allowlist_refresh.py (new):
- ip_allowlist_refresh_loop(): primary-worker task, every 2h
- _do_refresh(): fetch subscription, parse IPs, merge with manual IPs,
write combined to LOGIN_ALLOWED_IPS + DB setting; runs once at startup (5s delay)
- get_last_refresh_time(): returns last successful refresh timestamp
main.py:
- Register ip_allowlist_refresh_loop as background task
settings.py:
- GET /ip-allowlist: now returns subscription_url, manual_ips, last_refresh
- POST /ip-allowlist: saves manual_ips + subscription_url, triggers refresh
- POST /ip-allowlist/manual: append to manual list only, trigger rebuild
- DELETE /ip-allowlist/ip: remove single manual IP, trigger rebuild
settings.html:
- Subscription URL field with 保存 + 🔄 instant-refresh button
- Last refresh timestamp display
- Status badge shows '订阅自动刷新' when URL configured
- IP badges: blue=manual (deletable), grey=from subscription (auto)
- 预览 button to inspect subscription IPs without saving
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-05-23 18:15:29 +08:00
Your Name
61b891db73
fix: Phase 3 line-walk fixes (3a-3d)
...
F3a-01 agent.py: _safe_float() prevents ValueError from non-numeric metric values
F3b-01 schedule_runner.py: fix tz-aware minus naive DateTime TypeError
F3b-02 schedule_runner.py: cron field divided by 0 returns False instead of crash
F3c-01 redis/client.py: mask credentials in REDIS_URL log output
F3d-01 main.py: cancel background tasks when primary worker lock is lost
F3d-02 main.py: strip whitespace from CORS origins after split
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-05-23 15:37:15 +08:00