diff --git a/.gitignore b/.gitignore index 6c4cb07..c690cad 100644 --- a/.gitignore +++ b/.gitignore @@ -4,12 +4,11 @@ __pycache__/ *.pyc *.pyo *.pyd -.Python -env/ -venv/ + +# Dependencies .venv/ -.ENV -.venv.bak/ +venv/ +env/ pip-log.txt pip-delete-this-directory.txt .tox/ @@ -19,13 +18,6 @@ pip-delete-this-directory.txt nosetests.xml coverage.xml *.cover -*.log -*.pot -*.pyc -*.pyo -.pytest_cache/ -.mypy_cache/ -.hypothesis/ # Distribution / packaging .Python @@ -44,19 +36,28 @@ wheels/ *.egg-info/ .installed.cfg *.egg -MANIFEST -# IDEs +# Environment +.env +.env.local +.env.* + +# IDE and editor files .vscode/ .idea/ *.swp *.swo *~ +.DS_Store +Thumbs.db -# Environment variables -.env -.env.local -.env.* +# Logs +*.log + +# Testing +.tests/ +.pytest_cache/ +.hypothesis/ # OS generated files .DS_Store diff --git a/RELEASE_v1.1.0.md b/RELEASE_v1.1.0.md new file mode 100644 index 0000000..cb8f5bc --- /dev/null +++ b/RELEASE_v1.1.0.md @@ -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 +security.audit.query [limit] +security.circuit.reset + +# 运维相关 +ops.backup.create [name] +ops.backup.restore +ops.health.check +ops.quota.set [memory=512, cpu=50] + +# 部署相关 +deploy.project.detect +deploy.project.build +deploy.project.start + +# 网络相关 +ftp.user.add +frp.tunnel.create tcp +firewall.ip.block 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 | 安全 · 灵活 · 高效 diff --git a/oss/plugins/firewall.py b/oss/plugins/firewall.py new file mode 100644 index 0000000..0e8122f --- /dev/null +++ b/oss/plugins/firewall.py @@ -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("动态防火墙已停止") diff --git a/oss/plugins/frp_proxy.py b/oss/plugins/frp_proxy.py new file mode 100644 index 0000000..30dc990 --- /dev/null +++ b/oss/plugins/frp_proxy.py @@ -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 内网穿透插件已卸载") diff --git a/oss/plugins/ftp_server.py b/oss/plugins/ftp_server.py new file mode 100644 index 0000000..47375b0 --- /dev/null +++ b/oss/plugins/ftp_server.py @@ -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 服务器插件已卸载") diff --git a/oss/plugins/multi_lang_deploy.py b/oss/plugins/multi_lang_deploy.py new file mode 100644 index 0000000..1672d0f --- /dev/null +++ b/oss/plugins/multi_lang_deploy.py @@ -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("多语言部署编排器已停止") diff --git a/oss/plugins/ops_toolbox.py b/oss/plugins/ops_toolbox.py new file mode 100644 index 0000000..364b82d --- /dev/null +++ b/oss/plugins/ops_toolbox.py @@ -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("运维工具箱已停止") diff --git a/oss/plugins/security_gateway.py b/oss/plugins/security_gateway.py new file mode 100644 index 0000000..79cf694 --- /dev/null +++ b/oss/plugins/security_gateway.py @@ -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("安全网关已停止") diff --git a/oss/webui/index.html b/oss/webui/index.html new file mode 100644 index 0000000..72868b5 --- /dev/null +++ b/oss/webui/index.html @@ -0,0 +1,315 @@ + + + + + + FutureOSS v1.1.0 - 安全全能发行版 + + + +
+
+
+

🚀 FutureOSS

+

安全全能发行版 v1.1.0

+
+
+ + 系统运行正常 + +
+
+
+ +
+ +
+
+
+ 安全网关 +
🛡️
+
+
0
+
今日安全事件
+
+
+ +
+
+ 运维状态 +
⚙️
+
+
100%
+
系统健康度
+
+
+ +
+
+ 部署项目 +
📦
+
+
0
+
多语言项目
+
+
+ +
+
+ 运行时环境 +
🌐
+
+
0/5
+
已就绪语言环境
+
+
+
+ + +

🔒 安全中心

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
功能状态今日拦截操作
+ API 限流 +
防止 DDoS 攻击
+
● 启用0
+ IP 黑白名单 +
访问控制
+
● 启用0
+ 操作审计 +
记录所有关键操作
+
● 启用0
+ 熔断保护 +
异常自动隔离
+
● 待机0
+
+ +

📦 多语言部署

+
+
+ + + + +
+ + + + + + + + + + + + + + + +
项目名称语言状态构建时间操作
暂无部署项目
+
+ +

⚙️ 运维工具箱

+
+
+
+ 备份管理 +
+

一键备份/恢复系统配置和数据

+ + +
+ +
+
+ 健康检查 +
+
+ CPU 使用率 + 12% +
+
+ +
+ 内存使用率 + 34% +
+
+ + +
+ +
+
+ 资源配额 +
+

限制插件资源使用,防止系统过载

+
+ + +
+
+
+ +

🔌 已加载插件

+ + + + + + + + + + + + + +
插件名称版本描述状态操作
+
+ +
+

FutureOSS v1.1.0 安全全能发行版 | 基于进程隔离的安全架构 | HTML5 + CSS3 + Vanilla JS

+

© 2024 FutureOSS Team. All rights reserved.

+
+ + + + \ No newline at end of file diff --git a/store/@{FutureOSS}/dashboard/manifest.json b/store/@{FutureOSS}/dashboard/manifest.json index ccf9bcf..44bc438 100644 --- a/store/@{FutureOSS}/dashboard/manifest.json +++ b/store/@{FutureOSS}/dashboard/manifest.json @@ -1,15 +1,21 @@ { "metadata": { "name": "dashboard", - "version": "1.0.0", + "version": "1.1.0", "author": "FutureOSS", - "description": "WebUI 仪表盘", + "description": "WebUI 仪表盘 - 系统监控/插件管理/安全配置/多语言支持", "type": "webui-extension" }, "config": { "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": ["*"] } diff --git a/store/@{FutureOSS}/firewall/manifest.json b/store/@{FutureOSS}/firewall/manifest.json new file mode 100644 index 0000000..346974d --- /dev/null +++ b/store/@{FutureOSS}/firewall/manifest.json @@ -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"] +} diff --git a/store/@{FutureOSS}/frp-proxy/manifest.json b/store/@{FutureOSS}/frp-proxy/manifest.json new file mode 100644 index 0000000..e88db7e --- /dev/null +++ b/store/@{FutureOSS}/frp-proxy/manifest.json @@ -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"] +} diff --git a/store/@{FutureOSS}/ftp-server/manifest.json b/store/@{FutureOSS}/ftp-server/manifest.json new file mode 100644 index 0000000..aa629cb --- /dev/null +++ b/store/@{FutureOSS}/ftp-server/manifest.json @@ -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"] +} diff --git a/store/@{FutureOSS}/http-api/manifest.json b/store/@{FutureOSS}/http-api/manifest.json index 22d2e2a..fb5c4e7 100644 --- a/store/@{FutureOSS}/http-api/manifest.json +++ b/store/@{FutureOSS}/http-api/manifest.json @@ -1,18 +1,25 @@ { "metadata": { "name": "http-api", - "version": "1.0.0", + "version": "1.1.0", "author": "FutureOSS", - "description": "HTTP API 服务 - 提供 RESTful API 和路由功能", + "description": "HTTP API 服务 - 提供 RESTful API/路由功能/多语言支持/安全中间件", "type": "protocol" }, "config": { "enabled": true, "args": { "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"] } diff --git a/store/@{FutureOSS}/http-tcp/manifest.json b/store/@{FutureOSS}/http-tcp/manifest.json index e36bf76..6f552c6 100644 --- a/store/@{FutureOSS}/http-tcp/manifest.json +++ b/store/@{FutureOSS}/http-tcp/manifest.json @@ -1,18 +1,21 @@ { "metadata": { "name": "http-tcp", - "version": "1.0.0", + "version": "1.1.0", "author": "FutureOSS", - "description": "HTTP TCP 服务 - 基于 TCP 的 HTTP 协议实现", + "description": "HTTP TCP 服务 - 基于 TCP 的 HTTP 协议实现/多语言支持", "type": "protocol" }, "config": { "enabled": true, "args": { "host": "0.0.0.0", - "port": 8082 + "port": 8082, + "ssl_enabled": false, + "max_connections": 500, + "timeout": 30 } }, - "dependencies": [], - "permissions": [] + "dependencies": ["i18n"], + "permissions": ["lifecycle"] } diff --git a/store/@{FutureOSS}/i18n.disabled/__pycache__/i18n.cpython-313.pyc b/store/@{FutureOSS}/i18n.disabled/__pycache__/i18n.cpython-313.pyc deleted file mode 100644 index 214108e..0000000 Binary files a/store/@{FutureOSS}/i18n.disabled/__pycache__/i18n.cpython-313.pyc and /dev/null differ diff --git a/store/@{FutureOSS}/i18n.disabled/__pycache__/main.cpython-313.pyc b/store/@{FutureOSS}/i18n.disabled/__pycache__/main.cpython-313.pyc deleted file mode 100644 index 8fe0147..0000000 Binary files a/store/@{FutureOSS}/i18n.disabled/__pycache__/main.cpython-313.pyc and /dev/null differ diff --git a/store/@{FutureOSS}/i18n.disabled/__pycache__/middleware.cpython-313.pyc b/store/@{FutureOSS}/i18n.disabled/__pycache__/middleware.cpython-313.pyc deleted file mode 100644 index 13f7019..0000000 Binary files a/store/@{FutureOSS}/i18n.disabled/__pycache__/middleware.cpython-313.pyc and /dev/null differ diff --git a/store/@{FutureOSS}/i18n.disabled/SIGNATURE b/store/@{FutureOSS}/i18n/SIGNATURE similarity index 100% rename from store/@{FutureOSS}/i18n.disabled/SIGNATURE rename to store/@{FutureOSS}/i18n/SIGNATURE diff --git a/store/@{FutureOSS}/i18n.disabled/__init__.py b/store/@{FutureOSS}/i18n/__init__.py similarity index 100% rename from store/@{FutureOSS}/i18n.disabled/__init__.py rename to store/@{FutureOSS}/i18n/__init__.py diff --git a/store/@{FutureOSS}/i18n.disabled/i18n.py b/store/@{FutureOSS}/i18n/i18n.py similarity index 100% rename from store/@{FutureOSS}/i18n.disabled/i18n.py rename to store/@{FutureOSS}/i18n/i18n.py diff --git a/store/@{FutureOSS}/i18n.disabled/locales/en-US.json b/store/@{FutureOSS}/i18n/locales/en-US.json similarity index 100% rename from store/@{FutureOSS}/i18n.disabled/locales/en-US.json rename to store/@{FutureOSS}/i18n/locales/en-US.json diff --git a/store/@{FutureOSS}/i18n.disabled/locales/zh-CN.json b/store/@{FutureOSS}/i18n/locales/zh-CN.json similarity index 100% rename from store/@{FutureOSS}/i18n.disabled/locales/zh-CN.json rename to store/@{FutureOSS}/i18n/locales/zh-CN.json diff --git a/store/@{FutureOSS}/i18n.disabled/locales/zh-TW.json b/store/@{FutureOSS}/i18n/locales/zh-TW.json similarity index 100% rename from store/@{FutureOSS}/i18n.disabled/locales/zh-TW.json rename to store/@{FutureOSS}/i18n/locales/zh-TW.json diff --git a/store/@{FutureOSS}/i18n.disabled/main.py b/store/@{FutureOSS}/i18n/main.py similarity index 100% rename from store/@{FutureOSS}/i18n.disabled/main.py rename to store/@{FutureOSS}/i18n/main.py diff --git a/store/@{FutureOSS}/i18n.disabled/manifest.json b/store/@{FutureOSS}/i18n/manifest.json similarity index 58% rename from store/@{FutureOSS}/i18n.disabled/manifest.json rename to store/@{FutureOSS}/i18n/manifest.json index 1d63ad7..1fdee2c 100644 --- a/store/@{FutureOSS}/i18n.disabled/manifest.json +++ b/store/@{FutureOSS}/i18n/manifest.json @@ -1,9 +1,9 @@ { "metadata": { "name": "i18n", - "version": "1.0.0", + "version": "1.1.0", "author": "FutureOSS", - "description": "国际化多语言支持 - 提供翻译加载/语言切换/HTTP中间件", + "description": "国际化多语言支持 - 提供翻译加载/语言切换/HTTP中间件/WebUI集成", "type": "middleware" }, "config": { @@ -12,12 +12,13 @@ "default_locale": "zh-CN", "fallback_locale": "en-US", "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, "cookie_name": "locale", - "query_param": "lang" + "query_param": "lang", + "header_name": "Accept-Language" } }, "dependencies": [], - "permissions": ["lifecycle"] + "permissions": ["lifecycle", "http-api"] } diff --git a/store/@{FutureOSS}/i18n.disabled/middleware.py b/store/@{FutureOSS}/i18n/middleware.py similarity index 100% rename from store/@{FutureOSS}/i18n.disabled/middleware.py rename to store/@{FutureOSS}/i18n/middleware.py diff --git a/store/@{FutureOSS}/pkg-manager/manifest.json b/store/@{FutureOSS}/pkg-manager/manifest.json index d6bf07d..86915e4 100644 --- a/store/@{FutureOSS}/pkg-manager/manifest.json +++ b/store/@{FutureOSS}/pkg-manager/manifest.json @@ -1,15 +1,21 @@ { "metadata": { "name": "pkg-manager", - "version": "1.0.0", + "version": "1.1.0", "author": "FutureOSS", - "description": "插件包管理器 - 配置管理和商店", + "description": "插件包管理器 - 配置管理/商店/多语言项目部署支持", "type": "webui-extension" }, "config": { "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"], - "permissions": ["*"] + "dependencies": ["http-api", "webui", "plugin-storage", "i18n"], + "permissions": ["lifecycle", "plugin-storage"] } diff --git a/store/@{FutureOSS}/plugin-bridge/manifest.json b/store/@{FutureOSS}/plugin-bridge/manifest.json index 401e89a..8e931cb 100644 --- a/store/@{FutureOSS}/plugin-bridge/manifest.json +++ b/store/@{FutureOSS}/plugin-bridge/manifest.json @@ -1,15 +1,20 @@ { "metadata": { "name": "plugin-bridge", - "version": "1.0.0", + "version": "1.1.0", "author": "FutureOSS", - "description": "插件桥接器 - 共享事件、广播、桥接", + "description": "插件桥接器 - 共享事件/广播/桥接/多语言支持", "type": "core" }, "config": { "enabled": true, - "args": {} + "args": { + "max_events": 1000, + "event_ttl": 3600, + "broadcast_enabled": true, + "queue_size": 5000 + } }, - "dependencies": ["plugin-storage"], - "permissions": ["plugin-storage"] + "dependencies": ["plugin-storage", "i18n"], + "permissions": ["plugin-storage", "lifecycle"] } diff --git a/store/@{FutureOSS}/plugin-storage/manifest.json b/store/@{FutureOSS}/plugin-storage/manifest.json index e43fdd8..50773ef 100644 --- a/store/@{FutureOSS}/plugin-storage/manifest.json +++ b/store/@{FutureOSS}/plugin-storage/manifest.json @@ -1,17 +1,22 @@ { "metadata": { "name": "plugin-storage", - "version": "1.0.0", + "version": "1.1.0", "author": "FutureOSS", - "description": "插件存储 - 为所有插件提供隔离的键值存储服务", + "description": "插件存储 - 为所有插件提供隔离的键值存储服务/多语言支持", "type": "utility" }, "config": { "enabled": true, "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": [], - "permissions": ["*"] + "dependencies": ["i18n"], + "permissions": ["lifecycle"] } diff --git a/store/@{FutureOSS}/polyglot-deploy/manifest.json b/store/@{FutureOSS}/polyglot-deploy/manifest.json new file mode 100644 index 0000000..598db4a --- /dev/null +++ b/store/@{FutureOSS}/polyglot-deploy/manifest.json @@ -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"] +} diff --git a/store/@{FutureOSS}/signature-verifier/manifest.json b/store/@{FutureOSS}/signature-verifier/manifest.json index e76af4b..8ca5150 100644 --- a/store/@{FutureOSS}/signature-verifier/manifest.json +++ b/store/@{FutureOSS}/signature-verifier/manifest.json @@ -1,18 +1,23 @@ { "metadata": { "name": "signature-verifier", - "version": "1.0.0", + "version": "1.1.0", "author": "FutureOSS", - "description": "插件签名验证服务 - 验证官方插件完整性与来源真实性", + "description": "插件签名验证服务 - 验证官方插件完整性与来源真实性/安全增强", "type": "core" }, "config": { "enabled": true, "args": { "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"] } diff --git a/store/@{FutureOSS}/webui/core/server.py b/store/@{FutureOSS}/webui/core/server.py index b6b4535..d6fb39f 100644 --- a/store/@{FutureOSS}/webui/core/server.py +++ b/store/@{FutureOSS}/webui/core/server.py @@ -36,29 +36,54 @@ class WebUIServer: self.router.get(path, lambda req: self._render_page(path, req)) def _render_page(self, path: str, request): - """渲染页面布局+内容""" + """渲染页面布局 + 内容""" provider = self.pages.get(path) content = provider() if provider else "" # 排序导航项(首页在前) sorted_nav = sorted(self.nav_items, key=lambda x: 0 if x.get('url') == '/' else 1) - variables = { - "pageTitle": self.config.get("title", "FutureOSS"), - "currentPage": path, - "navItems": sorted_nav, - "content": content + # 构建导航项 HTML + nav_html = "" + icon_map = { + '🏠': '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', } + 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''' + + + + ''' - php_file = self.frontend_dir / "views" / "layout.php" - html = self._execute_php(str(php_file), variables) + page_title = self.config.get("title", "FutureOSS") + + # 读取 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( status=200, headers={"Content-Type": "text/html; charset=utf-8"}, body=html ) - def _default_home_content(self) -> str: """默认首页内容""" return """ diff --git a/store/@{FutureOSS}/webui/frontend/views/dashboard.php b/store/@{FutureOSS}/webui/frontend/views/dashboard.php deleted file mode 100644 index ac3ba89..0000000 --- a/store/@{FutureOSS}/webui/frontend/views/dashboard.php +++ /dev/null @@ -1,17 +0,0 @@ -

仪表盘内容加载中...

'; -} - -// 复用 layout -include __DIR__ . '/layout.php'; diff --git a/store/@{FutureOSS}/webui/frontend/views/index.html b/store/@{FutureOSS}/webui/frontend/views/index.html new file mode 100644 index 0000000..110d0dd --- /dev/null +++ b/store/@{FutureOSS}/webui/frontend/views/index.html @@ -0,0 +1,110 @@ + + + + + + FutureOSS - 首页 + + + + + +
+ + +
+
+
+
+

👋 欢迎使用 FutureOSS

+

一切皆为插件的轻量级框架

+
+ +
+
+

插件化架构

+

所有功能皆可通过插件扩展,灵活定制您的系统

+
+
+

安全隔离

+

进程级沙箱保护,确保插件运行安全

+
+
+

多语言支持

+

内置国际化框架,支持全球多种语言

+
+
+

轻松部署

+

Docker 容器化部署,一键启动服务

+
+
+
+
+
+
+ + + + diff --git a/store/@{FutureOSS}/webui/frontend/views/index.php b/store/@{FutureOSS}/webui/frontend/views/index.php deleted file mode 100644 index b2c3067..0000000 --- a/store/@{FutureOSS}/webui/frontend/views/index.php +++ /dev/null @@ -1,17 +0,0 @@ -

暂无内容

'; - -include __DIR__ . '/layout.php'; diff --git a/store/@{FutureOSS}/webui/frontend/views/layout.html b/store/@{FutureOSS}/webui/frontend/views/layout.html new file mode 100644 index 0000000..7274d7f --- /dev/null +++ b/store/@{FutureOSS}/webui/frontend/views/layout.html @@ -0,0 +1,33 @@ + + + + + + {{ pageTitle }} + + + + + +
+ + +
+
+ {{ content }} +
+
+
+ + + + diff --git a/store/@{FutureOSS}/webui/frontend/views/layout.php b/store/@{FutureOSS}/webui/frontend/views/layout.php deleted file mode 100644 index f0f12a7..0000000 --- a/store/@{FutureOSS}/webui/frontend/views/layout.php +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - <?= htmlspecialchars($pageTitle ?? 'FutureOSS') ?> - - - - - -
- - -
-
- - - -
-

暂无内容

-
- -
-
-
- - - - diff --git a/store/@{FutureOSS}/webui/manifest.json b/store/@{FutureOSS}/webui/manifest.json index a06abee..ae03373 100644 --- a/store/@{FutureOSS}/webui/manifest.json +++ b/store/@{FutureOSS}/webui/manifest.json @@ -1,9 +1,9 @@ { "metadata": { "name": "webui", - "version": "2.0.0", + "version": "2.1.0", "author": "FutureOSS", - "description": "Web 控制台 - 使用 PHP 前端和 MySQL 数据库", + "description": "Web 控制台 - 多语言支持/插件管理/安全配置/系统监控", "type": "webui" }, "config": { @@ -11,10 +11,17 @@ "args": { "port": 8080, "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": ["*"], "frontend": "php", "database": { diff --git a/store/@{FutureOSS}/ws-api/manifest.json b/store/@{FutureOSS}/ws-api/manifest.json index 11f5f8b..c19276d 100644 --- a/store/@{FutureOSS}/ws-api/manifest.json +++ b/store/@{FutureOSS}/ws-api/manifest.json @@ -1,18 +1,22 @@ { "metadata": { "name": "ws-api", - "version": "1.0.0", + "version": "1.1.0", "author": "FutureOSS", - "description": "WebSocket API 服务 - 实时双向通信", + "description": "WebSocket API 服务 - 实时双向通信/多语言支持/安全认证", "type": "protocol" }, "config": { "enabled": true, "args": { "host": "0.0.0.0", - "port": 8081 + "port": 8081, + "ssl_enabled": false, + "heartbeat_interval": 30, + "max_connections": 1000, + "auth_enabled": true } }, - "dependencies": [], - "permissions": [] + "dependencies": ["i18n"], + "permissions": ["lifecycle"] }