diff --git a/.pid b/.pid deleted file mode 100644 index 1447442..0000000 --- a/.pid +++ /dev/null @@ -1 +0,0 @@ -18490 diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index de82293..0000000 --- a/.pylintrc +++ /dev/null @@ -1,287 +0,0 @@ -[MASTER] -jobs=4 -persistent=yes -rcfile= -load-plugins= -extension-pkg-whitelist= -ignore-patterns=^test_.*\.py$ -ignore=CVS -output-format=colorized -reports=yes -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) -score=yes -fail-under=7.0 - -[MESSAGES CONTROL] -disable=all -enable= - missing-docstring, - empty-docstring, - invalid-name, - too-few-public-methods, - too-many-arguments, - too-many-instance-attributes, - too-many-locals, - too-many-public-methods, - too-many-statements, - redefined-builtin, - redefined-outer-name, - unused-argument, - unused-import, - unused-variable, - unused-wildcard-import, - wrong-import-order, - wrong-import-position, - import-error, - no-name-in-module, - no-member, - no-self-use, - not-callable, - undefined-variable, - used-before-assignment, - broad-except, - bare-except, - try-except-raise, - duplicate-code, - fixme, - trailing-whitespace, - bad-whitespace, - line-too-long, - missing-final-newline, - mixed-line-endings, - bad-continuation, - trailing-newlines, - multiple-statements, - anomalous-backslash-in-string, - deprecated-module, - deprecated-method, - super-with-arguments, - raise-missing-from, - consider-using-f-string, - consider-using-with, - use-implicit-booleaness-not-comparison, - use-list-literal, - use-dict-literal, - consider-using-enumerate, - consider-iterating-dictionary, - consider-using-set-comprehension, - consider-using-generator, - consider-using-any-or-all, - consider-using-in, - consider-using-max-builtin, - consider-using-min-builtin, - consider-using-sum, - consider-merging-isinstance, - chained-comparison, - simplifiable-if-expression, - unnecessary-lambda, - unnecessary-comprehension, - unnecessary-dunder-call, - unnecessary-pass, - unnecessary-ellipsis, - useless-else-on-loop, - useless-return, - useless-object-inheritance, - useless-suppression, - wrong-spelling-in-comment, - wrong-spelling-in-docstring - -[REPORTS] -output-format=text -files-output=no -reports=yes -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) -score=yes - -[REFACTORING] -max-nested-blocks=5 -max-line-length=88 -max-module-lines=1000 -max-statements=50 -max-args=5 -max-locals=15 -max-returns=6 -max-branches=12 -max-statements-in-a-loop=20 -max-public-methods=20 -max-attributes=7 -max-parents=7 -max-bool-expr=5 - -[BASIC] -good-names=i, - j, - k, - ex, - Run, - _, - __, - fd, - msg, - v, - var, - x, - y, - z, - ax, - fig, - plt, - df, - idx, - cnt, - doc, - env, - app, - req, - res, - cls, - self, - mcs, - obj, - mod, - pkgs, - pkg, - cfg, - conf, - config, - opts, - args, - kwargs, - logger, - log -bad-names=foo, - bar, - baz, - toto, - tutu, - tata -docstring-min-length=-1 - -[FORMAT] -max-line-length=88 -ignore-long-lines=^\\s*(# )??$ -single-line-if-stmt=no -single-line-class-stmt=no -max-module-lines=1000 -indent-string=' ' - -[SIMILARITIES] -min-similarity-lines=4 -ignore-comments=yes -ignore-docstrings=yes -ignore-imports=no - -[TYPECHECK] -ignored-modules= -ignored-classes=optparse.Values,thread._local,_thread._local -generated-members=REQUEST,acl_users,aq_parent -contextmanager-decorators=contextlib.contextmanager -missing-member-hint=yes -missing-member-hint-distance=1 -missing-member-max-choices=1 -missing-member-local-gt=2 -ignore-on-opaque-inference=yes -ignored-checks-for-mixins= -signature-mutators= -ignore-mixin-members=yes -ignore-none=yes -ignored-parents= -ignore-erase=no -ignore-import-error=yes -ignore-missing-imports=yes -dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ -additional-builtins= - -[VARIABLES] -additional-builtins= -init-import=no -dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ -callbacks=cb_,_cb -redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io -allow-global-unused-variables=no - -[LOGGING] -logging-modules=logging - -[MISCELLANEOUS] -notes=FIXME, - XXX, - TODO, - HACK, - BUG, - NOTE, - OPTIMIZE, - REVIEW, - WARNING, - DEPRECATED -max-string-length=100 - -[DESIGN] -max-args=5 -max-locals=15 -max-returns=6 -max-branches=12 -max-statements=50 -max-parents=7 -max-attributes=7 -min-public-methods=2 -max-public-methods=20 - -[IMPORTS] -deprecated-modules= -import-graph= -ext-import-graph= -int-import-graph= -known-standard-library= -known-third-party= -known-local-folder= -preferred-modules= -allow-wildcard-with-all=no -allow-any-import-level=no -allow-relative-imports=yes -allow-from-import-under-package=yes -allow-import-from-same-module=no -allow-import-from-package=yes -allow-unused-imports=no -allow-cyclic-import=no -cyclic-import-limit=10 -ignore-imports=no -ignore-import-error=yes -ignore-missing-imports=yes -preferred-modules= -single-line-exceptions=no - -[EXCEPTIONS] -overgeneral-exceptions=Exception,BaseException,StandardError,ArithmeticError,LookupError,EnvironmentError,EOFError,ImportError -ignore-on-exception=no - -[CLASSES] -defining-attr-methods=__init__, - __new__, - setUp, - __post_init__ -valid-classmethod-first-arg=cls -valid-metaclass-classmethod-first-arg=mcs -exclude-protected=_asdict, - _fields, - _replace, - _source, - _make -bad-dunder-names=__authors__, - __version__, - __date__, - __credits__, - __status__, - __maintainer__, - __email__, - __contact__, - __copyright__, - __license__, - __uri__, - __url__, - __program__, - __description__, - __build__ - -[STRING] -check-str-concat-over-line-jumps=no diff --git a/ai.md b/ai.md deleted file mode 100644 index 482b933..0000000 --- a/ai.md +++ /dev/null @@ -1,661 +0,0 @@ -# FutureOSS - AI 专用项目介绍 - -## 项目概述 - -**FutureOSS** 是一个面向开发者的插件化运行时框架,采用「一切皆为插件」的设计理念。它是一个轻量级、安全、灵活的底层支撑系统,适用于构建微服务、开发工具链和可扩展的业务系统。 - -**核心设计哲学**:最小化核心框架,最大化插件扩展能力。核心框架仅提供最基本的插件加载和管理功能,所有其他功能(HTTP服务、Web界面、日志系统等)都通过插件实现。 - -## 技术栈 - -- **语言**: Python 3.10+ -- **主要依赖**: - - `click`: CLI 框架 - - `pyyaml`: 配置解析 - - `websockets`: WebSocket 支持 - - `psutil`: 系统监控 - - `cryptography`: 加密和签名验证 -- **架构**: 插件化微内核架构 -- **协议支持**: HTTP RESTful API, WebSocket, TCP HTTP -- **部署**: Docker 容器化支持 - -## 项目结构 - -``` -/root/future-oss/ -├── 📁 oss/ # 核心框架代码 -│ ├── cli.py # CLI 命令入口 -│ ├── config/ # 配置系统 -│ ├── logger/ # 日志系统 -│ ├── plugin/ # 插件框架核心 -│ │ ├── capabilities.py # 能力接口定义 -│ │ ├── loader.py # 插件加载器 -│ │ ├── manager.py # 插件生命周期管理 -│ │ └── types.py # 类型定义 -│ └── shared/ # 共享组件 -│ └── router.py # 统一路由系统 -├── 📁 store/ # 插件仓库(核心功能) -│ ├── @{FutureOSS}/ # 官方核心插件 -│ │ ├── plugin-loader/ # 插件加载器(核心) -│ │ ├── http-api/ # HTTP API 服务 -│ │ ├── http-tcp/ # TCP HTTP 服务 -│ │ ├── ws-api/ # WebSocket API -│ │ ├── dashboard/ # Web 控制台 -│ │ ├── dependency/ # 依赖解析 -│ │ ├── signature-verifier/ # 签名验证 -│ │ ├── plugin-bridge/ # 插件间通信 -│ │ ├── plugin-storage/ # 数据持久化 -│ │ ├── pkg-manager/ # 包管理 -│ │ ├── log-terminal/ # 日志终端 -│ │ ├── json-codec/ # JSON 编解码器 -│ │ └── webui/ # Web 用户界面 -│ └── @{Falck}/ # 社区插件 -│ ├── html-render/ # HTML 渲染引擎 -│ └── web-toolkit/ # Web 开发工具集 -├── 📁 data/ # 运行时数据目录 -├── 📁 static/ # 静态资源 -├── 📁 templates/ # 模板文件 -├── 📁 tools/ # 开发工具脚本 -├── 📁 video/ # 演示视频和文档 -├── 📄 pyproject.toml # Python 项目配置 -├── 📄 requirements.txt # Python 依赖 -├── 📄 docker-compose.yml # Docker 编排配置 -├── 📄 Dockerfile # Docker 构建文件 -├── 📄 README.md # 项目说明文档 -└── 📄 LICENSE # Apache 2.0 许可证 -``` - -## 核心架构 - -### 1. 插件系统架构 - -FutureOSS 采用三层插件架构: - -1. **核心框架层** (`oss/`): 提供最基本的插件加载和管理能力 -2. **核心插件层** (`store/@{FutureOSS}/`): 官方提供的核心功能插件 -3. **社区插件层** (`store/@{Falck}/`): 第三方社区插件 - -### 2. 插件生命周期 - -``` -加载 (load) → 初始化 (init) → 启动 (start) → 运行 (run) → 停止 (stop) -``` - -### 3. 插件元数据格式 - -每个插件必须包含 `manifest.json` 文件,格式如下: - -```json -{ - "metadata": { - "name": "插件名称", - "version": "版本号", - "author": "作者", - "description": "功能描述", - "type": "插件类型 (core/protocol/utility)" - }, - "config": { - "enabled": true/false, - "args": { - "参数名": "参数值" - } - }, - "dependencies": ["依赖插件列表"], - "permissions": ["所需权限列表"] -} -``` - -### 4. 安全机制 - -- **数字签名验证**: 每个插件包含 SIGNATURE 文件 -- **权限分级控制**: 插件声明所需权限 -- **沙箱环境**: 可选的安全隔离 -- **来源验证**: 插件作者命名空间 (@{作者名}) - -## 核心插件功能 - -### 系统核心插件 - -1. **plugin-loader**: 插件扫描、加载与生命周期管理(必需) -2. **http-api**: HTTP RESTful API 服务(端口 8080) -3. **http-tcp**: TCP 高性能 HTTP 服务(端口 8082) -4. **ws-api**: WebSocket API 服务(端口 8081) -5. **dashboard**: Web 可视化监控仪表盘 -6. **dependency**: 插件依赖解析与自动安装 -7. **signature-verifier**: 插件数字签名验证 -8. **plugin-bridge**: 插件间通信桥接 -9. **plugin-storage**: 插件数据持久化存储 -10. **pkg-manager**: 插件包管理(安装/卸载/搜索) -11. **log-terminal**: 日志终端实时输出 -12. **json-codec**: 统一 JSON 编解码器 -13. **webui**: Web 用户界面框架 - -### 社区插件 - -1. **html-render**: HTML 模板渲染引擎 -2. **web-toolkit**: Web 开发工具集(静态文件/模板/路由) - -### 禁用插件(默认不加载) - -1. **hot-reload**: 开发模式热重载 -2. **i18n**: 国际化支持 -3. **lifecycle**: 插件生命周期钩子 -4. **code-reviewer**: 代码审查工具 -5. **plugin-loader-pro**: 高级插件加载器 - -## PL 注入机制 - -PL 注入是 plugin-loader 插件提供的一种扩展机制,允许插件通过 `PL/` 文件夹向插件加载器注册自定义功能。 - -### 工作原理 - -插件加载器在启动时自动扫描所有插件,检查其 `manifest.json` 中是否声明了 `pl_injection` 配置项: - -``` -插件加载器启动 - ↓ -扫描所有插件 manifest.json - ↓ -检查 config.args.pl_injection - ├── true → 检查 PL/ 文件夹 - │ ├── 存在 PL/main.py → 沙箱执行 → 调用 register(injector) → ✅ 正常加载 - │ └── 缺少 PL/ 或 PL/main.py → ⚠️ 警告并 ❌ 拒绝加载 - └── false/未声明 → ✅ 正常加载(跳过 PL 检查) -``` - -### 使用方式 - -#### 1. 在 manifest.json 中声明 - -```json -{ - "config": { - "args": { - "pl_injection": true - } - } -} -``` - -#### 2. 创建 PL/main.py - -``` -store/@{作者名}/插件名/ -├── manifest.json # 声明 pl_injection: true -├── main.py # 插件主逻辑 -├── PL/ # PL 注入文件夹 -│ └── main.py # 注入逻辑(必须包含 register() 函数) -└── README.md -``` - -#### 3. 实现 register() 函数 - -```python -# PL/main.py -def register(injector): - """向插件加载器注册功能 - - Args: - injector: PLInjector 实例 - """ - # 注册普通功能 - injector.register_function("my_helper", my_func, "功能描述") - - # 注册 HTTP 路由 - injector.register_route("GET", "/pl/hello", handler) - - # 注册事件处理器 - injector.register_event_handler("plugin.started", on_started) -``` - -### 注入器 API - -| 方法 | 说明 | -|------|------| -| `register_function(name, func, description="")` | 注册注入功能 | -| `register_route(method, path, handler)` | 注册 HTTP 路由 | -| `register_event_handler(event_name, handler)` | 注册事件处理器 | -| `get_injected_functions(name=None)` | 获取已注册的注入功能 | -| `get_injection_info(plugin_name=None)` | 获取注入信息 | -| `has_injection(plugin_name)` | 检查插件是否有 PL 注入 | -| `get_registry_info()` | 获取注册表完整信息 | - -### 安全限制 - -PL 注入机制实施了多层安全限制: - -| 限制类型 | 具体措施 | -|---------|---------| -| **文件类型限制** | 禁止 PL 文件夹中包含 `.sh`、`.bat`、`.exe`、`.dll`、`.so` 等可执行文件 | -| **静态源码检查** | 编译前扫描源码,禁止导入 `os/sys/subprocess/socket/ctypes` 等系统模块,禁止 `exec/eval/compile/open/__import__` | -| **沙箱执行** | 在受限沙箱中执行 PL/main.py,仅提供安全的 builtins | -| **参数校验** | 功能名称、路由路径、HTTP 方法、事件名称均通过正则校验 | -| **数量限制** | 每个插件最多注册 50 个功能,每个名称最多被注册 10 次 | -| **异常安全** | 所有注册函数自动包装 try-catch,异常不影响主流程 | -| **调用者溯源** | 通过栈帧回溯自动识别调用者插件名,防止冒充注册 | - -### 行为说明 - -| 场景 | 结果 | -|------|------| -| `pl_injection: true` + 存在 `PL/main.py` | ✅ 正常加载,执行注入 | -| `pl_injection: true` + 缺少 `PL/` 文件夹 | ❌ 警告并拒绝加载该插件 | -| `pl_injection: true` + 存在 `PL/` 但缺少 `main.py` | ❌ 警告并拒绝加载该插件 | -| 未声明 `pl_injection` | ✅ 正常加载,跳过 PL 检查 | -| `pl_injection: false` | ✅ 正常加载,跳过 PL 检查 | - -## 开发与部署 - -### 开发环境设置 - -```bash -# 安装依赖 -pip install -e . - -# 启动开发服务器 -oss serve - -# 访问 Web 控制台 -# http://localhost:8080 -``` - -### Docker 部署 - -```bash -# 使用 Docker Compose -docker-compose up -d - -# 暴露端口 -# 8080: HTTP API + 网站 -# 8081: WebSocket -# 8082: HTTP TCP -``` - -### 插件开发 - -1. **创建插件目录**: `store/@{作者名}/{插件名}/` -2. **编写 manifest.json**: 定义插件元数据 -3. **实现 main.py**: 插件主逻辑 -4. **添加 SIGNATURE**: 数字签名(可选) -5. **测试插件**: 通过 pkg-manager 安装测试 - -## API 接口 - -### HTTP API (端口 8080) - -- `GET /health`: 健康检查 -- `GET /api/plugins`: 获取插件列表 -- `GET /api/plugins/{name}`: 获取插件详情 -- `POST /api/plugins/{name}/enable`: 启用插件 -- `POST /api/plugins/{name}/disable`: 禁用插件 - -### WebSocket API (端口 8081) - -- 实时日志推送 -- 系统状态监控 -- 插件事件通知 - -### TCP HTTP (端口 8082) - -- 高性能 HTTP 服务 -- 兼容 HTTP/1.1 协议 - -## 配置系统 - -### 配置文件位置 - -1. **全局配置**: `config.yaml` (可选) -2. **插件配置**: `store/@{作者名}/{插件名}/config.json` -3. **环境变量**: 支持 Docker 环境变量覆盖 - -### 配置优先级 - -``` -环境变量 > 全局配置文件 > 插件默认配置 -``` - -## 数据存储 - -### 数据目录结构 - -``` -data/ -├── html-render/ # 网站渲染文件 -├── web-toolkit/ # Web 工具配置 -├── plugin-storage/ # 插件持久化数据 -└── DCIM/ # 共享资源存储 -``` - -### 存储类型 - -1. **临时存储**: 内存缓存 -2. **持久化存储**: 文件系统 (data/ 目录) -3. **插件私有存储**: 每个插件独立存储空间 - -## 监控与日志 - -### 日志系统 - -- **日志级别**: DEBUG, INFO, WARNING, ERROR, CRITICAL -- **输出目标**: 控制台、文件、WebSocket -- **日志格式**: 结构化 JSON 日志 - -### 监控指标 - -- 系统资源使用率 (CPU/内存/磁盘) -- 插件运行状态 -- API 请求统计 -- 错误率和异常监控 - -## 扩展能力 - -### 自定义插件开发 - -FutureOSS 支持多种插件类型: - -1. **协议插件**: 实现网络协议 (HTTP/WebSocket/TCP) -2. **工具插件**: 提供开发工具功能 -3. **界面插件**: 扩展 Web 控制台 -4. **存储插件**: 实现数据存储后端 -5. **中间件插件**: 请求处理管道 - -### 插件间通信 - -- **事件系统**: 发布/订阅模式 -- **直接调用**: 通过插件管理器 -- **共享存储**: 通过 plugin-storage -- **消息队列**: 通过 plugin-bridge - -## 最佳实践 - -### 性能优化 - -1. **懒加载插件**: 按需加载非核心插件 -2. **连接池管理**: 数据库和网络连接复用 -3. **缓存策略**: 合理使用内存缓存 -4. **异步处理**: I/O 密集型操作异步化 - -### 安全建议 - -1. **签名验证**: 生产环境启用所有插件签名验证 -2. **权限最小化**: 插件只申请必要权限 -3. **沙箱隔离**: 不可信插件启用沙箱模式 -4. **定期更新**: 及时更新插件和安全补丁 - -### 高可用性 - -1. **健康检查**: 配置完整的健康检查端点 -2. **故障转移**: 关键插件多实例部署 -3. **监控告警**: 设置系统监控和告警 -4. **备份恢复**: 定期备份插件配置和数据 - -## 故障排除 - -### 常见问题 - -1. **插件加载失败**: 检查 manifest.json 格式和依赖 -2. **服务启动失败**: 检查端口冲突和权限 -3. **性能问题**: 监控系统资源使用情况 -4. **内存泄漏**: 检查插件资源释放 - -### 调试工具 - -1. **日志终端**: 实时查看系统日志 -2. **Web 控制台**: 可视化监控插件状态 -3. **API 接口**: 通过 REST API 获取系统信息 -4. **开发工具**: tools/ 目录下的辅助脚本 - -## 官方网站项目 - -### 项目位置 -`/root/future-oss/website/` - FutureOSS 官方宣传网站 - -### 技术栈 -- **后端**: Node.js + Express.js -- **前端**: EJS 模板引擎 + 原生 JavaScript + CSS3 -- **构建工具**: npm -- **开发工具**: VS Code 运行与调试配置 - -### 项目结构 -``` -website/ -├── 📁 public/ # 静态资源 -│ ├── css/ # 样式文件 -│ │ ├── main.css # 基础样式和变量 -│ │ ├── components.css # 组件样式 -│ │ ├── animations.css # 动画效果 -│ │ └── pages/ # 页面特定样式 -│ ├── js/ # JavaScript 文件 -│ │ ├── main.js # 主逻辑 -│ │ ├── router.js # 前端路由 -│ │ ├── animations.js # 动画控制 -│ │ └── pages/ # 页面特定脚本 -│ └── images/ # 图片资源 -├── 📁 src/ # 源代码 -│ ├── server.js # Express 服务器 -│ ├── router.js # 路由配置 -│ ├── controllers/ # 控制器 -│ │ ├── pagesController.js # 页面控制器 -│ │ └── apiController.js # API 控制器 -│ ├── middleware/ # 中间件 -│ │ └── performance.js # 性能优化中间件 -│ ├── components/ # 组件(预留) -│ ├── pages/ # 页面逻辑(预留) -│ └── styles/ # 样式源码(预留) -├── 📁 views/ # EJS 视图模板 -│ ├── layouts/ # 布局文件 -│ │ └── main.ejs # 主布局 -│ ├── pages/ # 页面模板 -│ │ ├── home.ejs # 首页 -│ │ ├── features.ejs # 特性页 -│ │ ├── architecture.ejs # 架构页 -│ │ └── plugins.ejs # 插件页 -│ └── partials/ # 局部组件 -│ ├── navbar.ejs # 导航栏 -│ └── footer.ejs # 页脚 -├── 📄 package.json # npm 配置 -├── 📄 package-lock.json # 依赖锁定 -└── 📄 server.log # 服务器日志 -``` - -### 核心功能 - -#### 1. 多页面网站 -- **首页** (`/`): 项目介绍和快速开始 -- **特性页** (`/features`): 核心功能展示 -- **架构页** (`/architecture`): 技术架构说明 -- **插件页** (`/plugins`): 插件生态系统 - -#### 2. 性能优化特性 -- **响应时间监控**: X-Response-Time 头部 -- **缓存控制**: 静态资源长期缓存 -- **压缩支持**: Gzip 和预压缩 -- **安全头**: CSP、XSS 保护等 -- **内存监控**: 实时内存使用监控 - -#### 3. 用户体验增强 -- **加载动画**: 页面加载旋转指示器 -- **页面切换动画**: 平滑的页面过渡效果 -- **图片懒加载**: 延迟加载非视口图片 -- **骨架屏**: 内容加载占位符 -- **响应式设计**: 完整的移动端适配 - -#### 4. API 接口 -- `GET /api/health`: 健康检查 -- `GET /api/metrics`: 性能指标 -- `GET /api/info`: 服务器信息 -- `GET /api/stress-test`: 压力测试(仅开发环境) - -### 技术特点 - -#### 服务器特性 -- **端口自动切换**: 8080被占用时自动使用8081、8082等 -- **优雅关闭**: 支持 SIGTERM/SIGINT 信号优雅关闭 -- **错误处理**: 完善的错误处理和404页面 -- **中间件栈**: 完整的性能优化中间件 - -#### 前端特性 -- **组件化设计**: 导航栏、页脚等独立组件 -- **前端路由**: 支持无刷新页面切换 -- **CSS 变量**: 统一的主题变量系统 -- **动画系统**: 丰富的CSS动画和过渡效果 - -#### 开发工具 -- **VS Code 调试配置**: 支持直接运行与调试 -- **热重载支持**: nodemon 开发模式 -- **性能监控**: 实时性能指标输出 -- **日志系统**: 结构化服务器日志 - -### 部署与运行 - -#### 开发模式 -```bash -cd /root/future-oss/website -npm install -npm start -# 访问 http://localhost:8080 (或自动切换的端口) -``` - -#### 生产部署 -```bash -# 使用 PM2 进程管理 -pm2 start src/server.js --name "futureoss-website" - -# 使用 Docker -docker build -t futureoss-website . -docker run -p 8080:8080 futureoss-website -``` - -#### VS Code 调试 -1. 打开运行与调试面板 (Ctrl+Shift+D) -2. 选择 "FutureOSS 网站: 启动Node.js服务器" -3. 按 F5 启动调试 - -### 性能优化措施 - -#### 已实施的优化 -1. **响应头优化**: 缓存控制、安全头、压缩头 -2. **静态资源优化**: 长期缓存、预压缩支持 -3. **代码分割**: 按页面加载CSS和JS -4. **图片优化**: 懒加载、占位符、响应式图片 -5. **动画优化**: 减少重绘、will-change提示 - -#### 监控指标 -- **响应时间**: X-Response-Time 头部 -- **内存使用**: X-Memory-Usage 头部(开发环境) -- **慢响应日志**: 超过1秒的请求记录 -- **错误率**: 500错误监控和记录 - -### 已知问题和解决方案 - -#### 1. ERR_HTTP_HEADERS_SENT 错误 -- **问题**: 在响应已发送后设置响应头 -- **原因**: `responseTime` 中间件在 `finish` 事件中设置头部 -- **解决方案**: 使用 `headers` 事件或重写 `end` 方法 -- **修复代码**: - ```javascript - // 错误写法(在 finish 事件中): - res.on('finish', () => { - res.setHeader('X-Response-Time', `${duration}ms`); // 错误! - }); - - // 正确写法(重写 end 方法): - const originalEnd = res.end; - res.end = function(...args) { - if (!res.headersSent) { - res.setHeader('X-Response-Time', `${duration}ms`); - } - return originalEnd.apply(this, args); - }; - ``` - -#### 2. CSS 加载问题 -- **问题**: 页面只显示纯文本,CSS未加载 -- **原因**: EJS 布局系统未正确配置 -- **解决方案**: 安装并配置 `express-ejs-layouts` -- **修复步骤**: - 1. `npm install express-ejs-layouts` - 2. 在 server.js 中添加中间件 - 3. 设置默认布局 `app.set('layout', 'layouts/main')` - -#### 3. 加载性能问题 -- **问题**: 页面加载慢,无加载反馈 -- **解决方案**: 添加加载动画和性能优化 -- **实施措施**: - 1. 添加页面加载旋转动画 - 2. 实现图片懒加载 - 3. 添加骨架屏占位符 - 4. 优化静态资源缓存 - -### 扩展和定制 - -#### 添加新页面 -1. 在 `views/pages/` 创建新的 `.ejs` 文件 -2. 在 `controllers/pagesController.js` 添加渲染函数 -3. 在 `src/router.js` 添加路由 -4. 在 `public/css/pages/` 添加页面特定CSS -5. 在 `public/js/pages/` 添加页面特定JS - -#### 添加新组件 -1. 在 `views/partials/` 创建组件 `.ejs` 文件 -2. 在 `public/css/components.css` 添加组件样式 -3. 在布局或页面中使用 `<%- include('partials/组件名') %>` - -#### 主题定制 -通过修改 CSS 变量实现主题切换: -```css -:root { - --primary-color: #1e6fbb; /* 主色调 */ - --text-primary: #333333; /* 主要文字 */ - --bg-primary: #ffffff; /* 背景色 */ - /* 更多变量... */ -} -``` - -### 维护指南 - -#### 日常维护 -1. **日志监控**: 定期检查 `server.log` 文件 -2. **性能监控**: 关注慢响应日志 -3. **错误处理**: 及时修复报告的错误 -4. **依赖更新**: 定期更新 npm 包 - -#### 故障排除 -1. **服务器无法启动**: 检查端口占用,查看日志 -2. **页面样式异常**: 检查CSS文件路径和网络请求 -3. **API 无响应**: 检查路由配置和控制器 -4. **性能下降**: 使用 `/api/metrics` 接口诊断 - -#### 备份策略 -1. **代码备份**: Git 版本控制 -2. **配置备份**: 备份 `package.json` 和服务器配置 -3. **数据备份**: 备份用户上传内容(如有) -4. **日志归档**: 定期归档服务器日志 - -## 未来发展方向 - -### 短期规划 - -1. 插件市场功能完善 -2. 更多官方插件开发 -3. 性能优化和稳定性提升 -4. 官方网站功能增强 - -### 长期愿景 - -1. 跨语言插件支持 -2. 云原生集成 -3. 企业级功能扩展 -4. 生态系统建设 - -## 注意事项 - -1. **生产部署**: 建议使用 Docker 容器化部署 -2. **数据备份**: 定期备份 data/ 目录重要数据 -3. **安全更新**: 关注安全公告并及时更新 -4. **社区支持**: 通过 Gitee Issues 获取帮助 -5. **网站维护**: 定期更新官方网站内容和功能 - ---- - -*本文件专为 AI 助手设计,提供 FutureOSS 项目的全面技术概述,帮助 AI 理解项目架构、功能和使用方式。更新日期:2026年4月19日* \ No newline at end of file diff --git a/tests/test_cli.py b/tests/test_cli.py deleted file mode 100644 index b89fba3..0000000 --- a/tests/test_cli.py +++ /dev/null @@ -1,39 +0,0 @@ -"""CLI 命令单元测试""" -import pytest -from click.testing import CliRunner -from oss.cli import cli, version, serve - - -class TestCLI: - """测试 CLI 命令""" - - def test_version_command(self): - """测试版本命令""" - runner = CliRunner() - result = runner.invoke(version) - - assert result.exit_code == 0 - assert "Future OSS" in result.output - assert "1.2.0" in result.output - - def test_cli_help(self): - """测试 CLI 帮助信息""" - runner = CliRunner() - result = runner.invoke(cli, ['--help']) - - assert result.exit_code == 0 - assert "Future OSS" in result.output - assert "serve" in result.output - assert "version" in result.output - - def test_serve_command_exists(self): - """测试 serve 命令存在""" - runner = CliRunner() - result = runner.invoke(serve, ['--help']) - - assert result.exit_code == 0 - assert "启动 Future OSS" in result.output - - -if __name__ == "__main__": - pytest.main([__file__, "-v"]) diff --git a/tests/test_config.py b/tests/test_config.py deleted file mode 100644 index 6e131c1..0000000 --- a/tests/test_config.py +++ /dev/null @@ -1,105 +0,0 @@ -"""配置管理测试""" -import os -import pytest -from pathlib import Path -import tempfile -import json - -from oss.config.config import Config - - -class TestConfig: - """配置管理测试类""" - - def test_default_values(self): - """测试默认配置值""" - config = Config() - assert config.http_api_port == 8080 - assert config.http_tcp_port == 8082 - assert config.host == "0.0.0.0" - assert config.log_level == "INFO" - assert config.permission_check is True - - def test_env_override(self, monkeypatch): - """测试环境变量覆盖""" - monkeypatch.setenv("HTTP_API_PORT", "9999") - monkeypatch.setenv("LOG_LEVEL", "DEBUG") - - config = Config() - assert config.http_api_port == 9999 - assert config.log_level == "DEBUG" - - def test_file_config(self): - """测试配置文件加载""" - with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f: - json.dump({"HTTP_API_PORT": 7777, "LOG_LEVEL": "WARNING"}, f) - temp_path = f.name - - try: - config = Config(temp_path) - assert config.http_api_port == 7777 - assert config.log_level == "WARNING" - finally: - os.unlink(temp_path) - - def test_env_priority_over_file(self, monkeypatch): - """测试环境变量优先级高于配置文件""" - with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f: - json.dump({"HTTP_API_PORT": 7777}, f) - temp_path = f.name - - try: - monkeypatch.setenv("HTTP_API_PORT", "8888") - config = Config(temp_path) - assert config.http_api_port == 8888 # 环境变量优先 - finally: - os.unlink(temp_path) - monkeypatch.delenv("HTTP_API_PORT", raising=False) - - def test_get_set(self): - """测试 get/set 方法""" - config = Config() - assert config.get("HTTP_API_PORT") == 8080 - config.set("HTTP_API_PORT", 6666) - assert config.get("HTTP_API_PORT") == 6666 - - def test_properties(self): - """测试属性访问""" - config = Config() - assert isinstance(config.data_dir, Path) - assert isinstance(config.store_dir, Path) - assert config.data_dir.name == "data" - assert config.store_dir.name == "store" - - def test_all_method(self): - """测试 all() 方法返回所有配置""" - config = Config() - all_config = config.all() - assert "HTTP_API_PORT" in all_config - assert "HOST" in all_config - assert len(all_config) > 5 - - def test_bool_conversion(self, monkeypatch): - """测试布尔值转换""" - monkeypatch.setenv("PERMISSION_CHECK", "false") - config = Config() - assert config.permission_check is False - - monkeypatch.setenv("PERMISSION_CHECK", "true") - config = Config() - assert config.permission_check is True - - def test_int_conversion(self, monkeypatch): - """测试整数转换""" - monkeypatch.setenv("MAX_WORKERS", "8") - config = Config() - assert config.get("MAX_WORKERS") == 8 - - # 无效值应该保持默认 - monkeypatch.setenv("MAX_WORKERS", "invalid") - config = Config() - assert config.get("MAX_WORKERS") == 4 # 默认值 - - -if __name__ == "__main__": - pytest.main([__file__, "-v"]) diff --git a/tests/test_plugin_loader.py b/tests/test_plugin_loader.py deleted file mode 100644 index 49f05d5..0000000 --- a/tests/test_plugin_loader.py +++ /dev/null @@ -1,48 +0,0 @@ -"""插件加载器单元测试""" -import pytest -from pathlib import Path -from oss.plugin.loader import PluginLoader - - -class TestPluginLoader: - """测试插件加载器核心功能""" - - def test_loader_initialization(self): - """测试加载器初始化""" - loader = PluginLoader() - assert loader.loaded == {} - - def test_load_nonexistent_plugin(self): - """测试加载不存在的插件""" - loader = PluginLoader() - result = loader.load_core_plugin("nonexistent-plugin") - assert result is None - - def test_load_plugin_loader(self): - """测试加载 plugin-loader 核心插件""" - loader = PluginLoader() - result = loader.load_core_plugin("plugin-loader") - - assert result is not None - assert "instance" in result - assert "module" in result - assert "path" in result - assert "name" in result - assert result["name"] == "plugin-loader" - assert hasattr(result["instance"], "init") - assert hasattr(result["instance"], "start") - assert hasattr(result["instance"], "stop") - - def test_loaded_plugins_tracking(self): - """测试已加载插件跟踪""" - loader = PluginLoader() - initial_count = len(loader.loaded) - - loader.load_core_plugin("plugin-loader") - - assert len(loader.loaded) == initial_count + 1 - assert "plugin-loader" in loader.loaded - - -if __name__ == "__main__": - pytest.main([__file__, "-v"]) diff --git a/tests/test_plugin_manager.py b/tests/test_plugin_manager.py deleted file mode 100644 index 8656d9a..0000000 --- a/tests/test_plugin_manager.py +++ /dev/null @@ -1,53 +0,0 @@ -"""插件管理器单元测试""" -import pytest -from oss.plugin.manager import PluginManager - - -class TestPluginManager: - """测试插件管理器核心功能""" - - def test_manager_initialization(self): - """测试管理器初始化""" - manager = PluginManager() - assert manager.plugin_loader is None - assert manager.loader is not None - - def test_manager_load(self): - """测试管理器加载 plugin-loader""" - manager = PluginManager() - manager.load() - - assert manager.plugin_loader is not None - assert hasattr(manager.plugin_loader, "init") - assert hasattr(manager.plugin_loader, "start") - assert hasattr(manager.plugin_loader, "stop") - - def test_manager_start_without_load(self): - """测试未加载时启动(应安全处理)""" - manager = PluginManager() - # 不应抛出异常 - manager.start() - - def test_manager_stop_without_load(self): - """测试未加载时停止(应安全处理)""" - manager = PluginManager() - # 不应抛出异常 - manager.stop() - - def test_manager_lifecycle(self): - """测试完整生命周期""" - manager = PluginManager() - - # 加载 - manager.load() - assert manager.plugin_loader is not None - - # 启动(会初始化所有插件) - # 注意:实际启动需要完整环境,这里只测试方法存在 - assert callable(manager.plugin_loader.init) - assert callable(manager.plugin_loader.start) - assert callable(manager.plugin_loader.stop) - - -if __name__ == "__main__": - pytest.main([__file__, "-v"]) diff --git a/tools/__pycache__/sign_core_plugins.cpython-312.pyc b/tools/__pycache__/sign_core_plugins.cpython-312.pyc deleted file mode 100644 index 4cf7f17..0000000 Binary files a/tools/__pycache__/sign_core_plugins.cpython-312.pyc and /dev/null differ diff --git a/tools/__pycache__/sign_plugin_loader.cpython-312.pyc b/tools/__pycache__/sign_plugin_loader.cpython-312.pyc deleted file mode 100644 index a44e864..0000000 Binary files a/tools/__pycache__/sign_plugin_loader.cpython-312.pyc and /dev/null differ diff --git a/tools/__pycache__/sign_plugins.cpython-312.pyc b/tools/__pycache__/sign_plugins.cpython-312.pyc deleted file mode 100644 index 57607e6..0000000 Binary files a/tools/__pycache__/sign_plugins.cpython-312.pyc and /dev/null differ diff --git a/tools/__pycache__/sign_single_plugin.cpython-312.pyc b/tools/__pycache__/sign_single_plugin.cpython-312.pyc deleted file mode 100644 index 19bb313..0000000 Binary files a/tools/__pycache__/sign_single_plugin.cpython-312.pyc and /dev/null differ diff --git a/tools/__pycache__/test_signature.cpython-312.pyc b/tools/__pycache__/test_signature.cpython-312.pyc deleted file mode 100644 index 1a84f4b..0000000 Binary files a/tools/__pycache__/test_signature.cpython-312.pyc and /dev/null differ diff --git a/tools/sign_core_plugins.py b/tools/sign_core_plugins.py deleted file mode 100644 index fbc4acc..0000000 --- a/tools/sign_core_plugins.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env python3 -""" -为 dependency 和 signature-verifier 插件签名 -""" - -import sys -import json -import base64 -import hashlib -import time -from pathlib import Path - -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import padding -from cryptography.hazmat.backends import default_backend - -# ========== 配置 ========== -PROJECT_ROOT = Path(__file__).parent.parent -PRIVATE_KEY_FILE = PROJECT_ROOT / "data" / "signature-verifier" / "keys" / "private" / "futureoss_private.pem" - -PLUGINS = ["dependency", "signature-verifier"] - - -def compute_plugin_hash(plugin_dir: Path) -> str: - """计算插件目录的内容哈希""" - hasher = hashlib.sha256() - files_to_hash = [] - for file_path in sorted(plugin_dir.rglob("*")): - if file_path.is_file() and file_path.name != "SIGNATURE": - rel_path = file_path.relative_to(plugin_dir) - files_to_hash.append((str(rel_path), file_path)) - - for rel_path, file_path in files_to_hash: - hasher.update(rel_path.encode("utf-8")) - hasher.update(file_path.read_bytes()) - - return hasher.hexdigest() - - -def sign_plugin(plugin_dir: Path): - """为插件签名""" - # 加载私钥 - print(f"加载私钥: {PRIVATE_KEY_FILE}") - private_key = serialization.load_pem_private_key( - PRIVATE_KEY_FILE.read_bytes(), - password=None, - backend=default_backend() - ) - - # 计算插件哈希 - print(f"计算插件目录哈希: {plugin_dir.name}...") - plugin_hash = compute_plugin_hash(plugin_dir) - print(f"哈希: {plugin_hash}") - - # 签名 - signed_data = f"FutureOSS:{plugin_hash}".encode("utf-8") - signature = private_key.sign( - signed_data, - padding.PSS( - mgf=padding.MGF1(hashes.SHA256()), - salt_length=padding.PSS.MAX_LENGTH - ), - hashes.SHA256() - ) - - # 写入签名文件 - sig_data = { - "signature": base64.b64encode(signature).decode(), - "signer": "FutureOSS", - "algorithm": "RSA-SHA256", - "timestamp": time.time(), - "plugin_hash": plugin_hash, - "author": "FutureOSS" - } - - signature_file = plugin_dir / "SIGNATURE" - signature_file.write_text(json.dumps(sig_data, indent=2)) - print(f"✓ 已签名: {plugin_dir.name}") - - -def main(): - if not PRIVATE_KEY_FILE.exists(): - print(f"错误: 私钥文件不存在: {PRIVATE_KEY_FILE}") - sys.exit(1) - - store_dir = PROJECT_ROOT / "store" / "@{FutureOSS}" - - for plugin_name in PLUGINS: - plugin_dir = store_dir / plugin_name - if plugin_dir.exists(): - sign_plugin(plugin_dir) - else: - print(f"警告: 插件目录不存在: {plugin_dir}") - - print("\n完成!") - - -if __name__ == "__main__": - main() diff --git a/tools/sign_plugin_loader.py b/tools/sign_plugin_loader.py deleted file mode 100644 index f9914b6..0000000 --- a/tools/sign_plugin_loader.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python3 -""" -为 plugin-loader 插件签名 -""" - -import sys -import json -import base64 -import hashlib -import time -from pathlib import Path - -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import padding -from cryptography.hazmat.backends import default_backend - -# ========== 配置 ========== -PROJECT_ROOT = Path(__file__).parent.parent -PRIVATE_KEY_FILE = PROJECT_ROOT / "data" / "signature-verifier" / "keys" / "private" / "futureoss_private.pem" -PLUGIN_DIR = PROJECT_ROOT / "store" / "@{FutureOSS}" / "plugin-loader" - - -def compute_plugin_hash(plugin_dir: Path) -> str: - """计算插件目录的内容哈希""" - hasher = hashlib.sha256() - files_to_hash = [] - for file_path in sorted(plugin_dir.rglob("*")): - if file_path.is_file() and file_path.name != "SIGNATURE": - rel_path = file_path.relative_to(plugin_dir) - files_to_hash.append((str(rel_path), file_path)) - - for rel_path, file_path in files_to_hash: - hasher.update(rel_path.encode("utf-8")) - hasher.update(file_path.read_bytes()) - - return hasher.hexdigest() - - -def sign_plugin(): - """为插件签名""" - # 加载私钥 - print(f"加载私钥: {PRIVATE_KEY_FILE}") - private_key = serialization.load_pem_private_key( - PRIVATE_KEY_FILE.read_bytes(), - password=None, - backend=default_backend() - ) - - # 计算插件哈希 - print(f"计算插件目录哈希...") - plugin_hash = compute_plugin_hash(PLUGIN_DIR) - print(f"哈希: {plugin_hash}") - - # 签名 - signed_data = f"FutureOSS:{plugin_hash}".encode("utf-8") - signature = private_key.sign( - signed_data, - padding.PSS( - mgf=padding.MGF1(hashes.SHA256()), - salt_length=padding.PSS.MAX_LENGTH - ), - hashes.SHA256() - ) - - # 写入签名文件 - sig_data = { - "signature": base64.b64encode(signature).decode(), - "signer": "FutureOSS", - "algorithm": "RSA-SHA256", - "timestamp": time.time(), - "plugin_hash": plugin_hash, - "author": "FutureOSS" - } - - signature_file = PLUGIN_DIR / "SIGNATURE" - signature_file.write_text(json.dumps(sig_data, indent=2)) - print(f"\n✓ 签名成功!") - print(f" 插件: {PLUGIN_DIR.name}") - print(f" 签名文件: {signature_file}") - print(f" 算法: RSA-SHA256") - print(f" 时间戳: {time.strftime('%Y-%m-%d %H:%M:%S')}") - - -if __name__ == "__main__": - try: - from cryptography.hazmat.primitives import hashes, serialization - from cryptography.hazmat.primitives.asymmetric import padding - from cryptography.hazmat.backends import default_backend - except ImportError: - print("错误: 未安装 cryptography 库") - print("运行: pip install cryptography") - sys.exit(1) - - if not PLUGIN_DIR.exists(): - print(f"错误: 插件目录不存在: {PLUGIN_DIR}") - sys.exit(1) - - if not PRIVATE_KEY_FILE.exists(): - print(f"错误: 私钥文件不存在: {PRIVATE_KEY_FILE}") - sys.exit(1) - - sign_plugin() diff --git a/tools/sign_plugins.py b/tools/sign_plugins.py deleted file mode 100644 index 80ff3a3..0000000 --- a/tools/sign_plugins.py +++ /dev/null @@ -1,193 +0,0 @@ -#!/usr/bin/env python3 -""" -密钥生成与插件签名工具 -- 生成 Falck 官方密钥对 -- 为所有官方插件签名 -""" - -import sys -import json -import base64 -import hashlib -import time -from pathlib import Path - -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import padding, rsa -from cryptography.hazmat.backends import default_backend - -# ========== 配置 ========== -PROJECT_ROOT = Path(__file__).parent.parent # 修复:tools 的上级目录 -KEY_DIR = PROJECT_ROOT / "data" / "signature-verifier" / "keys" -STORE_DIR = PROJECT_ROOT / "store" - -# 官方作者目录 -OFFICIAL_AUTHORS = ["FutureOSS", "Falck"] - - -def generate_keypair(author: str): - """生成 4096 位 RSA 密钥对""" - print(f"\n{'='*60}") - print(f"生成 {author} 的密钥对...") - print(f"{'='*60}") - - private_key = rsa.generate_private_key( - public_exponent=65537, - key_size=4096, - backend=default_backend() - ) - public_key = private_key.public_key() - - # 保存私钥 - private_pem = private_key.private_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PrivateFormat.PKCS8, - encryption_algorithm=serialization.NoEncryption() - ) - priv_dir = KEY_DIR / "private" - priv_dir.mkdir(parents=True, exist_ok=True) - priv_file = priv_dir / f"{author.lower()}_private.pem" - priv_file.write_bytes(private_pem) - print(f"私钥已保存: {priv_file}") - - # 保存公钥 - public_pem = public_key.public_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PublicFormat.SubjectPublicKeyInfo - ) - pub_dir = KEY_DIR / "public" - pub_dir.mkdir(parents=True, exist_ok=True) - pub_file = pub_dir / f"{author}.pem" - pub_file.write_bytes(public_pem) - print(f"公钥已保存: {pub_file}") - - # 显示公钥(用于嵌入代码) - print(f"\n--- 公钥 PEM (用于嵌入 main.py) ---") - print(public_pem.decode()) - print(f"--- END ---\n") - - return private_key, public_key - - -def compute_plugin_hash(plugin_dir: Path) -> str: - """计算插件目录的内容哈希""" - hasher = hashlib.sha256() - files_to_hash = [] - for file_path in sorted(plugin_dir.rglob("*")): - if file_path.is_file() and file_path.name != "SIGNATURE": - rel_path = file_path.relative_to(plugin_dir) - files_to_hash.append((str(rel_path), file_path)) - - for rel_path, file_path in files_to_hash: - hasher.update(rel_path.encode("utf-8")) - hasher.update(file_path.read_bytes()) - - return hasher.hexdigest() - - -def sign_plugin(plugin_dir: Path, private_key, signer_name: str, author: str): - """为插件生成签名""" - plugin_hash = compute_plugin_hash(plugin_dir) - - # 签名 - signed_data = f"{author}:{plugin_hash}".encode("utf-8") - signature = private_key.sign( - signed_data, - padding.PSS( - mgf=padding.MGF1(hashes.SHA256()), - salt_length=padding.PSS.MAX_LENGTH - ), - hashes.SHA256() - ) - - # 写入签名文件 - sig_data = { - "signature": base64.b64encode(signature).decode(), - "signer": signer_name, - "algorithm": "RSA-SHA256", - "timestamp": time.time(), - "plugin_hash": plugin_hash, - "author": author - } - - signature_file = plugin_dir / "SIGNATURE" - signature_file.write_text(json.dumps(sig_data, indent=2)) - print(f" ✓ 已签名: {plugin_dir.name} (哈希: {plugin_hash[:16]}...)") - - -def sign_all_plugins(private_key): - """为所有官方插件签名""" - for author in OFFICIAL_AUTHORS: - author_dir = STORE_DIR / f"@{{{author}}}" - if not author_dir.exists(): - print(f"\n警告: 作者目录不存在: {author_dir}") - continue - - print(f"\n{'='*60}") - print(f"为 @{{{author}}} 的插件签名...") - print(f"{'='*60}") - - count = 0 - for plugin_dir in sorted(author_dir.iterdir()): - if plugin_dir.is_dir() and (plugin_dir / "manifest.json").exists(): - sign_plugin(plugin_dir, private_key, author, author) - count += 1 - - print(f"\n完成: 已签名 {count} 个 @{author} 插件") - - -def main(): - print("="*60) - print("FutureOSS 插件签名工具") - print("="*60) - - # 检查 cryptography - try: - from cryptography.hazmat.primitives import hashes, serialization - from cryptography.hazmat.primitives.asymmetric import padding, rsa - from cryptography.hazmat.backends import default_backend - except ImportError: - print("错误: 未安装 cryptography 库") - print("运行: pip install cryptography") - sys.exit(1) - - # 步骤 1: 生成密钥对 - print("\n步骤 1: 生成 Falck 官方密钥对...") - falck_priv, falck_pub = generate_keypair("Falck") - - print("\n步骤 1b: 生成 FutureOSS 官方密钥对...") - foss_priv, foss_pub = generate_keypair("FutureOSS") - - # 步骤 2: 为所有官方插件签名(使用对应的密钥) - print("\n步骤 2: 为所有官方插件签名...") - - # Falck 的插件用 Falck 密钥签名 - falck_dir = STORE_DIR / "@{Falck}" - if falck_dir.exists(): - print(f"\n{'='*60}") - print("为 @{Falck} 的插件使用 Falck 密钥签名...") - print(f"{'='*60}") - for plugin_dir in sorted(falck_dir.iterdir()): - if plugin_dir.is_dir() and (plugin_dir / "manifest.json").exists(): - sign_plugin(plugin_dir, falck_priv, "Falck", "Falck") - - # FutureOSS 的插件用 FutureOSS 密钥签名 - foss_dir = STORE_DIR / "@{FutureOSS}" - if foss_dir.exists(): - print(f"\n{'='*60}") - print("为 @{FutureOSS} 的插件使用 FutureOSS 密钥签名...") - print(f"{'='*60}") - for plugin_dir in sorted(foss_dir.iterdir()): - if plugin_dir.is_dir() and (plugin_dir / "manifest.json").exists(): - sign_plugin(plugin_dir, foss_priv, "FutureOSS", "FutureOSS") - - print("\n" + "="*60) - print("全部完成!") - print("="*60) - print(f"\n密钥位置: {KEY_DIR}") - print("请将公钥嵌入 signature-verifier/main.py 的 FALCK_PUBLIC_KEY_PEM 变量") - print("并妥善保管私钥,不要提交到版本控制系统!") - - -if __name__ == "__main__": - main() diff --git a/tools/sign_single_plugin.py b/tools/sign_single_plugin.py deleted file mode 100644 index cfe32b2..0000000 --- a/tools/sign_single_plugin.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python3 -""" -为单个插件签名 -""" - -import sys -import json -import base64 -import hashlib -import time -from pathlib import Path - -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import padding -from cryptography.hazmat.backends import default_backend - -# ========== 配置 ========== -PROJECT_ROOT = Path(__file__).parent.parent -PRIVATE_KEY_FILE = PROJECT_ROOT / "data" / "signature-verifier" / "keys" / "private" / "futureoss_private.pem" -PLUGIN_DIR = PROJECT_ROOT / "store" / "@{FutureOSS}" / "log-terminal" - - -def compute_plugin_hash(plugin_dir: Path) -> str: - """计算插件目录的内容哈希""" - hasher = hashlib.sha256() - files_to_hash = [] - for file_path in sorted(plugin_dir.rglob("*")): - if file_path.is_file() and file_path.name != "SIGNATURE": - rel_path = file_path.relative_to(plugin_dir) - files_to_hash.append((str(rel_path), file_path)) - - for rel_path, file_path in files_to_hash: - hasher.update(rel_path.encode("utf-8")) - hasher.update(file_path.read_bytes()) - - return hasher.hexdigest() - - -def sign_plugin(): - """为插件签名""" - # 加载私钥 - print(f"加载私钥: {PRIVATE_KEY_FILE}") - private_key = serialization.load_pem_private_key( - PRIVATE_KEY_FILE.read_bytes(), - password=None, - backend=default_backend() - ) - - # 计算插件哈希 - print(f"计算插件目录哈希...") - plugin_hash = compute_plugin_hash(PLUGIN_DIR) - print(f"哈希: {plugin_hash}") - - # 签名 - signed_data = f"FutureOSS:{plugin_hash}".encode("utf-8") - signature = private_key.sign( - signed_data, - padding.PSS( - mgf=padding.MGF1(hashes.SHA256()), - salt_length=padding.PSS.MAX_LENGTH - ), - hashes.SHA256() - ) - - # 写入签名文件 - sig_data = { - "signature": base64.b64encode(signature).decode(), - "signer": "FutureOSS", - "algorithm": "RSA-SHA256", - "timestamp": time.time(), - "plugin_hash": plugin_hash, - "author": "FutureOSS" - } - - signature_file = PLUGIN_DIR / "SIGNATURE" - signature_file.write_text(json.dumps(sig_data, indent=2)) - print(f"\n✓ 签名成功!") - print(f" 插件: {PLUGIN_DIR.name}") - print(f" 签名文件: {signature_file}") - print(f" 算法: RSA-SHA256") - print(f" 时间戳: {time.strftime('%Y-%m-%d %H:%M:%S')}") - - -if __name__ == "__main__": - try: - from cryptography.hazmat.primitives import hashes, serialization - from cryptography.hazmat.primitives.asymmetric import padding - from cryptography.hazmat.backends import default_backend - except ImportError: - print("错误: 未安装 cryptography 库") - print("运行: pip install cryptography") - sys.exit(1) - - if not PLUGIN_DIR.exists(): - print(f"错误: 插件目录不存在: {PLUGIN_DIR}") - sys.exit(1) - - if not PRIVATE_KEY_FILE.exists(): - print(f"错误: 私钥文件不存在: {PRIVATE_KEY_FILE}") - sys.exit(1) - - sign_plugin() diff --git a/tools/test_signature.py b/tools/test_signature.py deleted file mode 100644 index beea771..0000000 --- a/tools/test_signature.py +++ /dev/null @@ -1,199 +0,0 @@ -#!/usr/bin/env python3 -""" -签名验证测试脚本 -测试签名验证功能是否正常工作 -""" - -import sys -import json -import base64 -import hashlib -from pathlib import Path - -# 添加项目路径 -sys.path.insert(0, str(Path(__file__).parent.parent)) -sys.path.insert(0, str(Path(__file__).parent.parent / "store/@{FutureOSS}/signature-verifier")) - -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import padding -from cryptography.hazmat.backends import default_backend -from cryptography.exceptions import InvalidSignature - -# 导入签名验证插件 -from main import SignatureVerifier, SignatureSigner - - -def test_verify_official_plugins(): - """测试验证所有已签名的官方插件""" - print("="*60) - print("测试 1: 验证所有官方插件签名") - print("="*60) - - store_dir = Path(__file__).parent.parent / "store" - verifier = SignatureVerifier(key_dir="./data/signature-verifier/keys") - - authors = ["FutureOSS", "Falck"] - total = 0 - passed = 0 - failed = 0 - - for author in authors: - author_dir = store_dir / f"@{{{author}}}" - if not author_dir.exists(): - continue - - print(f"\n--- @{author} ---") - for plugin_dir in sorted(author_dir.iterdir()): - if plugin_dir.is_dir() and (plugin_dir / "manifest.json").exists(): - total += 1 - valid, msg = verifier.verify_plugin(plugin_dir, author) - status = "✅ 通过" if valid else "❌ 失败" - print(f" {status}: {plugin_dir.name} - {msg}") - if valid: - passed += 1 - else: - failed += 1 - - print(f"\n{'='*60}") - print(f"结果: {passed}/{total} 通过, {failed} 失败") - print(f"{'='*60}") - return failed == 0 - - -def test_tamper_detection(): - """测试篡改检测""" - print("\n" + "="*60) - print("测试 2: 篡改检测") - print("="*60) - - store_dir = Path(__file__).parent.parent / "store" - verifier = SignatureVerifier(key_dir="./data/signature-verifier/keys") - - # 选择一个测试插件 - test_plugin = store_dir / "@{FutureOSS}" / "dashboard" - if not test_plugin.exists(): - print("跳过: dashboard 插件不存在") - return True - - # 验证原始签名 - valid_before, msg_before = verifier.verify_plugin(test_plugin, "FutureOSS") - print(f"\n篡改前: {'✅ 有效' if valid_before else '❌ 无效'} - {msg_before}") - - if not valid_before: - print("警告: 原始签名已无效,跳过篡改测试") - return False - - # 创建一个临时篡改文件 - tamper_file = test_plugin / "__tamper_test__.tmp" - tamper_file.write_text("tampered content") - - # 验证篡改后的签名 - valid_after, msg_after = verifier.verify_plugin(test_plugin, "FutureOSS") - print(f"篡改后: {'✅ 有效' if valid_after else '❌ 无效'} - {msg_after}") - - # 清理 - tamper_file.unlink() - - # 再次验证应该恢复有效 - valid_clean, msg_clean = verifier.verify_plugin(test_plugin, "FutureOSS") - print(f"清理后: {'✅ 有效' if valid_clean else '❌ 无效'} - {msg_clean}") - - # 预期:篡改后无效,清理后有效 - success = not valid_after and valid_clean - print(f"\n{'='*60}") - print(f"篡改检测: {'✅ 成功' if success else '❌ 失败'}") - print(f"{'='*60}") - return success - - -def test_missing_signature(): - """测试缺失签名文件""" - print("\n" + "="*60) - print("测试 3: 缺失签名检测") - print("="*60) - - store_dir = Path(__file__).parent.parent / "store" - verifier = SignatureVerifier(key_dir="./data/signature-verifier/keys") - - # 选择一个插件并临时移除签名 - test_plugin = store_dir / "@{FutureOSS}" / "json-codec" - if not test_plugin.exists(): - print("跳过: json-codec 插件不存在") - return True - - sig_file = test_plugin / "SIGNATURE" - if not sig_file.exists(): - print("跳过: json-codec 没有签名文件") - return True - - # 备份签名 - backup = sig_file.read_text() - sig_file.unlink() - - # 验证 - valid, msg = verifier.verify_plugin(test_plugin, "FutureOSS") - print(f"无签名: {'✅ 有效' if valid else '❌ 无效'} - {msg}") - - # 恢复 - sig_file.write_text(backup) - - valid_restored, msg_restored = verifier.verify_plugin(test_plugin, "FutureOSS") - print(f"恢复后: {'✅ 有效' if valid_restored else '❌ 无效'} - {msg_restored}") - - success = not valid and valid_restored - print(f"\n{'='*60}") - print(f"缺失签名检测: {'✅ 成功' if success else '❌ 失败'}") - print(f"{'='*60}") - return success - - -def test_official_check(): - """测试 is_official_plugin 方法""" - print("\n" + "="*60) - print("测试 4: 官方插件识别") - print("="*60) - - store_dir = Path(__file__).parent.parent / "store" - verifier = SignatureVerifier(key_dir="./data/signature-verifier/keys") - - # 测试官方插件 - official_plugin = store_dir / "@{FutureOSS}" / "dashboard" - is_official = verifier.is_official_plugin(official_plugin) - print(f"dashboard 是官方插件: {'✅ 是' if is_official else '❌ 否'}") - - success = is_official - print(f"\n{'='*60}") - print(f"官方插件识别: {'✅ 成功' if success else '❌ 失败'}") - print(f"{'='*60}") - return success - - -def main(): - print("FutureOSS 签名验证系统测试") - print("="*60) - - results = [] - - results.append(("官方插件验证", test_verify_official_plugins())) - results.append(("篡改检测", test_tamper_detection())) - results.append(("缺失签名检测", test_missing_signature())) - results.append(("官方插件识别", test_official_check())) - - print("\n" + "="*60) - print("测试总结") - print("="*60) - - for name, passed in results: - status = "✅ 通过" if passed else "❌ 失败" - print(f" {status}: {name}") - - all_passed = all(r[1] for r in results) - print(f"\n{'='*60}") - print(f"总体结果: {'✅ 全部通过' if all_passed else '❌ 有失败'}") - print(f"{'='*60}") - - return 0 if all_passed else 1 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/video/architecture.html b/video/architecture.html deleted file mode 100644 index 8166329..0000000 --- a/video/architecture.html +++ /dev/null @@ -1,274 +0,0 @@ - - -
- - -用动画和声音了解我们的项目
-立方体动画演示核心特性,插件化、安全性、实时监控...
-从零开发一个插件,看这里就对了
-深入了解 FutureOSS 的技术架构和设计思想
-git clone xxx
pip install -r req.txt
python -m venv .venv
source .venv/bin/activate
pip install flask mysql...
改配置文件半小时
python main.py
报错 -> 查日志 -> 改配置
python main.py
又报错...
bash start.sh
-按照规范在 store/@{作者名}/插件名/ 下创建目录
- store/@{myname}/hello-world/
- ├── main.py
- ├── manifest.json
- └── README.md
-
- 声明插件名称、版本、依赖和描述信息
-
- {
- "name": "hello-world",
- "version": "1.0.0",
- "author": "@{myname}",
- "description": "我的第一个插件"
- }
-
- 实现插件的初始化逻辑,注册路由或事件
-
- class Plugin:
- def init(self, app):
- @app.route("/hello")
- def hello():
- return {"msg": "Hello, FutureOSS!"}
-
- 运行项目,访问 http://localhost:8080/hello 验证插件是否正常工作
- bash start.sh
- curl http://localhost:8080/hello
- # → {"msg": "Hello, FutureOSS!"}
-
- 打包插件并上传到 Gitee 商店,其他人一键安装!
-
- python tools/sign_single_plugin.py @{myname}/hello-world
- # 上传到 Gitee 商店仓库
-
-