Commit Graph

45 Commits

Author SHA1 Message Date
qinglong faf695e361 style: 状态emoji(🔄) → 纯文本符号(✓✗↻) 2026-06-13 20:49:17 +08:00
qinglong 899bef7781 feat: 设备卡片显示系统名+版本 + 项目根 version.json
- SystemInfoCollector.platform 新增 release 字段 (内核版本)
- Sentinel 卡片每台设备显示: Linux 6.12.23 | aarch64
- 数据刷新时同步更新系统信息行
- 项目根 version.json: 本地版本清单

当前版本检测:
  UpdateService 每6h从 {repo}/raw/branch/{branch}/version.json 拉取
  对比 base_config.yaml 的 framework.version
  远程 > 本地 → 顶栏绿色按钮 + 设置页更新提示

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 20:47:22 +08:00
qinglong c8f2cb7b98 fix: Sentinel 编辑节点时 api_key 留空 → 保留旧值 2026-06-13 20:44:44 +08:00
qinglong cc50ecb813 fix: Windows兼容 + Textual 8.x + MD3 SVG图标替代emoji
1. Windows: reuse_port 仅非win32平台启用
2. Textual 8.2.7: refresh() 加 **kwargs 兼容 repaint 参数
3. WebUI: 设置页/插件页 emoji → SVG (fill:currentColor 日夜间适配)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 20:42:22 +08:00
qinglong c20417ff93 feat: 更新服务 — ZIP下载/备份/回滚/重启
UpdateService:
- 分支感知: 从 base_config 读取 branch, 拼接 archive/{branch}.zip
- 定时检查: 每6h 拉取 version.json 比对版本
- 更新前自动打包备份 (zip, 保留最新5个)
- 保护用户配置: base_config.yaml / plugins/*/config.yaml / data/
- 子进程 pip install 依赖

API:
- GET /api/updates — 更新状态
- POST /api/updates/check — 手动检查
- POST /api/updates/apply — 执行更新

回滚:
- python main.py --rollback  — 恢复到最新备份
- 无备份时提示

重启:
- .restart_flag 信号文件 → 优雅退出 → systemd 拉起

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 20:32:42 +08:00
qinglong d0206121b1 fix: 统计卡片'安装失败'→'启动失败' + 合并 error_count 计数 2026-06-13 18:44:20 +08:00
qinglong e16250c7e7 style: 插件导入卡片 CSS — 等高 / 文件按钮 / 纵向布局 2026-06-13 18:43:30 +08:00
qinglong b2021a45ce feat: 插件管理 — 导入安装 + 统计面板
新增 API:
- GET /api/plugins/stats — 统计 (总计/已启用/已停用/安装失败)
- POST /api/plugins/import — ZIP上传 或 Git clone 安装
  - 自动 pip install -r requirements.txt (子进程隔离)
  - 自动加载插件 (isolated 模式, 崩溃不影响框架)
  - 安装失败记录到 _IMPORT_FAILS

前端:
- 横版统计卡片 (总数/启用/停用/失败)
- ZIP 上传按钮 + Git URL 输入
- 安装状态实时反馈

安全:
- 所有端点 panel_auth 保护
- 子进程安装 (pip/git), 超时120s
- 仅接受 .zip 文件
- 目录冲突检测

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 18:39:38 +08:00
qinglong a2bd6486a0 fix: 动画改用 setInterval (兼容动态 script 加载) + try-catch 保护 2026-06-13 18:29:11 +08:00
qinglong c4b44e0fd2 fix: 仪表盘动画改为模块方法 _animateNumber (避免全局作用域问题) 2026-06-13 18:26:38 +08:00
qinglong 81ebbc3e45 feat: WebUI 首页仪表盘 — CPU/MEM/进程内存 数字跳动动画
- animateNumber(): 900ms ease-out 缓动, 存储前值于 data-val
- CPU%、MEM%、进程内存 三个指标使用跳动动画
- 与 Sentinel 卡片动画风格统一

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 18:21:05 +08:00
qinglong 3ca001b938 fix: 进度条平滑过渡 — force reflow 技巧确保 CSS transition 生效
- 临时关 transition → 设旧值 → offsetWidth reflow → 开 transition → 设新值
- DOM 复用: 首次 innerHTML 创建, 后续只改属性
- 进度条从旧值滑到新值, 不再闪现

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 18:19:07 +08:00
qinglong 417213096f fix: Sentinel 清除占位卡片 + 动画延长至 1s 2026-06-13 18:17:26 +08:00
qinglong f3a6e5fbcd feat: Sentinel 数字跳动动画 + 进度条平滑过渡
- 数字 count-up/down: requestAnimationFrame + ease-out cubic, 350ms
- 中间值过渡: 15%→22% 会显示 15.2,16.1,17.5...22.0
- 进度条: CSS transition 自动处理宽度变化
- 卡片 DOM 复用: 更新值而非重建 innerHTML

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 18:12:37 +08:00
qinglong 1d0f227267 fix: API Key 删除/创建去掉 CSRF — panel_token HttpOnly 前端无法读取
SameSite=Lax cookie 已防跨站 POST/DELETE, 无需额外 CSRF header
前端 JS 无法读取 HttpOnly cookie, 无法设置 X-CSRF-Token

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 18:07:47 +08:00
qinglong 51c1ee84f0 feat: Sentinel 卡片数据刷新动画
- 卡片更新时背景闪烁 (card-flash keyframe)
- 进度条平滑过渡 (cubic-bezier .6s)
- 数值涨跌颜色: 绿涨↑ 红跌↓ 不变灰色
- 渐变进度条背景
- 存储前值用于趋势对比

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 18:06:06 +08:00
qinglong c416b04798 fix: Sentinel 改用前端轮询替代 SSE (解决 EventSource 认证问题)
SSE 跨 panel_auth 认证层不可靠 → 改用 setInterval 每 2s fetch /sentinel/api/nodes

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 18:00:34 +08:00
qinglong a21e092207 fix: Sentinel SSE URL — /SenSu/plugin/... → /plugin/... (匹配实际路由) 2026-06-13 17:56:57 +08:00
qinglong b53410bc77 fix: Sentinel SSE 每次轮询都推送 (实时性) + isolation 默认 false + 文档
Sentinel:
- poll_interval 3s→2s, 每次轮询都推 SSE (不再等状态变化)
- 解决稳定状态下数据更新不实时问题

插件系统:
- 默认 isolation: false (避免插件 WebUI 不显示)
- example_plugin 显式设置 isolation: false
- 插件开发指南: settings 示例增加 isolation 说明

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 17:54:39 +08:00
qinglong af16549524 chore: 清理误提交的 base_config.yaml.bak 2026-06-13 17:46:33 +08:00
qinglong 5e06c17b52 fix: WebSocket 鉴权 — Cookie 优先 (支持 HttpOnly)
根因: panel_token 是 HttpOnly cookie, JS getCookie() 读不到
→ 前端 WS ?token= 参数为空 → 认证失败 → 仪表盘无数据

修复:
- _ws_auth_wrapper: Cookie 优先 → query token 备用 → API Key
- 浏览器同源 WS 自动发送 Cookie, 无需 ?token=
- dashboard.js / logs.js 移除多余的 getCookie+?token=

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 17:45:58 +08:00
qinglong 557135c376 security: 配置文件模板化 — base_config.yaml 不再入库
- base_config.yaml → .gitignore (含真实密码不入库)
- 新增 base_config.yaml.example 模板 (password: CHANGE_ME)
- InitService: 检测缺失时自动从模板复制
- 首次启动自动创建配置文件

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 15:20:14 +08:00
qinglong 634496d975 security: Sentinel 路由鉴权 + API Key CSRF + SSRF 防护
修复:
- Sentinel 路由 require_auth=False → True (严重: 未认证可访问)
- API Key 创建/删除加 csrf_protect=True
- SSRF 防护: 测试连接仅允许 http/https scheme
- 插件网络鉴权: 已加载插件自动放行 (不再要求 plugin.network.access)
- Sentinel 权限列表补充 plugin.network.access

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 15:13:56 +08:00
qinglong 66ad51002c feat: WebUI 框架设置页面 + API Key 管理 UI
新增:
- static/web_panel/pages/settings.html — API Key CRUD 界面
- 侧边栏 '框架设置' 导航项 (齿轮图标)
- BUILTIN_PAGES 增加 'settings'
- UI 功能: 创建对话框(名称/权限/过期), 列表表格, 一键删除

权限模板:
- readonly — framework.status.read + plugin.info.read
- monitor — + framework.event.subscribe
- full — admin (全部)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 14:28:59 +08:00
qinglong b92b1cc4fc security: API Key 权限范围 + 过期时间 + 用量追踪
增强:
- 权限模板: readonly / monitor / full
- 每 key 独立权限列表, 注入 user['perms']
- 可选过期时间 (ttl 参数)
- 过期 key 自动清理 (加载时 + 验证时)
- request_count 用量追踪
- 标记 is_api_key = True

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 14:27:07 +08:00
qinglong 9f6eb29820 feat: API Key 系统 — CRUD + panel_auth 集成 + 持久化
新增:
- services/web_panel/routes/apikeys.py — 创建/列表/删除 API Key
- panel_auth() 双重验证: Session Store → API Key fallback
- _check_plugin_auth() 支持 API Key
- API Key 持久化到 SenSuDB (config_kv 表)
- 格式: sk- + 48 hex chars
- 脱敏显示 (前8后4)
- 删除后立即失效 (401)

WebPanelManager 注册 apikeys 路由

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 14:25:55 +08:00
qinglong 2da52e80d0 security: P3+ — 面板密码哈希 + 上传类型白名单 + CSRF Token
面板密码安全:
- 支持哈希存储 (password_hash/password_salt)
- 登录使用 secrets.compare_digest 时序安全比较
- 回退明文兼容旧配置
- 默认密码 admin 时打印 CRITICAL 警告

文件上传安全:
- 拒绝危险扩展名: .exe/.dll/.so/.sh/.bat/.ps1 等
- 拒绝敏感文件名: .htaccess/Makefile/Dockerfile 等
- 上传时检查并返回 403

CSRF 防护:
- panel_auth(csrf_protect=True) 参数
- 写操作需 X-CSRF-Token header 匹配 session token
- 保护范围: 文件删除/写入/创建/上传/重命名 + 项目启停 + 代理管理

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 14:07:38 +08:00
qinglong ff02b2e16d security: P3 — 插件隔离默认开启 + SenSuDB 注册 + 审计日志
- plugins.isolation 默认 true (生产环境进程隔离)
- main.py 注册 SenSuDB 服务
- WebPanelManager 注入 sensu_db 到 app context
- 文件删除/写入操作写入审计日志 (audit_log 表)
- 修复 Session 持久化所需的数据库依赖

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 13:56:58 +08:00
qinglong c1d2767f52 fix: web 命令端点 execute_command → process_command (方法名错误)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 13:54:37 +08:00
qinglong fcac02d920 security: P2 生产深度加固 — 路径/鉴权/脱敏/校验/持久化/过期
4.3 文件管理器路径收紧:
- 默认移除 Path('/') 全文件系统访问
- 仅允许项目目录 + data/ + 环境变量 SENSU_FILE_ROOTS 指定路径

3.4 插件路由鉴权修复:
- _check_plugin_auth 增加 panel_token 用户身份验证
- 先验证用户登录, 再检查插件权限

4.2 错误脱敏:
- security middleware 捕获异常 → 通用 'Internal server error'
- 堆栈详情仅写入日志, 不暴露给客户端

4.4 命令参数校验:
- POST /api/command 拒绝 shell 元字符 (;&|`$(){}!#~<>)
- 防止命令注入

4.5 Session 持久化:
- 登录/退出时保存到 SenSuDB.config_kv
- 框架重启后自动恢复已持久化会话

4.6 Token 过期: 24h → 2h

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 13:50:51 +08:00
qinglong 2f9063d6d4 fix: 登录频率限制 bug — lock_until=0 导致计数被清零
根因: 初始 lock_until=0 时 now >= 0 + 60 恒为真, 每次请求都清除计数
修复: lock_until 改用 None 表示未锁定, 仅非 None 时做过期判断

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 13:46:29 +08:00
qinglong d5388057d9 feat(v0.2.2): 插件热重载 — watchdog 监听 plugins/ 自动重载
- PluginService.start() 中启动 watchdog Observer
- 监听 plugins/ 下 .py/.yaml/.yml 文件变更
- 1秒防抖,避免重复触发
- 变更后自动卸载→重新加载对应插件
- 插件重载后自动重连网络路由
- PluginService.stop() 清理 observer
- 配置项 hot_reload: true/false 控制

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 11:01:00 +08:00
qinglong dcef1173f2 feat(v0.2.2): 调试服务器自启动 — InitService.start_auto_scripts()
通用自动启动脚本机制:
- base_config.yaml 新增 auto_start_scripts 配置段
- InitService 在日志服务就绪后扫描并拉起配置的脚本
- 脚本不存在时优雅跳过,不影响框架启动
- 每个脚本独立子进程 + 独立进程组 (os.setsid)
- 框架 shutdown 时自动终止 (SIGTERM → killpg)
- 模块级单例跟踪所有进程,避免重复启动

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-13 10:58:01 +08:00
qinglong 9de094ea54 fix: 移除遗留fmfuncs目录创建 + 清理init_service无用导入 + 文件管理器SVG图标 + 示例插件MD3改造
- init_service: 删除_load_fmfuncs方法和fmfuncs目录创建(已迁移到sdk/)
- init_service: 清理未使用的importlib.util和sys导入
- 文件管理器: 全部emoji替换为MD3 SVG矢量图标(文件夹/文件类型/右键菜单)
- 示例插件: dashboard.html改为MD3风格 CSS变量自动适配日夜主题
- 面包屑: 加底色+模糊+左右外边距
- CSS: .btn::after加pointer-events:none
- 插件开发指南: 更新2.6节MD3主题同步和完善的CSS变量/组件类参考表

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 19:00:19 +08:00
qinglong 99c3e3e853 feat: hash路由 + 插件页面内联加载 + 侧边栏插件面板展开项
- Hash路由: #/dashboard #/files #/plugins/xxx 支持刷新保持/前进后退
- 登录过期保留hash,登录后自动跳回原页面
- 插件WebUI页面内联加载到page-container(不再弹新窗)
- 插件页面HTML自动处理: style提取/body剥离/script执行/padding归零
- 侧边栏新增「插件面板」可折叠项,展开列出所有已注册插件页面
- 内存卡片显示 已用/总容量(百分比右侧)
- 插件开发指南新增 2.6 WebUI页面开发章节

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 20:56:39 +08:00
qinglong fd715eac2b feat: 文件管理器 + Windows兼容 + SVG主题适配 (v0.6.0)
新增:
- services/web_panel/routes/files.py — 全功能文件管理后端API (11个端点)
- pages/files.html + files.js — 文件管理前端 (浏览/编辑/上传/删除/右键菜单)
- 插件Picker API: window.open+postMessage唤出文件选择器
- 符号链接目录双层面包屑 (逻辑路径+物理路径)
- 文件系统全访问+跨平台 (Linux/Windows/macOS)
- permission_rules.yaml新增4个filemanager.*权限

修复:
- SVG fill=currentColor 日夜模式自适应
- 特殊目录容错 (/dev/fd损坏符号链接/proc)
- 面包屑每层级独立可点击+可编辑路径跳转
- ..行返回上级+data-is-dir补全
- rmlint→lstat回退 损坏符号链接不炸页面

文档:
- 插件开发指南新增第八章(文件管理器集成)
- 开发踩坑记录新增4条(特殊目录/双面包屑/SVG颜色/Windows)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 18:23:32 +08:00
qinglong 4a989bf50f feat: WS实时推送、网速双线图、按钮MD3修复、页面加载器修复 (v0.6.0)
后端:
- 新增 /api/system/ws WebSocket端点 替代HTTP轮询 (每2s推送系统+框架数据)
- 修复 uptime始终为0 (sm.start_time时间戳)
- 网络采集新增TX上行+实时网速(delta法)
- 进程内存采集 (/proc/self/status VmRSS)
- 抑制aiohttp内部WS帧日志防刷爆日志文件

前端:
- 仪表盘: HTTP轮询→WS连接+指数退避自动重连
- 实时日志: 修复onclose重连bug+批量渲染30fps+500行上限防卡死
- 网速卡片: DualLineChart双线图(下行实线/上行虚线)
- Y轴零点偏移-5% 防止零网速贴底
- 所有按钮修复MD3组合类(btn+btn-tonal+btn-sm)
- 页面加载器: 改动态script元素执行 修复onclick全局作用域问题
- emoji图标→Material Design SVG图标
- CSS去残留</style>+新增.nav-item svg约束
- 登录页输入框+标签左对齐+按钮MD3样式
- 多个版本号显示修复(去双重v前缀)
- chart.js/app.js/HTML页面统一加版本号防浏览器缓存
- .gitignore新增docs/目录

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 16:23:31 +08:00
qinglong fd0a97fec5 Fix login redirect: add /SenSu/index.html route, restart picks up new app.js
- /SenSu/index.html now serves login page (was 404 after cookie expiry)
- Fresh restart with latest page loader + inline script execution
- All routes verified: 200 OK
2026-06-11 14:47:37 +08:00
qinglong c07cea4ff7 Fix page loader: execute inline scripts, JS module loading optional
- innerHTML strips script tags, now extract and eval them
- External .js module: 404 = skip gracefully (no error)
- Progress bar: completes regardless of JS module
- Proxy/projects pages now render with CSS + inline JS executes
2026-06-11 14:43:24 +08:00
qinglong dd8a31e29a Fix: proxy API prefix, version from config, remove auth from framework/system endpoints
- Proxy routes now use /SenSu/api/proxy (was missing prefix)
- Projects routes use dynamic prefix
- Version reads from config/framework/base_config.yaml
- Framework/System APIs no longer require auth (public info)
- Proxy init separated from route setup (avoids frozen router error)
- Version updated to v0.6.0
2026-06-11 14:37:28 +08:00
qinglong 6918ee6514 Fix headless mode: use sleep loop instead of CLI mode (prevent EOF exit)
- Headless now keeps server alive with asyncio.sleep(1) loop
- CLI mode only for non-headless fallback
- Enables running SenSu as daemon/service
2026-06-11 13:02:56 +08:00
AskaEth 8dbf628dd6 Phase 1: ProjectEngine + PyEnvManager + project management WebUI
- New: services/project_engine.py (async subprocess manager)
- New: services/pyenv_manager.py (Python version + venv + git clone)
- New: services/web_panel/routes/projects.py (5 REST endpoints)
- New: static/web_panel/pages/projects.html (WebUI)
- Tests: 28/28 passing, API verified (GET /api/projects)
- Docs: Phase1_Progress.md (local)
2026-06-10 20:41:24 +08:00
AskaEth 57009c7f43 Update version to v0.5.0 (config + TUI), clean DreamSu->SenSu in main.py 2026-06-10 19:46:09 +08:00
AskaEth f5800cc6c3 Debug: fix headless mode, plugin compat, psutil optional, module imports
- headless: TUI skip now works correctly
- example_plugin: keyword args compat (plugin_name=, config=, bridge=)
- sysmon: psutil made optional (graceful degrade)
- tui_service: SysMonWidget optional
- All 22 modules import clean, 23 tests pass, integration verified
2026-06-10 19:26:41 +08:00
AskaEth e6875f0b4b Initial commit: SenSu Alpha 0.2.0
- 13-service async plugin framework
- Textual TUI with CLI fallback
- Plugin hot-reload + permission system
- Web management panel (aiohttp)
- Bridge-based inter-module communication
- 10 regression tests

Fixes applied:
- PBKDF2-SHA256 auth (was plain SHA256)
- Auth bypass removed (was allow-all on fail)
- Bare excepts replaced with logged errors
- CatFramework/DreamSu -> SenSu naming unified
- ServiceManager: health checks + startup_order
- Env var credentials (SENSU_ADMIN_PASSWORD etc)
2026-06-10 12:28:05 +08:00