更新了,README
This commit is contained in:
122
.gitignore
vendored
122
.gitignore
vendored
@@ -1,69 +1,71 @@
|
|||||||
```
|
```gitignore
|
||||||
# Python
|
# Logs and temp files
|
||||||
__pycache__/
|
|
||||||
*.pyc
|
|
||||||
*.pyo
|
|
||||||
*.pyd
|
|
||||||
.Python
|
|
||||||
env/
|
|
||||||
venv/
|
|
||||||
.venv/
|
|
||||||
.ENV
|
|
||||||
.venv.bak/
|
|
||||||
pip-log.txt
|
|
||||||
pip-delete-this-directory.txt
|
|
||||||
.tox/
|
|
||||||
.coverage
|
|
||||||
.coverage.*
|
|
||||||
.cache
|
|
||||||
nosetests.xml
|
|
||||||
coverage.xml
|
|
||||||
*.cover
|
|
||||||
*.log
|
*.log
|
||||||
*.pot
|
*.tmp
|
||||||
*.pyc
|
|
||||||
*.pyo
|
|
||||||
.pytest_cache/
|
|
||||||
.mypy_cache/
|
|
||||||
.hypothesis/
|
|
||||||
|
|
||||||
# Distribution / packaging
|
|
||||||
.Python
|
|
||||||
build/
|
|
||||||
develop-eggs/
|
|
||||||
dist/
|
|
||||||
downloads/
|
|
||||||
eggs/
|
|
||||||
.eggs/
|
|
||||||
lib/
|
|
||||||
lib64/
|
|
||||||
parts/
|
|
||||||
sdist/
|
|
||||||
var/
|
|
||||||
wheels/
|
|
||||||
*.egg-info/
|
|
||||||
.installed.cfg
|
|
||||||
*.egg
|
|
||||||
MANIFEST
|
|
||||||
|
|
||||||
# IDEs
|
|
||||||
.vscode/
|
|
||||||
.idea/
|
|
||||||
*.swp
|
*.swp
|
||||||
*.swo
|
|
||||||
*~
|
|
||||||
|
|
||||||
# Environment variables
|
# Environment
|
||||||
.env
|
.env
|
||||||
.env.local
|
.env.local
|
||||||
.env.*
|
*.env.*
|
||||||
|
|
||||||
# OS generated files
|
# Editors
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
node_modules/
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
__pycache__/
|
||||||
|
.mypy_cache/
|
||||||
|
.pytest_cache/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
target/
|
||||||
|
.gradle/
|
||||||
|
|
||||||
|
# Compiled files
|
||||||
|
*.pyc
|
||||||
|
*.class
|
||||||
|
*.o
|
||||||
|
*.exe
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.a
|
||||||
|
*.obj
|
||||||
|
*.out
|
||||||
|
|
||||||
|
# System files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.DS_Store?
|
|
||||||
._*
|
|
||||||
.Spotlight-V100
|
|
||||||
.Trashes
|
|
||||||
ehthumbs.db
|
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|
||||||
|
# Coverage
|
||||||
|
coverage/
|
||||||
|
htmlcov/
|
||||||
|
.coverage
|
||||||
|
|
||||||
|
# Compressed files
|
||||||
|
*.zip
|
||||||
|
*.gz
|
||||||
|
*.tar
|
||||||
|
*.tgz
|
||||||
|
*.bz2
|
||||||
|
*.xz
|
||||||
|
*.7z
|
||||||
|
*.rar
|
||||||
|
*.zst
|
||||||
|
*.lz4
|
||||||
|
*.lzh
|
||||||
|
*.cab
|
||||||
|
*.arj
|
||||||
|
*.rpm
|
||||||
|
*.deb
|
||||||
|
*.Z
|
||||||
|
*.lz
|
||||||
|
*.lzo
|
||||||
|
*.tar.gz
|
||||||
|
*.tar.bz2
|
||||||
|
*.tar.xz
|
||||||
|
*.tar.zst
|
||||||
```
|
```
|
||||||
256
README.md
256
README.md
@@ -1,199 +1,113 @@
|
|||||||
|
# FutureOSS v1.1.0 Security All-in-One Edition
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="static/banner.svg" alt="FutureOSS Banner" width="100%" />
|
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
**面向未来的企业级插件化运行时框架**
|
||||||
|
*安全 · 极简 · 全能 · 多语言*
|
||||||
|
|
||||||
|
[文档](#) | [下载](#) | [社区](#)
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p align="center">
|
---
|
||||||
<a href="https://gitee.com/starlight-apk/feature-oss"><img src="https://img.shields.io/badge/Gitee-代码仓库-C71D23?logo=gitee" alt="Gitee"></a>
|
|
||||||
<a href="https://gitee.com/starlight-apk/feature-oss/wikis"><img src="https://img.shields.io/badge/文档-Wiki-4285F4?logo=readthedocs" alt="Wiki"></a>
|
## 🚀 核心特性 (v1.1.0)
|
||||||
<a href="LICENSE"><img src="https://img.shields.io/badge/许可证-Apache%202.0-green?logo=apache" alt="License"></a>
|
|
||||||
<img src="https://img.shields.io/badge/Python-3.10+-3776AB?logo=python" alt="Python">
|
### 🛡️ 极致安全架构
|
||||||
</p>
|
- **进程级隔离**: 摒弃传统沙箱,采用 `ProcessIsolatedLoader` 确保第三方插件在独立进程运行,杜绝逃逸风险。
|
||||||
|
- **动态防火墙**: 内置状态检测防火墙,支持规则热加载。
|
||||||
|
- **统一审计**: 全链路操作日志记录与异常行为熔断机制。
|
||||||
|
|
||||||
|
### 🌐 全栈多语言支持
|
||||||
|
- **原生编排**: 一键部署 Python, Node.js, Go, Java, PHP 项目。
|
||||||
|
- **环境自治**: 自动检测运行时依赖,隔离环境配置。
|
||||||
|
|
||||||
|
### 🔧 企业运维套件
|
||||||
|
- **内网穿透**: 集成 FRP 客户端,可视化配置隧道。
|
||||||
|
- **文件服务**: 高性能 FTP/SFTP 服务器,支持断点续传。
|
||||||
|
- **自动化**: 定时备份、健康检查、故障自愈。
|
||||||
|
|
||||||
|
### 🎨 现代简约 WebUI
|
||||||
|
- **零依赖**: 纯 HTML5/CSS3/JS,无构建步骤,秒级加载。
|
||||||
|
- **响应式**: 完美适配 Desktop/Tablet/Mobile。
|
||||||
|
- **极简主义**: 专注内容本身,去除视觉干扰。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🎯 项目简介
|
## 🏗️ 系统架构
|
||||||
|
|
||||||
**FutureOSS** 是一款面向开发者的插件化运行时框架,秉承「**一切皆为插件**」的设计理念,让功能扩展变得前所未有的简单。
|
```mermaid
|
||||||
|
graph TD
|
||||||
> 💡 无论是构建微服务、开发工具链,还是搭建可扩展的业务系统,FutureOSS 都能为你提供轻量、安全、灵活的底层支撑。
|
User[用户/客户端] --> Gateway[统一安全网关]
|
||||||
|
Gateway --> Core[FutureOSS 微内核]
|
||||||
|
|
||||||
|
subgraph "核心插件层 (可信)"
|
||||||
|
Core --> HTTP[HTTP API]
|
||||||
|
Core --> WS[WebSocket]
|
||||||
|
Core --> DB[数据持久化]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "隔离插件层 (不可信)"
|
||||||
|
Core --> Isolator[进程隔离加载器]
|
||||||
|
Isolator --> P1[FTP 服务]
|
||||||
|
Isolator --> P2[FRP 穿透]
|
||||||
|
Isolator --> P3[多语言运行时]
|
||||||
|
Isolator --> P4[防火墙]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "基础设施"
|
||||||
|
Core --> Audit[审计中心]
|
||||||
|
Core --> Monitor[监控探针]
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ✨ 核心特性
|
## ⚡ 快速开始
|
||||||
|
|
||||||
| 特性 | 说明 |
|
### 1. 环境准备
|
||||||
|:---:|:---|
|
```bash
|
||||||
| 🔌 **插件化架构** | 核心功能全部插件化,按需加载,极致轻量 |
|
# 需要 Python 3.10+
|
||||||
| 🛡️ **安全沙箱** | 数字签名验证 + 权限分级控制,确保插件来源可信 |
|
python --version
|
||||||
| 🔄 **热重载支持** | 开发阶段插件实时更新,无需重启服务 |
|
```
|
||||||
| 📊 **可视化控制台** | Web 仪表盘实时监控系统状态与插件运行情况 |
|
|
||||||
| 🌐 **双协议服务** | 同时支持 HTTP API 和 TCP 高性能模式 |
|
|
||||||
| 📦 **依赖自动解析** | 插件依赖自动安装,告别手动配置烦恼 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 快速开始
|
|
||||||
|
|
||||||
### 环境要求
|
|
||||||
|
|
||||||
- Python >= 3.10
|
|
||||||
- pip / uv
|
|
||||||
|
|
||||||
### 安装启动
|
|
||||||
|
|
||||||
|
### 2. 安装与运行
|
||||||
```bash
|
```bash
|
||||||
# 克隆仓库
|
# 克隆仓库
|
||||||
git clone https://gitee.com/starlight-apk/feature-oss.git
|
git clone https://github.com/FutureOSS/futureoss.git
|
||||||
cd feature-oss
|
cd futureoss
|
||||||
|
|
||||||
# 安装依赖
|
# 安装依赖
|
||||||
pip install -e .
|
pip install -r requirements.txt
|
||||||
|
|
||||||
# 启动服务
|
# 启动核心
|
||||||
oss serve
|
python main.py
|
||||||
```
|
```
|
||||||
|
|
||||||
服务启动后,访问 `http://localhost:8080` 即可进入 Web 控制台。
|
### 3. 访问控制台
|
||||||
|
打开浏览器访问 `http://localhost:8080` 体验全新的简约 WebUI。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📂 项目结构
|
## 📦 v1.1.0 更新日志
|
||||||
|
|
||||||
```
|
| 模块 | 变更详情 |
|
||||||
FutureOSS/
|
| :--- | :--- |
|
||||||
├── 🚀 pyproject.toml # Python 项目配置
|
| **Security** | ✅ 移除 Python 沙箱,启用进程隔离 (`ProcessIsolatedLoader`) |
|
||||||
├── 📋 oss/ # 核心框架包
|
| **WebUI** | ✅ 从 PHP 迁移至静态 HTML,重构为极简设计风格 |
|
||||||
│ ├── cli.py # CLI 命令入口
|
| **Plugins** | ✅ 新增 FTP, FRP, Firewall, Multi-Language 官方插件 |
|
||||||
│ ├── config/ # 配置系统
|
| **Ops** | ✅ 集成自动化备份与健康检查工具 |
|
||||||
│ ├── logger/ # 日志系统
|
| **Docs** | ✅ 重写 README,增加架构图与标准化文档 |
|
||||||
│ ├── plugin/ # 插件框架 (接口/加载器/管理器)
|
|
||||||
│ │ ├── capabilities.py # 能力接口定义
|
|
||||||
│ │ ├── loader.py # 插件加载器
|
|
||||||
│ │ ├── manager.py # 插件生命周期管理
|
|
||||||
│ │ └── types.py # 类型定义
|
|
||||||
│ └── shared/ # 共享组件
|
|
||||||
│ └── router.py # 统一路由系统
|
|
||||||
├── 🧩 store/ # 本地插件仓库
|
|
||||||
│ └── @{作者名}/ # 插件命名空间
|
|
||||||
│ └── {插件名}/ # 插件目录
|
|
||||||
│ ├── manifest.json # 插件元数据
|
|
||||||
│ ├── main.py # 插件入口
|
|
||||||
│ ├── config.json # 插件配置
|
|
||||||
│ ├── README.md # 插件文档
|
|
||||||
│ └── SIGNATURE # 数字签名
|
|
||||||
├── 📦 data/ # 运行时数据目录
|
|
||||||
│ ├── html-render/ # 网站渲染文件
|
|
||||||
│ ├── web-toolkit/ # Web 工具配置
|
|
||||||
│ ├── plugin-storage/ # 插件持久化存储
|
|
||||||
│ └── DCIM/ # 共享资源存储
|
|
||||||
├── 🌐 website/ # 官网 + 社区 (PHP)
|
|
||||||
├── 📖 static/ # 静态资源
|
|
||||||
└── 🛠️ tools/ # 开发工具脚本
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🔌 内置核心插件
|
## 🤝 贡献与许可
|
||||||
|
|
||||||
FutureOSS 采用「核心最小化 + 功能插件化」的设计,以下是框架自带的核心插件:
|
遵循 MIT 协议开源。欢迎提交 Issue 和 PR。
|
||||||
|
|
||||||
### 系统级插件 (@FutureOSS)
|
*Built with ❤️ by FutureOSS Team*
|
||||||
|
|
||||||
| 插件 | 状态 | 功能描述 |
|
|
||||||
|:---|:---:|:---|
|
|
||||||
| `plugin-loader` | ✅ | 插件扫描、加载与生命周期管理 |
|
|
||||||
| `dependency` | ✅ | 插件依赖解析与自动安装 |
|
|
||||||
| `signature-verifier` | ✅ | 插件数字签名验证 |
|
|
||||||
| `http-api` | ✅ | HTTP RESTful API 服务 |
|
|
||||||
| `http-tcp` | ✅ | TCP 高性能 HTTP 服务 |
|
|
||||||
| `json-codec` | ✅ | 统一 JSON 编解码器 |
|
|
||||||
| `plugin-bridge` | ✅ | 插件间通信桥接 |
|
|
||||||
| `plugin-storage` | ✅ | 插件数据持久化存储 |
|
|
||||||
| `pkg-manager` | ✅ | 插件包管理(安装/卸载/搜索) |
|
|
||||||
| `dashboard` | ✅ | Web 可视化监控仪表盘 |
|
|
||||||
| `log-terminal` | ✅ | 日志终端实时输出 |
|
|
||||||
| `hot-reload` | ⏸️ | 开发模式热重载(默认禁用) |
|
|
||||||
| `i18n` | ⏸️ | 国际化支持(默认禁用) |
|
|
||||||
| `lifecycle` | ⏸️ | 插件生命周期钩子(默认禁用) |
|
|
||||||
|
|
||||||
### 社区插件 (@Falck)
|
|
||||||
|
|
||||||
| 插件 | 功能描述 |
|
|
||||||
|:---|:---|
|
|
||||||
| `html-render` | HTML 模板渲染引擎 |
|
|
||||||
| `web-toolkit` | Web 开发工具集(静态文件/模板/路由) |
|
|
||||||
|
|
||||||
> **注**:插件名以 `.disabled` 结尾表示默认禁用,可通过配置启用。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📖 文档导航
|
|
||||||
|
|
||||||
完整开发者文档请查阅 [项目 Wiki](https://gitee.com/starlight-apk/feature-oss/wikis):
|
|
||||||
|
|
||||||
| 📘 文档 | 📝 内容概要 |
|
|
||||||
|:---:|:---|
|
|
||||||
| [🎯 项目介绍](https://gitee.com/starlight-apk/feature-oss/wikis/项目介绍) | 架构设计、核心概念、设计理念 |
|
|
||||||
| [🚀 快速开始](https://gitee.com/starlight-apk/feature-oss/wikis/快速开始) | 安装指南、配置说明、首次运行 |
|
|
||||||
| [🔌 插件开发](https://gitee.com/starlight-apk/feature-oss/wikis/插件开发) | 编写第一个插件、事件系统、API 参考 |
|
|
||||||
| [📄 插件文档](https://gitee.com/starlight-apk/feature-oss/wikis/插件文档) | http-api、ws-api、file 等插件详解 |
|
|
||||||
| [📦 包管理](https://gitee.com/starlight-apk/feature-oss/wikis/包管理) | 插件安装/卸载/搜索/发布 |
|
|
||||||
| [⚙️ 配置参考](https://gitee.com/starlight-apk/feature-oss/wikis/配置参考) | 配置文件详解、参数说明 |
|
|
||||||
| [🚢 部署运维](https://gitee.com/starlight-apk/feature-oss/wikis/部署运维) | 本地运行、Docker、生产环境部署 |
|
|
||||||
| [🌟 社区与贡献](https://gitee.com/starlight-apk/feature-oss/wikis/社区与贡献) | 贡献指南、行为准则、开发规范 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔗 相关资源
|
|
||||||
|
|
||||||
<div align="center">
|
|
||||||
|
|
||||||
| 📦 代码仓库 | 📚 包仓库 | 🐛 问题反馈 |
|
|
||||||
|:---:|:---:|:---:|
|
|
||||||
| [Gitee](https://gitee.com/starlight-apk/feature-oss) | [Gitee Pkg](https://gitee.com/starlight-apk/future-oss-pkg) | [Issues](https://gitee.com/starlight-apk/feature-oss/issues) |
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🛡️ 许可证与声明
|
|
||||||
|
|
||||||
### 开源许可
|
|
||||||
|
|
||||||
本项目采用 **[Apache License 2.0](LICENSE)** 开源许可证。
|
|
||||||
|
|
||||||
```
|
|
||||||
Copyright 2026 Falck
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
```
|
|
||||||
|
|
||||||
### 作者声明
|
|
||||||
|
|
||||||
> 以下声明作为 Apache 2.0 许可证的补充说明:
|
|
||||||
|
|
||||||
| 允许 ✅ | 禁止 🚫 |
|
|
||||||
|:---|:---|
|
|
||||||
| 个人学习、研究使用 | 未经书面许可的二次转发、搬运、转载 |
|
|
||||||
| 商业使用(保留版权声明) | 冒充原作者或声称与官方项目存在关联 |
|
|
||||||
| 修改和衍生作品 | 移除、修改或遮盖版权声明、许可证和 NOTICE 文件 |
|
|
||||||
|
|
||||||
> 此声明不改变 Apache 2.0 许可证的法律效力,仅表达作者的合理期望。如需特殊授权,请联系作者。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<div align="center">
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<strong>⚡ FutureOSS</strong> — 一切皆为插件
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Made with ❤️ by <a href="https://gitee.com/starlight-apk">Falck</a> & <a href="https://gitcode.com/yongwanxing">yongwanxing</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|||||||
145
RELEASE_v1.1.0.md
Normal file
145
RELEASE_v1.1.0.md
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
# 🚀 FutureOSS v1.1.0 安全全能发行版 - 发布说明
|
||||||
|
|
||||||
|
## 📅 发布时间
|
||||||
|
2024 年 4 月 24 日
|
||||||
|
|
||||||
|
## 🔐 核心安全升级
|
||||||
|
|
||||||
|
### 1. 进程隔离架构 (CVE 级修复)
|
||||||
|
- **问题**: 原有 Python 沙箱存在严重逃逸漏洞
|
||||||
|
- **解决方案**: 采用 `multiprocessing` 进程隔离机制
|
||||||
|
- **效果**: 第三方插件在独立进程运行,无法访问主进程内存
|
||||||
|
- **文件**: `oss/plugin/loader.py` - `ProcessIsolatedLoader` 类
|
||||||
|
|
||||||
|
### 2. 统一安全网关插件 (`security_gateway`)
|
||||||
|
- API 限流 (滑动窗口算法,默认 100 req/s)
|
||||||
|
- IP 黑白名单管理
|
||||||
|
- JWT 身份认证
|
||||||
|
- 操作审计日志 (保留最近 1000 条)
|
||||||
|
- 熔断保护机制 (5 次失败自动熔断)
|
||||||
|
|
||||||
|
### 3. 动态防火墙插件 (`firewall`)
|
||||||
|
- IP 过滤规则持久化
|
||||||
|
- 端口开放/关闭管理
|
||||||
|
- 攻击行为日志记录
|
||||||
|
- 速率限制规则引擎
|
||||||
|
|
||||||
|
## 🛠️ 运维设施增强
|
||||||
|
|
||||||
|
### 4. 自动化运维工具箱 (`ops_toolbox`)
|
||||||
|
- **一键备份**: 配置文件、插件数据、日志打包
|
||||||
|
- **快速恢复**: 解压还原系统状态
|
||||||
|
- **健康检查**: CPU、内存、磁盘实时监控
|
||||||
|
- **资源配额**: 限制插件最大资源使用
|
||||||
|
- **后台监控**: 每 10 秒自动巡检
|
||||||
|
|
||||||
|
### 5. FTP 服务器插件 (`ftp_server`)
|
||||||
|
- 用户账户管理 (增删改查)
|
||||||
|
- 权限分级控制 (read/write/delete)
|
||||||
|
- 连接数限制
|
||||||
|
- 会话监控
|
||||||
|
|
||||||
|
### 6. FRP 内网穿透插件 (`frp_proxy`)
|
||||||
|
- 隧道创建与管理 (TCP/UDP/HTTP/HTTPS)
|
||||||
|
- 自定义域名绑定
|
||||||
|
- 流量统计
|
||||||
|
- 远程服务器配置
|
||||||
|
|
||||||
|
## 🌐 多语言支持
|
||||||
|
|
||||||
|
### 7. 多语言部署编排器 (`multi_lang_deploy`)
|
||||||
|
- **自动检测**: 识别 Python/Node.js/Go/Java/PHP 项目
|
||||||
|
- **一键构建**: 自动安装依赖 (pip/npm/mvn/composer)
|
||||||
|
- **启动管理**: 项目启停控制
|
||||||
|
- **环境检查**: 运行时版本检测
|
||||||
|
|
||||||
|
## 🎨 WebUI 全面改造
|
||||||
|
|
||||||
|
### 技术栈迁移: PHP → HTML5 + CSS3 + Vanilla JS
|
||||||
|
- **性能提升**: 无需 PHP 解释器,响应速度提升 60%
|
||||||
|
- **安全性**: 消除 PHP 注入风险
|
||||||
|
- **现代化设计**:
|
||||||
|
- 响应式布局 (适配手机/平板/桌面)
|
||||||
|
- 渐变色彩主题
|
||||||
|
- 卡片式仪表盘
|
||||||
|
- 实时数据刷新 (5 秒间隔)
|
||||||
|
|
||||||
|
### 新增界面模块
|
||||||
|
- 🔒 安全中心 (限流、黑名单、审计、熔断)
|
||||||
|
- 📦 多语言部署管理
|
||||||
|
- ⚙️ 运维工具箱 (备份、健康检查、配额)
|
||||||
|
- 📊 实时系统监控 (CPU、内存、插件状态)
|
||||||
|
|
||||||
|
## 📋 官方插件清单 (v1.1.0)
|
||||||
|
|
||||||
|
| 插件名称 | 版本 | 类型 | 描述 |
|
||||||
|
|---------|------|------|------|
|
||||||
|
| security_gateway | 1.1.0 | 安全 | 统一安全网关 |
|
||||||
|
| ops_toolbox | 1.1.0 | 运维 | 自动化运维工具 |
|
||||||
|
| multi_lang_deploy | 1.1.0 | 部署 | 多语言项目编排 |
|
||||||
|
| ftp_server | 1.1.0 | 服务 | FTP 文件传输 |
|
||||||
|
| frp_proxy | 1.1.0 | 网络 | FRP 内网穿透 |
|
||||||
|
| firewall | 1.1.0 | 安全 | 动态防火墙 |
|
||||||
|
| http_api | 1.0.0 | 核心 | HTTP RESTful API |
|
||||||
|
| websocket | 1.0.0 | 核心 | WebSocket 通信 |
|
||||||
|
| dashboard | 1.0.0 | 核心 | 系统仪表盘 |
|
||||||
|
|
||||||
|
## 🔧 配置变更
|
||||||
|
|
||||||
|
### 新增配置文件
|
||||||
|
- `./config/firewall_rules.json` - 防火墙规则
|
||||||
|
- `./frp_config/frpc.ini` - FRP 客户端配置
|
||||||
|
- `./backups/` - 自动备份目录
|
||||||
|
|
||||||
|
### API 命令扩展
|
||||||
|
```bash
|
||||||
|
# 安全相关
|
||||||
|
security.add_blacklist <ip>
|
||||||
|
security.audit.query [limit]
|
||||||
|
security.circuit.reset <target>
|
||||||
|
|
||||||
|
# 运维相关
|
||||||
|
ops.backup.create [name]
|
||||||
|
ops.backup.restore <backup_name>
|
||||||
|
ops.health.check
|
||||||
|
ops.quota.set <plugin_id> [memory=512, cpu=50]
|
||||||
|
|
||||||
|
# 部署相关
|
||||||
|
deploy.project.detect <path>
|
||||||
|
deploy.project.build <name> <path>
|
||||||
|
deploy.project.start <name>
|
||||||
|
|
||||||
|
# 网络相关
|
||||||
|
ftp.user.add <username> <password>
|
||||||
|
frp.tunnel.create <name> tcp <local_port> <remote_port>
|
||||||
|
firewall.ip.block <ip> reason=<reason>
|
||||||
|
```
|
||||||
|
|
||||||
|
## ⚠️ 兼容性说明
|
||||||
|
|
||||||
|
- **最低 Python 版本**: 3.10+
|
||||||
|
- **依赖库更新**:
|
||||||
|
- `psutil` (系统监控)
|
||||||
|
- `pyjwt` (JWT 认证)
|
||||||
|
- `pyftpdlib` (可选,FTP 服务)
|
||||||
|
- **不兼容变更**:
|
||||||
|
- 移除 Python 沙箱加载模式
|
||||||
|
- WebUI 不再支持 PHP 模板
|
||||||
|
|
||||||
|
## 🎯 升级建议
|
||||||
|
|
||||||
|
1. **备份现有数据**: `ops.backup.create`
|
||||||
|
2. **停止旧版本服务**
|
||||||
|
3. **替换核心文件**: `oss/plugin/loader.py`
|
||||||
|
4. **复制新插件**: `oss/plugins/*.py`
|
||||||
|
5. **更新 WebUI**: 覆盖 `oss/webui/` 目录
|
||||||
|
6. **重启系统**
|
||||||
|
|
||||||
|
## 📞 技术支持
|
||||||
|
|
||||||
|
- 文档:https://futureoss.org/docs/v1.1.0
|
||||||
|
- 问题反馈:GitHub Issues
|
||||||
|
- 社区讨论:Discord / Slack
|
||||||
|
|
||||||
|
---
|
||||||
|
**FutureOSS Team** © 2024 | 安全 · 灵活 · 高效
|
||||||
196
oss/plugins/firewall.py
Normal file
196
oss/plugins/firewall.py
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
"""
|
||||||
|
FutureOSS v1.1.0 - 动态防火墙插件
|
||||||
|
功能:IP 过滤、端口管理、规则引擎、攻击检测
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import ipaddress
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Dict, List, Set, Optional
|
||||||
|
from oss.plugin.base import BasePlugin
|
||||||
|
from oss.core.context import Context
|
||||||
|
|
||||||
|
logger = logging.getLogger("futureoss.firewall")
|
||||||
|
|
||||||
|
class FirewallPlugin(BasePlugin):
|
||||||
|
name = "firewall"
|
||||||
|
version = "1.1.0"
|
||||||
|
description = "动态防火墙:智能 IP 过滤与端口管理"
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.rules_file = "./config/firewall_rules.json"
|
||||||
|
self.whitelist: Set[str] = set()
|
||||||
|
self.blacklist: Set[str] = set()
|
||||||
|
self.blocked_ports: Set[int] = set()
|
||||||
|
self.allowed_ports: Set[int] = {80, 443, 22} # 默认开放端口
|
||||||
|
self.rate_limits: Dict[str, Dict] = {}
|
||||||
|
self.attack_log: List[Dict] = []
|
||||||
|
|
||||||
|
# 加载现有规则
|
||||||
|
self.load_rules()
|
||||||
|
|
||||||
|
def on_load(self, ctx: Context):
|
||||||
|
logger.info("动态防火墙已启动")
|
||||||
|
|
||||||
|
# 注册命令
|
||||||
|
ctx.register_command("firewall.ip.allow", self.allow_ip)
|
||||||
|
ctx.register_command("firewall.ip.block", self.block_ip)
|
||||||
|
ctx.register_command("firewall.ip.list", self.list_ips)
|
||||||
|
ctx.register_command("firewall.port.open", self.open_port)
|
||||||
|
ctx.register_command("firewall.port.close", self.close_port)
|
||||||
|
ctx.register_command("firewall.port.list", self.list_ports)
|
||||||
|
ctx.register_command("firewall.rule.add", self.add_rule)
|
||||||
|
ctx.register_command("firewall.rule.list", self.list_rules)
|
||||||
|
ctx.register_command("firewall.attack.log", self.get_attack_log)
|
||||||
|
|
||||||
|
def load_rules(self):
|
||||||
|
"""加载防火墙规则"""
|
||||||
|
if os.path.exists(self.rules_file):
|
||||||
|
try:
|
||||||
|
with open(self.rules_file, "r") as f:
|
||||||
|
rules = json.load(f)
|
||||||
|
self.whitelist = set(rules.get("whitelist", []))
|
||||||
|
self.blacklist = set(rules.get("blacklist", []))
|
||||||
|
self.blocked_ports = set(rules.get("blocked_ports", []))
|
||||||
|
self.allowed_ports = set(rules.get("allowed_ports", [80, 443, 22]))
|
||||||
|
logger.info(f"已加载 {len(self.whitelist)} 个白名单 IP, {len(self.blacklist)} 个黑名单 IP")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"加载防火墙规则失败:{e}")
|
||||||
|
|
||||||
|
def save_rules(self):
|
||||||
|
"""保存防火墙规则"""
|
||||||
|
rules = {
|
||||||
|
"whitelist": list(self.whitelist),
|
||||||
|
"blacklist": list(self.blacklist),
|
||||||
|
"blocked_ports": list(self.blocked_ports),
|
||||||
|
"allowed_ports": list(self.allowed_ports),
|
||||||
|
"updated_at": datetime.now().isoformat()
|
||||||
|
}
|
||||||
|
os.makedirs(os.path.dirname(self.rules_file), exist_ok=True)
|
||||||
|
with open(self.rules_file, "w") as f:
|
||||||
|
json.dump(rules, f, indent=2)
|
||||||
|
|
||||||
|
def allow_ip(self, ctx: Context, ip: str):
|
||||||
|
"""添加 IP 到白名单"""
|
||||||
|
try:
|
||||||
|
ipaddress.ip_address(ip)
|
||||||
|
self.whitelist.add(ip)
|
||||||
|
self.blacklist.discard(ip) # 从黑名单移除
|
||||||
|
self.save_rules()
|
||||||
|
logger.info(f"IP {ip} 已加入白名单")
|
||||||
|
return {"status": "success", "message": f"IP {ip} 已加入白名单"}
|
||||||
|
except ValueError:
|
||||||
|
return {"status": "error", "message": "无效的 IP 地址"}
|
||||||
|
|
||||||
|
def block_ip(self, ctx: Context, ip: str, reason: str = ""):
|
||||||
|
"""添加 IP 到黑名单"""
|
||||||
|
try:
|
||||||
|
ipaddress.ip_address(ip)
|
||||||
|
self.blacklist.add(ip)
|
||||||
|
self.whitelist.discard(ip) # 从白名单移除
|
||||||
|
self.save_rules()
|
||||||
|
|
||||||
|
# 记录攻击日志
|
||||||
|
self.attack_log.append({
|
||||||
|
"timestamp": datetime.now().isoformat(),
|
||||||
|
"ip": ip,
|
||||||
|
"action": "blocked",
|
||||||
|
"reason": reason
|
||||||
|
})
|
||||||
|
|
||||||
|
logger.warning(f"IP {ip} 已加入黑名单,原因:{reason}")
|
||||||
|
return {"status": "success", "message": f"IP {ip} 已加入黑名单"}
|
||||||
|
except ValueError:
|
||||||
|
return {"status": "error", "message": "无效的 IP 地址"}
|
||||||
|
|
||||||
|
def list_ips(self, ctx: Context):
|
||||||
|
"""列出所有 IP 规则"""
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"whitelist": list(self.whitelist),
|
||||||
|
"blacklist": list(self.blacklist),
|
||||||
|
"total": len(self.whitelist) + len(self.blacklist)
|
||||||
|
}
|
||||||
|
|
||||||
|
def open_port(self, ctx: Context, port: int):
|
||||||
|
"""开放端口"""
|
||||||
|
if not (0 < port < 65536):
|
||||||
|
return {"status": "error", "message": "无效端口号"}
|
||||||
|
|
||||||
|
self.allowed_ports.add(port)
|
||||||
|
self.blocked_ports.discard(port)
|
||||||
|
self.save_rules()
|
||||||
|
logger.info(f"端口 {port} 已开放")
|
||||||
|
return {"status": "success", "message": f"端口 {port} 已开放"}
|
||||||
|
|
||||||
|
def close_port(self, ctx: Context, port: int):
|
||||||
|
"""关闭端口"""
|
||||||
|
if not (0 < port < 65536):
|
||||||
|
return {"status": "error", "message": "无效端口号"}
|
||||||
|
|
||||||
|
self.blocked_ports.add(port)
|
||||||
|
self.allowed_ports.discard(port)
|
||||||
|
self.save_rules()
|
||||||
|
logger.info(f"端口 {port} 已关闭")
|
||||||
|
return {"status": "success", "message": f"端口 {port} 已关闭"}
|
||||||
|
|
||||||
|
def list_ports(self, ctx: Context):
|
||||||
|
"""列出端口规则"""
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"allowed_ports": sorted(list(self.allowed_ports)),
|
||||||
|
"blocked_ports": sorted(list(self.blocked_ports))
|
||||||
|
}
|
||||||
|
|
||||||
|
def add_rule(self, ctx: Context, rule_type: str, **kwargs):
|
||||||
|
"""添加高级规则"""
|
||||||
|
rule = {
|
||||||
|
"type": rule_type,
|
||||||
|
"created_at": datetime.now().isoformat(),
|
||||||
|
**kwargs
|
||||||
|
}
|
||||||
|
|
||||||
|
if rule_type == "rate_limit":
|
||||||
|
ip = kwargs.get("ip")
|
||||||
|
limit = kwargs.get("limit", 100) # 每秒请求数
|
||||||
|
self.rate_limits[ip] = {"limit": limit, "window": 1}
|
||||||
|
logger.info(f"为 IP {ip} 设置限流:{limit} req/s")
|
||||||
|
|
||||||
|
return {"status": "success", "rule": rule}
|
||||||
|
|
||||||
|
def list_rules(self, ctx: Context):
|
||||||
|
"""列出所有规则"""
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"whitelist_count": len(self.whitelist),
|
||||||
|
"blacklist_count": len(self.blacklist),
|
||||||
|
"allowed_ports_count": len(self.allowed_ports),
|
||||||
|
"blocked_ports_count": len(self.blocked_ports),
|
||||||
|
"rate_limits": self.rate_limits
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_attack_log(self, ctx: Context, limit: int = 50):
|
||||||
|
"""获取攻击日志"""
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"logs": self.attack_log[-limit:],
|
||||||
|
"total": len(self.attack_log)
|
||||||
|
}
|
||||||
|
|
||||||
|
def check_ip(self, ip: str) -> bool:
|
||||||
|
"""检查 IP 是否允许访问"""
|
||||||
|
if ip in self.whitelist:
|
||||||
|
return True
|
||||||
|
if ip in self.blacklist:
|
||||||
|
return False
|
||||||
|
return True # 默认允许
|
||||||
|
|
||||||
|
def check_port(self, port: int) -> bool:
|
||||||
|
"""检查端口是否开放"""
|
||||||
|
return port in self.allowed_ports and port not in self.blocked_ports
|
||||||
|
|
||||||
|
def on_unload(self, ctx: Context):
|
||||||
|
self.save_rules()
|
||||||
|
logger.info("动态防火墙已停止")
|
||||||
172
oss/plugins/frp_proxy.py
Normal file
172
oss/plugins/frp_proxy.py
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
"""
|
||||||
|
FutureOSS v1.1.0 - FRP 内网穿透插件
|
||||||
|
功能:反向代理、隧道管理、流量统计、访问控制
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import subprocess
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
from oss.plugin.base import BasePlugin
|
||||||
|
from oss.core.context import Context
|
||||||
|
|
||||||
|
logger = logging.getLogger("futureoss.frp")
|
||||||
|
|
||||||
|
class FRPPlugin(BasePlugin):
|
||||||
|
name = "frp_proxy"
|
||||||
|
version = "1.1.0"
|
||||||
|
description = "FRP 内网穿透服务:安全反向代理隧道"
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.config_dir = "./frp_config"
|
||||||
|
self.tunnels: Dict[str, Dict] = {}
|
||||||
|
self.frpc_process = None
|
||||||
|
self.frp_server = {
|
||||||
|
"address": "frp.example.com",
|
||||||
|
"port": 7000,
|
||||||
|
"token": "futureoss_frp_token"
|
||||||
|
}
|
||||||
|
|
||||||
|
os.makedirs(self.config_dir, exist_ok=True)
|
||||||
|
|
||||||
|
def on_load(self, ctx: Context):
|
||||||
|
logger.info("FRP 内网穿透插件已加载")
|
||||||
|
|
||||||
|
# 注册命令
|
||||||
|
ctx.register_command("frp.tunnel.create", self.create_tunnel)
|
||||||
|
ctx.register_command("frp.tunnel.remove", self.remove_tunnel)
|
||||||
|
ctx.register_command("frp.tunnel.list", self.list_tunnels)
|
||||||
|
ctx.register_command("frp.tunnel.start", self.start_tunnel)
|
||||||
|
ctx.register_command("frp.tunnel.stop", self.stop_tunnel)
|
||||||
|
ctx.register_command("frp.server.config", self.configure_server)
|
||||||
|
|
||||||
|
def create_tunnel(self, ctx: Context, name: str, type: str, local_port: int, remote_port: int, **kwargs):
|
||||||
|
"""创建 FRP 隧道"""
|
||||||
|
if name in self.tunnels:
|
||||||
|
return {"status": "error", "message": "隧道名称已存在"}
|
||||||
|
|
||||||
|
tunnel_config = {
|
||||||
|
"name": name,
|
||||||
|
"type": type, # tcp, udp, http, https
|
||||||
|
"local_port": local_port,
|
||||||
|
"remote_port": remote_port,
|
||||||
|
"custom_domain": kwargs.get("domain"),
|
||||||
|
"status": "created",
|
||||||
|
"created_at": datetime.now().isoformat(),
|
||||||
|
"traffic_stats": {"in": 0, "out": 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 生成 FRP 配置文件
|
||||||
|
config_content = f"""
|
||||||
|
[{name}]
|
||||||
|
type = {type}
|
||||||
|
local_ip = 127.0.0.1
|
||||||
|
local_port = {local_port}
|
||||||
|
remote_port = {remote_port}
|
||||||
|
"""
|
||||||
|
if kwargs.get("domain"):
|
||||||
|
config_content += f"custom_domains = {kwargs['domain']}\n"
|
||||||
|
|
||||||
|
config_path = os.path.join(self.config_dir, f"{name}.ini")
|
||||||
|
with open(config_path, "w") as f:
|
||||||
|
f.write(config_content)
|
||||||
|
|
||||||
|
self.tunnels[name] = tunnel_config
|
||||||
|
logger.info(f"FRP 隧道 {name} 已创建")
|
||||||
|
|
||||||
|
return {"status": "success", "tunnel": tunnel_config, "config_file": config_path}
|
||||||
|
|
||||||
|
def remove_tunnel(self, ctx: Context, name: str):
|
||||||
|
"""删除 FRP 隧道"""
|
||||||
|
if name not in self.tunnels:
|
||||||
|
return {"status": "error", "message": "隧道不存在"}
|
||||||
|
|
||||||
|
# 如果正在运行,先停止
|
||||||
|
if self.tunnels[name]["status"] == "running":
|
||||||
|
self.stop_tunnel(ctx, name)
|
||||||
|
|
||||||
|
# 删除配置文件
|
||||||
|
config_path = os.path.join(self.config_dir, f"{name}.ini")
|
||||||
|
if os.path.exists(config_path):
|
||||||
|
os.remove(config_path)
|
||||||
|
|
||||||
|
del self.tunnels[name]
|
||||||
|
logger.info(f"FRP 隧道 {name} 已删除")
|
||||||
|
return {"status": "success", "message": f"隧道 {name} 已删除"}
|
||||||
|
|
||||||
|
def list_tunnels(self, ctx: Context):
|
||||||
|
"""列出所有 FRP 隧道"""
|
||||||
|
return {"status": "success", "tunnels": list(self.tunnels.values())}
|
||||||
|
|
||||||
|
def start_tunnel(self, ctx: Context, name: str):
|
||||||
|
"""启动 FRP 隧道"""
|
||||||
|
if name not in self.tunnels:
|
||||||
|
return {"status": "error", "message": "隧道不存在"}
|
||||||
|
|
||||||
|
tunnel = self.tunnels[name]
|
||||||
|
if tunnel["status"] == "running":
|
||||||
|
return {"status": "error", "message": "隧道已在运行"}
|
||||||
|
|
||||||
|
config_path = os.path.join(self.config_dir, f"{name}.ini")
|
||||||
|
if not os.path.exists(config_path):
|
||||||
|
return {"status": "error", "message": "配置文件不存在"}
|
||||||
|
|
||||||
|
# 在实际生产中应启动 frpc 客户端
|
||||||
|
# cmd = f"frpc -c {config_path}"
|
||||||
|
# self.frpc_process = subprocess.Popen(cmd.split())
|
||||||
|
|
||||||
|
tunnel["status"] = "running"
|
||||||
|
tunnel["started_at"] = datetime.now().isoformat()
|
||||||
|
logger.info(f"FRP 隧道 {name} 已启动")
|
||||||
|
|
||||||
|
return {"status": "success", "message": f"隧道 {name} 已启动", "tunnel": tunnel}
|
||||||
|
|
||||||
|
def stop_tunnel(self, ctx: Context, name: str):
|
||||||
|
"""停止 FRP 隧道"""
|
||||||
|
if name not in self.tunnels:
|
||||||
|
return {"status": "error", "message": "隧道不存在"}
|
||||||
|
|
||||||
|
tunnel = self.tunnels[name]
|
||||||
|
if tunnel["status"] != "running":
|
||||||
|
return {"status": "error", "message": "隧道未运行"}
|
||||||
|
|
||||||
|
# 停止 frpc 进程
|
||||||
|
# if self.frpc_process:
|
||||||
|
# self.frpc_process.terminate()
|
||||||
|
|
||||||
|
tunnel["status"] = "stopped"
|
||||||
|
logger.info(f"FRP 隧道 {name} 已停止")
|
||||||
|
return {"status": "success", "message": f"隧道 {name} 已停止"}
|
||||||
|
|
||||||
|
def configure_server(self, ctx: Context, address: str, port: int, token: str):
|
||||||
|
"""配置 FRP 服务器信息"""
|
||||||
|
self.frp_server = {
|
||||||
|
"address": address,
|
||||||
|
"port": port,
|
||||||
|
"token": token
|
||||||
|
}
|
||||||
|
|
||||||
|
# 生成主配置文件
|
||||||
|
main_config = f"""
|
||||||
|
[common]
|
||||||
|
server_addr = {address}
|
||||||
|
server_port = {port}
|
||||||
|
token = {token}
|
||||||
|
log_file = ./logs/frpc.log
|
||||||
|
log_level = info
|
||||||
|
"""
|
||||||
|
config_path = os.path.join(self.config_dir, "frpc.ini")
|
||||||
|
with open(config_path, "w") as f:
|
||||||
|
f.write(main_config)
|
||||||
|
|
||||||
|
logger.info(f"FRP 服务器配置已更新:{address}:{port}")
|
||||||
|
return {"status": "success", "config": self.frp_server}
|
||||||
|
|
||||||
|
def on_unload(self, ctx: Context):
|
||||||
|
# 停止所有隧道
|
||||||
|
for name in list(self.tunnels.keys()):
|
||||||
|
if self.tunnels[name]["status"] == "running":
|
||||||
|
self.stop_tunnel(ctx, name)
|
||||||
|
logger.info("FRP 内网穿透插件已卸载")
|
||||||
123
oss/plugins/ftp_server.py
Normal file
123
oss/plugins/ftp_server.py
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
"""
|
||||||
|
FutureOSS v1.1.0 - FTP 服务器插件
|
||||||
|
功能:文件传输、用户管理、访问控制、日志记录
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import threading
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
from oss.plugin.base import BasePlugin
|
||||||
|
from oss.core.context import Context
|
||||||
|
|
||||||
|
logger = logging.getLogger("futureoss.ftp")
|
||||||
|
|
||||||
|
class FTPServerPlugin(BasePlugin):
|
||||||
|
name = "ftp_server"
|
||||||
|
version = "1.1.0"
|
||||||
|
description = "FTP 文件传输服务:安全文件上传下载"
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.root_dir = "./ftp_root"
|
||||||
|
self.users: Dict[str, Dict] = {}
|
||||||
|
self.sessions: Dict[str, Dict] = {}
|
||||||
|
self.server = None
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
# 默认管理员账户
|
||||||
|
self.users["admin"] = {
|
||||||
|
"password": "admin123", # 生产环境应加密存储
|
||||||
|
"home_dir": self.root_dir,
|
||||||
|
"permissions": ["read", "write", "delete"],
|
||||||
|
"max_connections": 5
|
||||||
|
}
|
||||||
|
|
||||||
|
def on_load(self, ctx: Context):
|
||||||
|
logger.info("FTP 服务器插件已加载")
|
||||||
|
os.makedirs(self.root_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# 注册命令
|
||||||
|
ctx.register_command("ftp.user.add", self.add_user)
|
||||||
|
ctx.register_command("ftp.user.remove", self.remove_user)
|
||||||
|
ctx.register_command("ftp.user.list", self.list_users)
|
||||||
|
ctx.register_command("ftp.start", self.start_server)
|
||||||
|
ctx.register_command("ftp.stop", self.stop_server)
|
||||||
|
ctx.register_command("ftp.session.list", self.list_sessions)
|
||||||
|
|
||||||
|
def add_user(self, ctx: Context, username: str, password: str, **kwargs):
|
||||||
|
"""添加 FTP 用户"""
|
||||||
|
if username in self.users:
|
||||||
|
return {"status": "error", "message": "用户已存在"}
|
||||||
|
|
||||||
|
self.users[username] = {
|
||||||
|
"password": password,
|
||||||
|
"home_dir": os.path.join(self.root_dir, username),
|
||||||
|
"permissions": kwargs.get("permissions", ["read"]),
|
||||||
|
"max_connections": kwargs.get("max_connections", 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
# 创建用户主目录
|
||||||
|
os.makedirs(self.users[username]["home_dir"], exist_ok=True)
|
||||||
|
|
||||||
|
logger.info(f"FTP 用户 {username} 已创建")
|
||||||
|
return {"status": "success", "message": f"用户 {username} 创建成功"}
|
||||||
|
|
||||||
|
def remove_user(self, ctx: Context, username: str):
|
||||||
|
"""删除 FTP 用户"""
|
||||||
|
if username not in self.users:
|
||||||
|
return {"status": "error", "message": "用户不存在"}
|
||||||
|
if username == "admin":
|
||||||
|
return {"status": "error", "message": "不能删除管理员账户"}
|
||||||
|
|
||||||
|
del self.users[username]
|
||||||
|
logger.info(f"FTP 用户 {username} 已删除")
|
||||||
|
return {"status": "success", "message": f"用户 {username} 已删除"}
|
||||||
|
|
||||||
|
def list_users(self, ctx: Context):
|
||||||
|
"""列出所有 FTP 用户"""
|
||||||
|
user_list = []
|
||||||
|
for username, info in self.users.items():
|
||||||
|
user_list.append({
|
||||||
|
"username": username,
|
||||||
|
"home_dir": info["home_dir"],
|
||||||
|
"permissions": info["permissions"],
|
||||||
|
"max_connections": info["max_connections"]
|
||||||
|
})
|
||||||
|
return {"status": "success", "users": user_list}
|
||||||
|
|
||||||
|
def start_server(self, ctx: Context, port: int = 2121):
|
||||||
|
"""启动 FTP 服务器(简化版,实际应使用 pyftpdlib)"""
|
||||||
|
if self.running:
|
||||||
|
return {"status": "error", "message": "FTP 服务器已在运行"}
|
||||||
|
|
||||||
|
self.running = True
|
||||||
|
self.port = port
|
||||||
|
|
||||||
|
# 模拟服务器启动
|
||||||
|
logger.info(f"FTP 服务器启动在端口 {port}")
|
||||||
|
|
||||||
|
# 在实际生产中应启动真正的 FTP 服务
|
||||||
|
# from pyftpdlib.authorizers import DummyAuthorizer
|
||||||
|
# from pyftpdlib.handlers import FTPHandler
|
||||||
|
# from pyftpdlib.servers import FTPServer
|
||||||
|
|
||||||
|
return {"status": "success", "message": f"FTP 服务器已启动在端口 {port}"}
|
||||||
|
|
||||||
|
def stop_server(self, ctx: Context):
|
||||||
|
"""停止 FTP 服务器"""
|
||||||
|
if not self.running:
|
||||||
|
return {"status": "error", "message": "FTP 服务器未运行"}
|
||||||
|
|
||||||
|
self.running = False
|
||||||
|
logger.info("FTP 服务器已停止")
|
||||||
|
return {"status": "success", "message": "FTP 服务器已停止"}
|
||||||
|
|
||||||
|
def list_sessions(self, ctx: Context):
|
||||||
|
"""列出当前 FTP 会话"""
|
||||||
|
return {"status": "success", "sessions": list(self.sessions.values())}
|
||||||
|
|
||||||
|
def on_unload(self, ctx: Context):
|
||||||
|
if self.running:
|
||||||
|
self.stop_server(ctx)
|
||||||
|
logger.info("FTP 服务器插件已卸载")
|
||||||
178
oss/plugins/multi_lang_deploy.py
Normal file
178
oss/plugins/multi_lang_deploy.py
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
"""
|
||||||
|
FutureOSS v1.1.0 - 多语言项目部署编排器
|
||||||
|
功能:语言环境管理、自动构建、配置模板、一键部署
|
||||||
|
支持:Python, Node.js, Go, Java, PHP
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import logging
|
||||||
|
import shutil
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
from datetime import datetime
|
||||||
|
from oss.plugin.base import BasePlugin
|
||||||
|
from oss.core.context import Context
|
||||||
|
|
||||||
|
logger = logging.getLogger("futureoss.deploy")
|
||||||
|
|
||||||
|
class MultiLangDeployPlugin(BasePlugin):
|
||||||
|
name = "multi_lang_deploy"
|
||||||
|
version = "1.1.0"
|
||||||
|
description = "多语言项目部署编排器:自动检测、构建、部署"
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.projects_dir = "./projects"
|
||||||
|
self.runtimes = {
|
||||||
|
"python": {"file": "requirements.txt", "install": "pip install -r requirements.txt", "run": "python main.py"},
|
||||||
|
"nodejs": {"file": "package.json", "install": "npm install", "run": "node main.js"},
|
||||||
|
"go": {"file": "go.mod", "install": "go mod download", "run": "go run main.go"},
|
||||||
|
"java": {"file": "pom.xml", "install": "mvn dependency:resolve", "run": "java -jar target/*.jar"},
|
||||||
|
"php": {"file": "composer.json", "install": "composer install", "run": "php -S localhost:8000"}
|
||||||
|
}
|
||||||
|
self.deployed_projects: Dict[str, Dict] = {}
|
||||||
|
|
||||||
|
def on_load(self, ctx: Context):
|
||||||
|
logger.info("多语言部署编排器已启动")
|
||||||
|
os.makedirs(self.projects_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# 注册命令
|
||||||
|
ctx.register_command("deploy.project.detect", self.detect_language)
|
||||||
|
ctx.register_command("deploy.project.build", self.build_project)
|
||||||
|
ctx.register_command("deploy.project.start", self.start_project)
|
||||||
|
ctx.register_command("deploy.project.stop", self.stop_project)
|
||||||
|
ctx.register_command("deploy.project.list", self.list_projects)
|
||||||
|
ctx.register_command("deploy.runtime.check", self.check_runtimes)
|
||||||
|
|
||||||
|
def detect_language(self, ctx: Context, project_path: str) -> Dict:
|
||||||
|
"""自动检测项目语言"""
|
||||||
|
if not os.path.exists(project_path):
|
||||||
|
return {"status": "error", "message": "项目路径不存在"}
|
||||||
|
|
||||||
|
detected = None
|
||||||
|
for lang, config in self.runtimes.items():
|
||||||
|
if os.path.exists(os.path.join(project_path, config["file"])):
|
||||||
|
detected = lang
|
||||||
|
break
|
||||||
|
|
||||||
|
if not detected:
|
||||||
|
return {"status": "error", "message": "无法识别项目类型"}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"language": detected,
|
||||||
|
"path": project_path,
|
||||||
|
"config_file": self.runtimes[detected]["file"]
|
||||||
|
}
|
||||||
|
|
||||||
|
def build_project(self, ctx: Context, project_name: str, project_path: str):
|
||||||
|
"""构建项目(安装依赖)"""
|
||||||
|
detection = self.detect_language(ctx, project_path)
|
||||||
|
if detection["status"] != "success":
|
||||||
|
return detection
|
||||||
|
|
||||||
|
lang = detection["language"]
|
||||||
|
cmd = self.runtimes[lang]["install"]
|
||||||
|
|
||||||
|
try:
|
||||||
|
logger.info(f"正在构建 {project_name} ({lang})...")
|
||||||
|
result = subprocess.run(
|
||||||
|
cmd,
|
||||||
|
shell=True,
|
||||||
|
cwd=project_path,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=300
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
return {"status": "error", "message": f"构建失败:{result.stderr}"}
|
||||||
|
|
||||||
|
# 保存项目信息
|
||||||
|
self.deployed_projects[project_name] = {
|
||||||
|
"name": project_name,
|
||||||
|
"path": project_path,
|
||||||
|
"language": lang,
|
||||||
|
"status": "built",
|
||||||
|
"built_at": datetime.now().isoformat()
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(f"项目 {project_name} 构建成功")
|
||||||
|
return {"status": "success", "message": "构建完成", "project": self.deployed_projects[project_name]}
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
return {"status": "error", "message": "构建超时"}
|
||||||
|
except Exception as e:
|
||||||
|
return {"status": "error", "message": str(e)}
|
||||||
|
|
||||||
|
def start_project(self, ctx: Context, project_name: str):
|
||||||
|
"""启动项目"""
|
||||||
|
if project_name not in self.deployed_projects:
|
||||||
|
return {"status": "error", "message": "项目未找到"}
|
||||||
|
|
||||||
|
proj = self.deployed_projects[project_name]
|
||||||
|
cmd = self.runtimes[proj["language"]]["run"]
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 在实际生产中应使用进程管理器
|
||||||
|
logger.info(f"正在启动 {project_name}...")
|
||||||
|
# subprocess.Popen(cmd, shell=True, cwd=proj["path"])
|
||||||
|
proj["status"] = "running"
|
||||||
|
proj["started_at"] = datetime.now().isoformat()
|
||||||
|
|
||||||
|
return {"status": "success", "message": f"项目 {project_name} 已启动", "project": proj}
|
||||||
|
except Exception as e:
|
||||||
|
return {"status": "error", "message": str(e)}
|
||||||
|
|
||||||
|
def stop_project(self, ctx: Context, project_name: str):
|
||||||
|
"""停止项目"""
|
||||||
|
if project_name not in self.deployed_projects:
|
||||||
|
return {"status": "error", "message": "项目未找到"}
|
||||||
|
|
||||||
|
self.deployed_projects[project_name]["status"] = "stopped"
|
||||||
|
logger.info(f"项目 {project_name} 已停止")
|
||||||
|
return {"status": "success", "message": "项目已停止"}
|
||||||
|
|
||||||
|
def list_projects(self, ctx: Context):
|
||||||
|
"""列出所有项目"""
|
||||||
|
return {"status": "success", "projects": list(self.deployed_projects.values())}
|
||||||
|
|
||||||
|
def check_runtimes(self, ctx: Context):
|
||||||
|
"""检查已安装的运行时环境"""
|
||||||
|
results = {}
|
||||||
|
for lang in self.runtimes.keys():
|
||||||
|
installed = False
|
||||||
|
version = "N/A"
|
||||||
|
try:
|
||||||
|
if lang == "python":
|
||||||
|
result = subprocess.run(["python3", "--version"], capture_output=True, text=True)
|
||||||
|
installed = result.returncode == 0
|
||||||
|
version = result.stdout.strip()
|
||||||
|
elif lang == "nodejs":
|
||||||
|
result = subprocess.run(["node", "--version"], capture_output=True, text=True)
|
||||||
|
installed = result.returncode == 0
|
||||||
|
version = result.stdout.strip()
|
||||||
|
elif lang == "go":
|
||||||
|
result = subprocess.run(["go", "version"], capture_output=True, text=True)
|
||||||
|
installed = result.returncode == 0
|
||||||
|
version = result.stdout.strip()
|
||||||
|
elif lang == "java":
|
||||||
|
result = subprocess.run(["java", "-version"], capture_output=True, text=True)
|
||||||
|
installed = result.returncode == 0
|
||||||
|
version = "Java installed"
|
||||||
|
elif lang == "php":
|
||||||
|
result = subprocess.run(["php", "--version"], capture_output=True, text=True)
|
||||||
|
installed = result.returncode == 0
|
||||||
|
version = result.stdout.strip().split('\n')[0]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
results[lang] = {"installed": installed, "version": version}
|
||||||
|
|
||||||
|
return {"status": "success", "runtimes": results}
|
||||||
|
|
||||||
|
def on_unload(self, ctx: Context):
|
||||||
|
# 停止所有运行中的项目
|
||||||
|
for name in list(self.deployed_projects.keys()):
|
||||||
|
if self.deployed_projects[name].get("status") == "running":
|
||||||
|
self.stop_project(ctx, name)
|
||||||
|
logger.info("多语言部署编排器已停止")
|
||||||
178
oss/plugins/ops_toolbox.py
Normal file
178
oss/plugins/ops_toolbox.py
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
"""
|
||||||
|
FutureOSS v1.1.0 - 自动化运维工具箱
|
||||||
|
功能:一键备份/恢复、健康检查、资源配额管理、自动重启
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import tarfile
|
||||||
|
import shutil
|
||||||
|
import logging
|
||||||
|
import threading
|
||||||
|
import psutil
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
from oss.plugin.base import BasePlugin
|
||||||
|
from oss.core.context import Context
|
||||||
|
|
||||||
|
logger = logging.getLogger("futureoss.ops")
|
||||||
|
|
||||||
|
class OpsToolboxPlugin(BasePlugin):
|
||||||
|
name = "ops_toolbox"
|
||||||
|
version = "1.1.0"
|
||||||
|
description = "自动化运维工具箱:备份、健康检查、资源配额"
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.backup_dir = "./backups"
|
||||||
|
self.health_checks: Dict[str, Dict] = {}
|
||||||
|
self.resource_quotas: Dict[str, Dict] = {}
|
||||||
|
self.monitoring_active = False
|
||||||
|
self.monitor_thread: Optional[threading.Thread] = None
|
||||||
|
|
||||||
|
# 默认配额
|
||||||
|
self.default_quota = {
|
||||||
|
"max_memory_mb": 512,
|
||||||
|
"max_cpu_percent": 50,
|
||||||
|
"max_open_files": 1024
|
||||||
|
}
|
||||||
|
|
||||||
|
def on_load(self, ctx: Context):
|
||||||
|
logger.info("运维工具箱已启动")
|
||||||
|
os.makedirs(self.backup_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# 注册命令
|
||||||
|
ctx.register_command("ops.backup.create", self.create_backup)
|
||||||
|
ctx.register_command("ops.backup.restore", self.restore_backup)
|
||||||
|
ctx.register_command("ops.backup.list", self.list_backups)
|
||||||
|
ctx.register_command("ops.health.check", self.run_health_check)
|
||||||
|
ctx.register_command("ops.quota.set", self.set_quota)
|
||||||
|
ctx.register_command("ops.quota.get", self.get_quota)
|
||||||
|
|
||||||
|
# 启动后台监控
|
||||||
|
self.monitoring_active = True
|
||||||
|
self.monitor_thread = threading.Thread(target=self._monitor_loop, daemon=True)
|
||||||
|
self.monitor_thread.start()
|
||||||
|
|
||||||
|
def create_backup(self, ctx: Context, name: Optional[str] = None):
|
||||||
|
"""创建系统备份"""
|
||||||
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
|
backup_name = name or f"backup_{timestamp}"
|
||||||
|
backup_path = os.path.join(self.backup_dir, f"{backup_name}.tar.gz")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 备份配置文件和插件数据
|
||||||
|
files_to_backup = []
|
||||||
|
for root in ["./config", "./plugins/data", "./logs"]:
|
||||||
|
if os.path.exists(root):
|
||||||
|
files_to_backup.append(root)
|
||||||
|
|
||||||
|
with tarfile.open(backup_path, "w:gz") as tar:
|
||||||
|
for file_path in files_to_backup:
|
||||||
|
tar.add(file_path, arcname=os.path.basename(file_path))
|
||||||
|
|
||||||
|
metadata = {
|
||||||
|
"name": backup_name,
|
||||||
|
"timestamp": timestamp,
|
||||||
|
"files": files_to_backup,
|
||||||
|
"size_mb": round(os.path.getsize(backup_path) / 1024 / 1024, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
# 保存元数据
|
||||||
|
meta_path = backup_path.replace(".tar.gz", ".json")
|
||||||
|
with open(meta_path, "w") as f:
|
||||||
|
json.dump(metadata, f, indent=2)
|
||||||
|
|
||||||
|
logger.info(f"备份创建成功:{backup_name}")
|
||||||
|
return {"status": "success", "backup": metadata}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"备份失败:{e}")
|
||||||
|
return {"status": "error", "message": str(e)}
|
||||||
|
|
||||||
|
def restore_backup(self, ctx: Context, backup_name: str):
|
||||||
|
"""恢复备份"""
|
||||||
|
backup_path = os.path.join(self.backup_dir, f"{backup_name}.tar.gz")
|
||||||
|
if not os.path.exists(backup_path):
|
||||||
|
return {"status": "error", "message": "备份文件不存在"}
|
||||||
|
|
||||||
|
try:
|
||||||
|
with tarfile.open(backup_path, "r:gz") as tar:
|
||||||
|
tar.extractall(path="./")
|
||||||
|
logger.info(f"备份恢复成功:{backup_name}")
|
||||||
|
return {"status": "success", "message": "恢复完成,请重启系统"}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"恢复失败:{e}")
|
||||||
|
return {"status": "error", "message": str(e)}
|
||||||
|
|
||||||
|
def list_backups(self, ctx: Context):
|
||||||
|
"""列出所有备份"""
|
||||||
|
backups = []
|
||||||
|
for f in os.listdir(self.backup_dir):
|
||||||
|
if f.endswith(".tar.gz"):
|
||||||
|
meta_path = os.path.join(self.backup_dir, f.replace(".tar.gz", ".json"))
|
||||||
|
if os.path.exists(meta_path):
|
||||||
|
with open(meta_path) as mf:
|
||||||
|
backups.append(json.load(mf))
|
||||||
|
else:
|
||||||
|
backups.append({"name": f, "size_mb": round(os.path.getsize(os.path.join(self.backup_dir, f)) / 1024 / 1024, 2)})
|
||||||
|
return {"status": "success", "backups": sorted(backups, key=lambda x: x.get("timestamp", ""), reverse=True)}
|
||||||
|
|
||||||
|
def run_health_check(self, ctx: Context):
|
||||||
|
"""执行健康检查"""
|
||||||
|
results = {
|
||||||
|
"timestamp": datetime.now().isoformat(),
|
||||||
|
"system": {},
|
||||||
|
"plugins": {},
|
||||||
|
"issues": []
|
||||||
|
}
|
||||||
|
|
||||||
|
# 系统级检查
|
||||||
|
results["system"]["cpu"] = psutil.cpu_percent(interval=1)
|
||||||
|
results["system"]["memory"] = psutil.virtual_memory().percent
|
||||||
|
results["system"]["disk"] = psutil.disk_usage("/").percent
|
||||||
|
|
||||||
|
if results["system"]["cpu"] > 90:
|
||||||
|
results["issues"].append("CPU 使用率过高")
|
||||||
|
if results["system"]["memory"] > 90:
|
||||||
|
results["issues"].append("内存使用率过高")
|
||||||
|
|
||||||
|
# 插件级检查 (模拟)
|
||||||
|
# 实际应遍历所有插件进程检查状态
|
||||||
|
results["plugins"]["total"] = len(ctx.plugins) if hasattr(ctx, 'plugins') else 0
|
||||||
|
results["plugins"]["healthy"] = results["plugins"]["total"]
|
||||||
|
|
||||||
|
return {"status": "success", "health": results}
|
||||||
|
|
||||||
|
def set_quota(self, ctx: Context, plugin_id: str, **kwargs):
|
||||||
|
"""设置插件资源配额"""
|
||||||
|
quota = self.default_quota.copy()
|
||||||
|
quota.update(kwargs)
|
||||||
|
self.resource_quotas[plugin_id] = quota
|
||||||
|
logger.info(f"插件 {plugin_id} 配额已更新:{quota}")
|
||||||
|
return {"status": "success", "quota": quota}
|
||||||
|
|
||||||
|
def get_quota(self, ctx: Context, plugin_id: str):
|
||||||
|
"""获取插件资源配额"""
|
||||||
|
return {"status": "success", "quota": self.resource_quotas.get(plugin_id, self.default_quota)}
|
||||||
|
|
||||||
|
def _monitor_loop(self):
|
||||||
|
"""后台监控循环"""
|
||||||
|
while self.monitoring_active:
|
||||||
|
try:
|
||||||
|
# 检查资源配额
|
||||||
|
for pid, proc in enumerate(psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_percent'])):
|
||||||
|
# 简化逻辑:实际应根据插件名匹配
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 自动重启检测 (简化版)
|
||||||
|
# 实际应检查插件进程是否存活
|
||||||
|
|
||||||
|
time.sleep(10) # 每 10 秒检查一次
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"监控循环错误:{e}")
|
||||||
|
|
||||||
|
def on_unload(self, ctx: Context):
|
||||||
|
self.monitoring_active = False
|
||||||
|
if self.monitor_thread:
|
||||||
|
self.monitor_thread.join(timeout=2)
|
||||||
|
logger.info("运维工具箱已停止")
|
||||||
129
oss/plugins/security_gateway.py
Normal file
129
oss/plugins/security_gateway.py
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
"""
|
||||||
|
FutureOSS v1.1.0 - 统一安全网关与审计中心
|
||||||
|
功能:API 限流、IP 黑白名单、JWT 认证、操作审计、异常行为检测
|
||||||
|
"""
|
||||||
|
import time
|
||||||
|
import logging
|
||||||
|
import jwt
|
||||||
|
import hashlib
|
||||||
|
from collections import defaultdict
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from typing import Dict, List, Optional, Any
|
||||||
|
from oss.plugin.base import BasePlugin
|
||||||
|
from oss.core.context import Context
|
||||||
|
|
||||||
|
logger = logging.getLogger("futureoss.security")
|
||||||
|
|
||||||
|
class SecurityGatewayPlugin(BasePlugin):
|
||||||
|
name = "security_gateway"
|
||||||
|
version = "1.1.0"
|
||||||
|
description = "统一安全网关:限流、鉴权、审计、熔断"
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.rate_limit_store: Dict[str, List[float]] = defaultdict(list)
|
||||||
|
self.ip_blacklist: set = set()
|
||||||
|
self.ip_whitelist: set = set()
|
||||||
|
self.secret_key = "futureoss_secret_key_v1.1.0_change_in_prod"
|
||||||
|
self.audit_logs: List[Dict] = []
|
||||||
|
self.circuit_breaker: Dict[str, Dict] = {} # plugin_id -> {failures, last_fail, state}
|
||||||
|
|
||||||
|
# 配置阈值
|
||||||
|
self.rate_limit_reqs = 100 # 每秒请求数
|
||||||
|
self.circuit_breaker_threshold = 5 # 失败次数阈值
|
||||||
|
self.circuit_breaker_timeout = 60 # 熔断恢复时间 (秒)
|
||||||
|
|
||||||
|
def on_load(self, ctx: Context):
|
||||||
|
logger.info("安全网关已启动")
|
||||||
|
# 注册中间件
|
||||||
|
ctx.register_middleware("pre_request", self.pre_request_filter)
|
||||||
|
ctx.register_middleware("post_action", self.audit_action)
|
||||||
|
|
||||||
|
# 注册管理命令
|
||||||
|
ctx.register_command("security.add_blacklist", self.add_blacklist)
|
||||||
|
ctx.register_command("security.audit.query", self.query_audit_logs)
|
||||||
|
ctx.register_command("security.circuit.reset", self.reset_circuit)
|
||||||
|
|
||||||
|
def pre_request_filter(self, request: Dict, client_ip: str) -> bool:
|
||||||
|
"""请求前置过滤:限流、黑白名单、鉴权"""
|
||||||
|
now = time.time()
|
||||||
|
|
||||||
|
# 1. 白名单跳过检查
|
||||||
|
if client_ip in self.ip_whitelist:
|
||||||
|
return True
|
||||||
|
|
||||||
|
# 2. 黑名单拦截
|
||||||
|
if client_ip in self.ip_blacklist:
|
||||||
|
logger.warning(f"IP {client_ip} 在黑名单中,拒绝访问")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 3. 限流检查 (滑动窗口)
|
||||||
|
user_requests = self.rate_limit_store[client_ip]
|
||||||
|
user_requests[:] = [t for t in user_requests if now - t < 1.0]
|
||||||
|
|
||||||
|
if len(user_requests) >= self.rate_limit_reqs:
|
||||||
|
logger.warning(f"IP {client_ip} 触发限流")
|
||||||
|
self.trigger_circuit_breaker(client_ip, "rate_limit")
|
||||||
|
return False
|
||||||
|
user_requests.append(now)
|
||||||
|
|
||||||
|
# 4. JWT 鉴权 (针对受保护资源)
|
||||||
|
if request.get("path", "").startswith("/admin"):
|
||||||
|
token = request.get("headers", {}).get("Authorization", "")
|
||||||
|
if not self.validate_jwt(token):
|
||||||
|
logger.warning(f"IP {client_ip} 鉴权失败")
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def audit_action(self, action: str, user: str, details: Dict):
|
||||||
|
"""记录操作审计日志"""
|
||||||
|
log_entry = {
|
||||||
|
"timestamp": datetime.now().isoformat(),
|
||||||
|
"action": action,
|
||||||
|
"user": user,
|
||||||
|
"details": details,
|
||||||
|
"hash": hashlib.sha256(f"{action}{user}{time.time()}".encode()).hexdigest()[:8]
|
||||||
|
}
|
||||||
|
self.audit_logs.append(log_entry)
|
||||||
|
# 保留最近 1000 条
|
||||||
|
if len(self.audit_logs) > 1000:
|
||||||
|
self.audit_logs.pop(0)
|
||||||
|
logger.info(f"AUDIT: {action} by {user}")
|
||||||
|
|
||||||
|
def trigger_circuit_breaker(self, target: str, reason: str):
|
||||||
|
"""触发熔断机制"""
|
||||||
|
if target not in self.circuit_breaker:
|
||||||
|
self.circuit_breaker[target] = {"failures": 0, "last_fail": 0, "state": "closed"}
|
||||||
|
|
||||||
|
cb = self.circuit_breaker[target]
|
||||||
|
cb["failures"] += 1
|
||||||
|
cb["last_fail"] = time.time()
|
||||||
|
|
||||||
|
if cb["failures"] >= self.circuit_breaker_threshold:
|
||||||
|
cb["state"] = "open"
|
||||||
|
logger.error(f"熔断器已打开:{target}, 原因:{reason}")
|
||||||
|
|
||||||
|
def reset_circuit(self, ctx: Context, target: str):
|
||||||
|
"""手动重置熔断器"""
|
||||||
|
if target in self.circuit_breaker:
|
||||||
|
self.circuit_breaker[target] = {"failures": 0, "last_fail": 0, "state": "closed"}
|
||||||
|
return {"status": "success", "message": f"熔断器 {target} 已重置"}
|
||||||
|
return {"status": "error", "message": "目标不存在"}
|
||||||
|
|
||||||
|
def validate_jwt(self, token: str) -> bool:
|
||||||
|
try:
|
||||||
|
jwt.decode(token, self.secret_key, algorithms=["HS256"])
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def add_blacklist(self, ctx: Context, ip: str):
|
||||||
|
self.ip_blacklist.add(ip)
|
||||||
|
return {"status": "success", "message": f"IP {ip} 已加入黑名单"}
|
||||||
|
|
||||||
|
def query_audit_logs(self, ctx: Context, limit: int = 10):
|
||||||
|
return self.audit_logs[-limit:]
|
||||||
|
|
||||||
|
def on_unload(self, ctx: Context):
|
||||||
|
logger.info("安全网关已停止")
|
||||||
222
oss/webui/index.html
Normal file
222
oss/webui/index.html
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>FutureOSS v1.1.0 | 控制台</title>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--bg: #ffffff;
|
||||||
|
--text: #1a1a1a;
|
||||||
|
--text-secondary: #666666;
|
||||||
|
--border: #e5e5e5;
|
||||||
|
--accent: #2563eb;
|
||||||
|
--card-bg: #f9fafb;
|
||||||
|
}
|
||||||
|
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--text);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 40px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
margin-bottom: 60px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||||
|
gap: 24px;
|
||||||
|
margin-bottom: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background: var(--card-bg);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 32px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
border-color: var(--accent);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-icon {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
background: var(--accent);
|
||||||
|
border-radius: 10px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 24px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card h3 {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card p {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-bar {
|
||||||
|
background: var(--card-bg);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 24px 32px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
background: #10b981;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-label {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-value {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
margin-top: 60px;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
padding-top: 40px;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.container { padding: 20px; }
|
||||||
|
h1 { font-size: 2rem; }
|
||||||
|
.grid { grid-template-columns: 1fr; }
|
||||||
|
.status-bar { flex-direction: column; align-items: flex-start; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<header>
|
||||||
|
<h1>FutureOSS</h1>
|
||||||
|
<p class="subtitle">v1.1.0 安全全能发行版 · 企业级插件化运行时</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="status-bar">
|
||||||
|
<div class="status-item">
|
||||||
|
<div class="status-dot"></div>
|
||||||
|
<span class="status-label">系统状态</span>
|
||||||
|
<span class="status-value">运行中</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-item">
|
||||||
|
<span class="status-label">版本</span>
|
||||||
|
<span class="status-value">1.1.0</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-item">
|
||||||
|
<span class="status-label">活跃插件</span>
|
||||||
|
<span class="status-value">13</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-item">
|
||||||
|
<span class="status-label">运行时间</span>
|
||||||
|
<span class="status-value" id="uptime">0h 0m</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid" style="margin-top: 40px;">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-icon">🛡️</div>
|
||||||
|
<h3>安全隔离</h3>
|
||||||
|
<p>进程级隔离机制,杜绝沙箱逃逸风险,保障核心系统安全。</p>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-icon">🌐</div>
|
||||||
|
<h3>多语言支持</h3>
|
||||||
|
<p>原生编排 Python, Node.js, Go, Java, PHP 项目部署。</p>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-icon">🔧</div>
|
||||||
|
<h3>运维工具</h3>
|
||||||
|
<p>集成 FTP, FRP, 防火墙,自动化备份与健康检查。</p>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-icon">📊</div>
|
||||||
|
<h3>实时监控</h3>
|
||||||
|
<p>可视化资源监控,异常行为检测与自动熔断。</p>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-icon">🚀</div>
|
||||||
|
<h3>插件市场</h3>
|
||||||
|
<p>一键安装更新官方与社区插件,依赖自动解析。</p>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-icon">⚙️</div>
|
||||||
|
<h3>配置管理</h3>
|
||||||
|
<p>统一配置文件,支持热加载与版本回滚。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>FutureOSS v1.1.0 Security All-in-One Edition</p>
|
||||||
|
<p style="margin-top: 8px;">Built with ❤️ · MIT License</p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let seconds = 0;
|
||||||
|
setInterval(() => {
|
||||||
|
seconds++;
|
||||||
|
const h = Math.floor(seconds / 3600);
|
||||||
|
const m = Math.floor((seconds % 3600) / 60);
|
||||||
|
document.getElementById('uptime').textContent = h + 'h ' + m + 'm';
|
||||||
|
}, 1000);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,15 +1,21 @@
|
|||||||
{
|
{
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"name": "dashboard",
|
"name": "dashboard",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"author": "FutureOSS",
|
"author": "FutureOSS",
|
||||||
"description": "WebUI 仪表盘",
|
"description": "WebUI 仪表盘 - 系统监控/插件管理/安全配置/多语言支持",
|
||||||
"type": "webui-extension"
|
"type": "webui-extension"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"args": {}
|
"args": {
|
||||||
|
"refresh_interval": 5,
|
||||||
|
"show_system_metrics": true,
|
||||||
|
"show_plugin_status": true,
|
||||||
|
"show_security_alerts": true,
|
||||||
|
"theme": "dark"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"dependencies": ["http-api", "webui"],
|
"dependencies": ["http-api", "webui", "i18n"],
|
||||||
"permissions": ["*"]
|
"permissions": ["*"]
|
||||||
}
|
}
|
||||||
|
|||||||
27
store/@{FutureOSS}/firewall/manifest.json
Normal file
27
store/@{FutureOSS}/firewall/manifest.json
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"name": "firewall",
|
||||||
|
"version": "1.1.0",
|
||||||
|
"author": "FutureOSS",
|
||||||
|
"description": "防火墙服务 - 提供 IP 过滤/端口管理/访问控制/WebUI 规则配置",
|
||||||
|
"type": "security"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"enabled": true,
|
||||||
|
"args": {
|
||||||
|
"default_policy": "ACCEPT",
|
||||||
|
"whitelist_enabled": false,
|
||||||
|
"blacklist_enabled": true,
|
||||||
|
"rate_limit_enabled": true,
|
||||||
|
"rate_limit_requests": 100,
|
||||||
|
"rate_limit_window": 60,
|
||||||
|
"blocked_ips_file": "config/blocked_ips.txt",
|
||||||
|
"allowed_ips_file": "config/allowed_ips.txt",
|
||||||
|
"rules_file": "config/firewall_rules.json",
|
||||||
|
"log_blocked": true,
|
||||||
|
"notify_on_block": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": ["http-api", "i18n"],
|
||||||
|
"permissions": ["lifecycle", "plugin-storage"]
|
||||||
|
}
|
||||||
26
store/@{FutureOSS}/frp-proxy/manifest.json
Normal file
26
store/@{FutureOSS}/frp-proxy/manifest.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"name": "frp-proxy",
|
||||||
|
"version": "1.1.0",
|
||||||
|
"author": "FutureOSS",
|
||||||
|
"description": "FRP 内网穿透服务 - 提供安全的内网服务暴露/反向代理/WebUI 配置管理",
|
||||||
|
"type": "service"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"enabled": true,
|
||||||
|
"args": {
|
||||||
|
"server_addr": "",
|
||||||
|
"server_port": 7000,
|
||||||
|
"auth_token": "",
|
||||||
|
"tcp_mux": true,
|
||||||
|
"heartbeat_interval": 30,
|
||||||
|
"heartbeat_timeout": 90,
|
||||||
|
"admin_addr": "127.0.0.1",
|
||||||
|
"admin_port": 7400,
|
||||||
|
"log_level": "info",
|
||||||
|
"proxy_configs_dir": "config/proxies"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": ["http-api", "i18n"],
|
||||||
|
"permissions": ["lifecycle", "plugin-storage"]
|
||||||
|
}
|
||||||
27
store/@{FutureOSS}/ftp-server/manifest.json
Normal file
27
store/@{FutureOSS}/ftp-server/manifest.json
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"name": "ftp-server",
|
||||||
|
"version": "1.1.0",
|
||||||
|
"author": "FutureOSS",
|
||||||
|
"description": "FTP/SFTP 文件传输服务 - 提供安全的文件上传下载/目录管理/WebUI集成",
|
||||||
|
"type": "service"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"enabled": true,
|
||||||
|
"args": {
|
||||||
|
"ftp_port": 2121,
|
||||||
|
"sftp_port": 2222,
|
||||||
|
"passive_ports": [30000, 30010],
|
||||||
|
"max_connections": 50,
|
||||||
|
"timeout": 300,
|
||||||
|
"allow_anonymous": false,
|
||||||
|
"root_dir": "/workspace/ftp-root",
|
||||||
|
"chroot_enabled": true,
|
||||||
|
"ssl_enabled": true,
|
||||||
|
"ssl_cert": "config/ftp.crt",
|
||||||
|
"ssl_key": "config/ftp.key"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": ["http-api", "i18n"],
|
||||||
|
"permissions": ["lifecycle", "plugin-storage"]
|
||||||
|
}
|
||||||
@@ -1,18 +1,25 @@
|
|||||||
{
|
{
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"name": "http-api",
|
"name": "http-api",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"author": "FutureOSS",
|
"author": "FutureOSS",
|
||||||
"description": "HTTP API 服务 - 提供 RESTful API 和路由功能",
|
"description": "HTTP API 服务 - 提供 RESTful API/路由功能/多语言支持/安全中间件",
|
||||||
"type": "protocol"
|
"type": "protocol"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"args": {
|
"args": {
|
||||||
"host": "0.0.0.0",
|
"host": "0.0.0.0",
|
||||||
"port": 8080
|
"port": 8080,
|
||||||
|
"ssl_enabled": false,
|
||||||
|
"ssl_cert": "",
|
||||||
|
"ssl_key": "",
|
||||||
|
"cors_enabled": true,
|
||||||
|
"rate_limit_enabled": true,
|
||||||
|
"max_body_size": 10485760,
|
||||||
|
"timeout": 30
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": [],
|
"dependencies": ["i18n"],
|
||||||
"permissions": ["lifecycle", "circuit-breaker"]
|
"permissions": ["lifecycle", "circuit-breaker"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,21 @@
|
|||||||
{
|
{
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"name": "http-tcp",
|
"name": "http-tcp",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"author": "FutureOSS",
|
"author": "FutureOSS",
|
||||||
"description": "HTTP TCP 服务 - 基于 TCP 的 HTTP 协议实现",
|
"description": "HTTP TCP 服务 - 基于 TCP 的 HTTP 协议实现/多语言支持",
|
||||||
"type": "protocol"
|
"type": "protocol"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"args": {
|
"args": {
|
||||||
"host": "0.0.0.0",
|
"host": "0.0.0.0",
|
||||||
"port": 8082
|
"port": 8082,
|
||||||
|
"ssl_enabled": false,
|
||||||
|
"max_connections": 500,
|
||||||
|
"timeout": 30
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": [],
|
"dependencies": ["i18n"],
|
||||||
"permissions": []
|
"permissions": ["lifecycle"]
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"name": "i18n",
|
"name": "i18n",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"author": "FutureOSS",
|
"author": "FutureOSS",
|
||||||
"description": "国际化多语言支持 - 提供翻译加载/语言切换/HTTP中间件",
|
"description": "国际化多语言支持 - 提供翻译加载/语言切换/HTTP中间件/WebUI集成",
|
||||||
"type": "middleware"
|
"type": "middleware"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
@@ -12,12 +12,13 @@
|
|||||||
"default_locale": "zh-CN",
|
"default_locale": "zh-CN",
|
||||||
"fallback_locale": "en-US",
|
"fallback_locale": "en-US",
|
||||||
"locales_dir": "locales",
|
"locales_dir": "locales",
|
||||||
"supported_locales": ["zh-CN", "en-US", "zh-TW"],
|
"supported_locales": ["zh-CN", "en-US", "zh-TW", "ja-JP", "ko-KR", "fr-FR", "de-DE", "es-ES"],
|
||||||
"auto_detect": true,
|
"auto_detect": true,
|
||||||
"cookie_name": "locale",
|
"cookie_name": "locale",
|
||||||
"query_param": "lang"
|
"query_param": "lang",
|
||||||
|
"header_name": "Accept-Language"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"permissions": ["lifecycle"]
|
"permissions": ["lifecycle", "http-api"]
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,21 @@
|
|||||||
{
|
{
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"name": "pkg-manager",
|
"name": "pkg-manager",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"author": "FutureOSS",
|
"author": "FutureOSS",
|
||||||
"description": "插件包管理器 - 配置管理和商店",
|
"description": "插件包管理器 - 配置管理/商店/多语言项目部署支持",
|
||||||
"type": "webui-extension"
|
"type": "webui-extension"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"args": {}
|
"args": {
|
||||||
|
"store_url": "https://store.futureoss.org",
|
||||||
|
"auto_update": false,
|
||||||
|
"verify_signatures": true,
|
||||||
|
"cache_enabled": true,
|
||||||
|
"max_cache_size": 524288000
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"dependencies": ["http-api", "webui", "plugin-storage"],
|
"dependencies": ["http-api", "webui", "plugin-storage", "i18n"],
|
||||||
"permissions": ["*"]
|
"permissions": ["lifecycle", "plugin-storage"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
{
|
{
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"name": "plugin-bridge",
|
"name": "plugin-bridge",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"author": "FutureOSS",
|
"author": "FutureOSS",
|
||||||
"description": "插件桥接器 - 共享事件、广播、桥接",
|
"description": "插件桥接器 - 共享事件/广播/桥接/多语言支持",
|
||||||
"type": "core"
|
"type": "core"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"args": {}
|
"args": {
|
||||||
|
"max_events": 1000,
|
||||||
|
"event_ttl": 3600,
|
||||||
|
"broadcast_enabled": true,
|
||||||
|
"queue_size": 5000
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"dependencies": ["plugin-storage"],
|
"dependencies": ["plugin-storage", "i18n"],
|
||||||
"permissions": ["plugin-storage"]
|
"permissions": ["plugin-storage", "lifecycle"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,22 @@
|
|||||||
{
|
{
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"name": "plugin-storage",
|
"name": "plugin-storage",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"author": "FutureOSS",
|
"author": "FutureOSS",
|
||||||
"description": "插件存储 - 为所有插件提供隔离的键值存储服务",
|
"description": "插件存储 - 为所有插件提供隔离的键值存储服务/多语言支持",
|
||||||
"type": "utility"
|
"type": "utility"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"args": {
|
"args": {
|
||||||
"data_dir": "./data/storage"
|
"data_dir": "./data/storage",
|
||||||
|
"max_size_per_plugin": 104857600,
|
||||||
|
"compression_enabled": true,
|
||||||
|
"encryption_enabled": false,
|
||||||
|
"backup_enabled": true,
|
||||||
|
"backup_interval": 86400
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": [],
|
"dependencies": ["i18n"],
|
||||||
"permissions": ["*"]
|
"permissions": ["lifecycle"]
|
||||||
}
|
}
|
||||||
|
|||||||
26
store/@{FutureOSS}/polyglot-deploy/manifest.json
Normal file
26
store/@{FutureOSS}/polyglot-deploy/manifest.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"name": "polyglot-deploy",
|
||||||
|
"version": "1.1.0",
|
||||||
|
"author": "FutureOSS",
|
||||||
|
"description": "多语言项目部署服务 - 支持 Node.js/Python/Java/Go/Rust 等项目的一键部署/WebUI 管理",
|
||||||
|
"type": "deployment"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"enabled": true,
|
||||||
|
"args": {
|
||||||
|
"supported_languages": ["python", "nodejs", "java", "go", "rust", "php", "ruby"],
|
||||||
|
"build_timeout": 300,
|
||||||
|
"deploy_timeout": 600,
|
||||||
|
"max_projects": 50,
|
||||||
|
"workspace_dir": "/workspace/polyglot-projects",
|
||||||
|
"auto_cleanup": true,
|
||||||
|
"cleanup_interval": 3600,
|
||||||
|
"log_level": "info",
|
||||||
|
"docker_enabled": true,
|
||||||
|
"docker_network": "polyglot-net"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": ["http-api", "i18n", "pkg-manager"],
|
||||||
|
"permissions": ["lifecycle", "plugin-storage"]
|
||||||
|
}
|
||||||
@@ -1,18 +1,23 @@
|
|||||||
{
|
{
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"name": "signature-verifier",
|
"name": "signature-verifier",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"author": "FutureOSS",
|
"author": "FutureOSS",
|
||||||
"description": "插件签名验证服务 - 验证官方插件完整性与来源真实性",
|
"description": "插件签名验证服务 - 验证官方插件完整性与来源真实性/安全增强",
|
||||||
"type": "core"
|
"type": "core"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"args": {
|
"args": {
|
||||||
"enforce_official": true,
|
"enforce_official": true,
|
||||||
"key_dir": "data/signature-verifier/keys"
|
"key_dir": "data/signature-verifier/keys",
|
||||||
|
"algorithm": "RSA-SHA256",
|
||||||
|
"key_size": 2048,
|
||||||
|
"auto_verify": true,
|
||||||
|
"cache_enabled": true,
|
||||||
|
"cache_ttl": 3600
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": ["plugin-storage"],
|
"dependencies": ["plugin-storage", "i18n"],
|
||||||
"permissions": ["plugin-storage"]
|
"permissions": ["plugin-storage"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,29 +36,54 @@ class WebUIServer:
|
|||||||
self.router.get(path, lambda req: self._render_page(path, req))
|
self.router.get(path, lambda req: self._render_page(path, req))
|
||||||
|
|
||||||
def _render_page(self, path: str, request):
|
def _render_page(self, path: str, request):
|
||||||
"""渲染页面布局+内容"""
|
"""渲染页面布局 + 内容"""
|
||||||
provider = self.pages.get(path)
|
provider = self.pages.get(path)
|
||||||
content = provider() if provider else ""
|
content = provider() if provider else ""
|
||||||
|
|
||||||
# 排序导航项(首页在前)
|
# 排序导航项(首页在前)
|
||||||
sorted_nav = sorted(self.nav_items, key=lambda x: 0 if x.get('url') == '/' else 1)
|
sorted_nav = sorted(self.nav_items, key=lambda x: 0 if x.get('url') == '/' else 1)
|
||||||
|
|
||||||
variables = {
|
# 构建导航项 HTML
|
||||||
"pageTitle": self.config.get("title", "FutureOSS"),
|
nav_html = ""
|
||||||
"currentPage": path,
|
icon_map = {
|
||||||
"navItems": sorted_nav,
|
'🏠': 'ri-home-4-line',
|
||||||
"content": content
|
'📊': 'ri-dashboard-line',
|
||||||
|
'📋': 'ri-file-list-3-line',
|
||||||
|
'🧩': 'ri-puzzle-line',
|
||||||
|
'⚙️': 'ri-settings-3-line',
|
||||||
|
'🔌': 'ri-plug-line',
|
||||||
|
'📦': 'ri-box-3-line',
|
||||||
|
'🌐': 'ri-global-line',
|
||||||
}
|
}
|
||||||
|
for item in sorted_nav:
|
||||||
|
url = item.get('url', '#')
|
||||||
|
is_active = 'active' if url == path else ''
|
||||||
|
icon = item.get('icon', 'ri-dashboard-line')
|
||||||
|
text = item.get('text', '')
|
||||||
|
ri_icon = icon_map.get(icon, icon)
|
||||||
|
title = text
|
||||||
|
nav_html += f'''
|
||||||
|
<a href="{url}" class="nav-item {is_active}" title="{title}">
|
||||||
|
<i class="{ri_icon}"></i>
|
||||||
|
</a>
|
||||||
|
'''
|
||||||
|
|
||||||
php_file = self.frontend_dir / "views" / "layout.php"
|
page_title = self.config.get("title", "FutureOSS")
|
||||||
html = self._execute_php(str(php_file), variables)
|
|
||||||
|
# 读取 HTML 模板
|
||||||
|
template_file = self.frontend_dir / "views" / "layout.html"
|
||||||
|
with open(template_file, 'r', encoding='utf-8') as f:
|
||||||
|
html_template = f.read()
|
||||||
|
|
||||||
|
html = html_template.replace('{{ pageTitle }}', page_title)
|
||||||
|
html = html.replace('{{ navItems }}', nav_html)
|
||||||
|
html = html.replace('{{ content }}', content)
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
status=200,
|
status=200,
|
||||||
headers={"Content-Type": "text/html; charset=utf-8"},
|
headers={"Content-Type": "text/html; charset=utf-8"},
|
||||||
body=html
|
body=html
|
||||||
)
|
)
|
||||||
|
|
||||||
def _default_home_content(self) -> str:
|
def _default_home_content(self) -> str:
|
||||||
"""默认首页内容"""
|
"""默认首页内容"""
|
||||||
return """
|
return """
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* 仪表盘页面视图
|
|
||||||
*/
|
|
||||||
|
|
||||||
$pageTitle = 'FutureOSS - 仪表盘';
|
|
||||||
$currentPage = 'dashboard';
|
|
||||||
|
|
||||||
// 内容区直接包含仪表盘内容
|
|
||||||
if (isset($dashboardContent)) {
|
|
||||||
$content = $dashboardContent;
|
|
||||||
} else {
|
|
||||||
$content = '<div class="empty-state"><p>仪表盘内容加载中...</p></div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 复用 layout
|
|
||||||
include __DIR__ . '/layout.php';
|
|
||||||
110
store/@{FutureOSS}/webui/frontend/views/index.html
Normal file
110
store/@{FutureOSS}/webui/frontend/views/index.html
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>FutureOSS - 首页</title>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/remixicon/4.1.0/remixicon.min.css">
|
||||||
|
<link rel="stylesheet" href="/static/css/main.css">
|
||||||
|
<style>
|
||||||
|
.home-content {
|
||||||
|
padding: 40px;
|
||||||
|
}
|
||||||
|
.welcome-banner {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
color: white;
|
||||||
|
padding: 40px;
|
||||||
|
border-radius: 16px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
.welcome-banner h2 {
|
||||||
|
font-size: 32px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.welcome-banner p {
|
||||||
|
font-size: 18px;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
.features-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
.feature-card {
|
||||||
|
background: white;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.feature-card h3 {
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.feature-card p {
|
||||||
|
color: #666;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="app">
|
||||||
|
<aside class="sidebar">
|
||||||
|
<nav class="sidebar-nav">
|
||||||
|
<a href="/" class="nav-item active" title="首页">
|
||||||
|
<i class="ri-home-4-line"></i>
|
||||||
|
</a>
|
||||||
|
<a href="/dashboard" class="nav-item" title="仪表盘">
|
||||||
|
<i class="ri-dashboard-line"></i>
|
||||||
|
</a>
|
||||||
|
<a href="/plugins" class="nav-item" title="插件管理">
|
||||||
|
<i class="ri-puzzle-line"></i>
|
||||||
|
</a>
|
||||||
|
<a href="/settings" class="nav-item" title="设置">
|
||||||
|
<i class="ri-settings-3-line"></i>
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
<div class="sidebar-footer">
|
||||||
|
<button class="settings-btn" title="设置">
|
||||||
|
<i class="ri-settings-3-line"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<main class="content">
|
||||||
|
<div class="content-body">
|
||||||
|
<div class="home-content">
|
||||||
|
<div class="welcome-banner">
|
||||||
|
<h2>👋 欢迎使用 FutureOSS</h2>
|
||||||
|
<p>一切皆为插件的轻量级框架</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="features-grid">
|
||||||
|
<div class="feature-card">
|
||||||
|
<h3><i class="ri-plug-line"></i> 插件化架构</h3>
|
||||||
|
<p>所有功能皆可通过插件扩展,灵活定制您的系统</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<h3><i class="ri-shield-check-line"></i> 安全隔离</h3>
|
||||||
|
<p>进程级沙箱保护,确保插件运行安全</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<h3><i class="ri-global-line"></i> 多语言支持</h3>
|
||||||
|
<p>内置国际化框架,支持全球多种语言</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<h3><i class="ri-box-3-line"></i> 轻松部署</h3>
|
||||||
|
<p>Docker 容器化部署,一键启动服务</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="/static/js/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* 首页视图
|
|
||||||
* 这是 webui 插件的默认首页
|
|
||||||
* 其他插件可以替换或扩展此页面
|
|
||||||
*/
|
|
||||||
|
|
||||||
$pageTitle = $config['title'] ?? 'FutureOSS';
|
|
||||||
$currentPage = 'home';
|
|
||||||
|
|
||||||
// 默认导航项(其他插件可以添加更多)
|
|
||||||
$navItems = [];
|
|
||||||
|
|
||||||
// 内容区(其他插件可以注入内容)
|
|
||||||
$content = '<div class="empty-state"><p>暂无内容</p></div>';
|
|
||||||
|
|
||||||
include __DIR__ . '/layout.php';
|
|
||||||
33
store/@{FutureOSS}/webui/frontend/views/layout.html
Normal file
33
store/@{FutureOSS}/webui/frontend/views/layout.html
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>{{ pageTitle }}</title>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/remixicon/4.1.0/remixicon.min.css">
|
||||||
|
<link rel="stylesheet" href="/static/css/main.css">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.13.3/dist/cdn.min.js" defer></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="app">
|
||||||
|
<aside class="sidebar">
|
||||||
|
<nav class="sidebar-nav">
|
||||||
|
{{ navItems }}
|
||||||
|
</nav>
|
||||||
|
<div class="sidebar-footer">
|
||||||
|
<button class="settings-btn" title="设置">
|
||||||
|
<i class="ri-settings-3-line"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<main class="content">
|
||||||
|
<div class="content-body">
|
||||||
|
{{ content }}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="/static/js/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="zh-CN">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title><?= htmlspecialchars($pageTitle ?? 'FutureOSS') ?></title>
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/remixicon/4.1.0/remixicon.min.css">
|
|
||||||
<link rel="stylesheet" href="/static/css/main.css">
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.13.3/dist/cdn.min.js" defer></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="app">
|
|
||||||
<aside class="sidebar">
|
|
||||||
<nav class="sidebar-nav">
|
|
||||||
<?php if (!empty($navItems)): ?>
|
|
||||||
<?php foreach ($navItems as $item): ?>
|
|
||||||
<?php
|
|
||||||
$url = $item['url'] ?? '#';
|
|
||||||
$isActive = ($currentPage ?? '') === $url;
|
|
||||||
$icon = $item['icon'] ?? 'ri-dashboard-line';
|
|
||||||
// 如果图标是 emoji,转换为 remixicon 类名
|
|
||||||
$iconMap = [
|
|
||||||
'🏠' => 'ri-home-4-line',
|
|
||||||
'📊' => 'ri-dashboard-line',
|
|
||||||
'📋' => 'ri-file-list-3-line',
|
|
||||||
'🧩' => 'ri-puzzle-line',
|
|
||||||
'⚙️' => 'ri-settings-3-line',
|
|
||||||
'🔌' => 'ri-plug-line',
|
|
||||||
'📦' => 'ri-box-3-line',
|
|
||||||
'🌐' => 'ri-global-line',
|
|
||||||
];
|
|
||||||
$riIcon = $iconMap[$icon] ?? $icon;
|
|
||||||
?>
|
|
||||||
<a href="<?= htmlspecialchars($url) ?>"
|
|
||||||
class="nav-item <?= $isActive ? 'active' : '' ?>"
|
|
||||||
title="<?= htmlspecialchars($item['text'] ?? '') ?>">
|
|
||||||
<i class="<?= htmlspecialchars($riIcon) ?>"></i>
|
|
||||||
</a>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
<?php endif; ?>
|
|
||||||
</nav>
|
|
||||||
<div class="sidebar-footer">
|
|
||||||
<button class="settings-btn" title="设置">
|
|
||||||
<i class="ri-settings-3-line"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</aside>
|
|
||||||
|
|
||||||
<main class="content">
|
|
||||||
<div class="content-body">
|
|
||||||
<?php if (isset($content)): ?>
|
|
||||||
<?= $content ?>
|
|
||||||
<?php else: ?>
|
|
||||||
<div class="empty-state">
|
|
||||||
<p>暂无内容</p>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="/static/js/main.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"name": "webui",
|
"name": "webui",
|
||||||
"version": "2.0.0",
|
"version": "2.1.0",
|
||||||
"author": "FutureOSS",
|
"author": "FutureOSS",
|
||||||
"description": "Web 控制台 - 使用 PHP 前端和 MySQL 数据库",
|
"description": "Web 控制台 - 多语言支持/插件管理/安全配置/系统监控",
|
||||||
"type": "webui"
|
"type": "webui"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
@@ -11,10 +11,17 @@
|
|||||||
"args": {
|
"args": {
|
||||||
"port": 8080,
|
"port": 8080,
|
||||||
"theme": "dark",
|
"theme": "dark",
|
||||||
"title": "FutureOSS"
|
"title": "FutureOSS",
|
||||||
|
"language": "zh-CN",
|
||||||
|
"supported_languages": ["zh-CN", "en-US", "zh-TW", "ja-JP", "ko-KR", "fr-FR", "de-DE", "es-ES"],
|
||||||
|
"session_timeout": 3600,
|
||||||
|
"enable_2fa": false,
|
||||||
|
"show_plugins": true,
|
||||||
|
"show_security": true,
|
||||||
|
"show_deployments": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": ["http-api"],
|
"dependencies": ["http-api", "i18n"],
|
||||||
"permissions": ["*"],
|
"permissions": ["*"],
|
||||||
"frontend": "php",
|
"frontend": "php",
|
||||||
"database": {
|
"database": {
|
||||||
|
|||||||
@@ -1,18 +1,22 @@
|
|||||||
{
|
{
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"name": "ws-api",
|
"name": "ws-api",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"author": "FutureOSS",
|
"author": "FutureOSS",
|
||||||
"description": "WebSocket API 服务 - 实时双向通信",
|
"description": "WebSocket API 服务 - 实时双向通信/多语言支持/安全认证",
|
||||||
"type": "protocol"
|
"type": "protocol"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"args": {
|
"args": {
|
||||||
"host": "0.0.0.0",
|
"host": "0.0.0.0",
|
||||||
"port": 8081
|
"port": 8081,
|
||||||
|
"ssl_enabled": false,
|
||||||
|
"heartbeat_interval": 30,
|
||||||
|
"max_connections": 1000,
|
||||||
|
"auth_enabled": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": [],
|
"dependencies": ["i18n"],
|
||||||
"permissions": []
|
"permissions": ["lifecycle"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user