重构:核心迁移至 oss/core + NBPF 多重签名加密 + NIR 编译器 + README 全面升级

- 核心功能从 store/ 迁移至 oss/core/ 框架层
- 实现 NBPF 包格式:多重签名(Ed25519+RSA-PSS+HMAC)+ 多重加密(AES-256-GCM)
- 实现 NIR 编译器:基于 compile()+marshal 的跨平台中间表示
- 新增 nebula nbpf CLI 命令组(pack/unpack/verify/sign/keygen)
- 新增 19 个 NBPF 测试用例,覆盖全链路
- 彻底重写 README,大型项目标准框架风格,所有图表使用 SVG
- 更新 LICENSE 版权声明
- 清理旧版 store 插件目录(已迁移至 oss/core)
This commit is contained in:
Falck
2026-05-05 07:29:43 +08:00
parent 4441a968db
commit 3a096f59a9
184 changed files with 5715 additions and 10066 deletions

View File

View File

@@ -0,0 +1,113 @@
"""中间件链 - CORS/鉴权/日志/限流/CSRF/输入验证等"""
import json
import time
import threading
from collections import deque
from typing import Callable, Optional, Any
from oss.config import get_config
from oss.logger.logger import Log
from .server import Request, Response
from .rate_limiter import RateLimitMiddleware
class Middleware:
"""中间件基类"""
def process(self, ctx: dict[str, Any], next_fn: Callable) -> Optional[Response]:
return next_fn()
class CorsMiddleware(Middleware):
"""CORS 中间件"""
def process(self, ctx: dict, next_fn: Callable) -> Optional[Response]:
config = get_config()
allowed_origins = config.get("CORS_ALLOWED_ORIGINS", ["http://localhost:3000", "http://127.0.0.1:3000"])
req = ctx.get("request")
origin = req.headers.get("Origin", "") if req else ""
if not allowed_origins or not origin:
return next_fn()
if origin in allowed_origins or "*" in allowed_origins:
ctx["response_headers"] = {
"Access-Control-Allow-Origin": origin,
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
"Access-Control-Allow-Credentials": "true",
}
return next_fn()
class AuthMiddleware(Middleware):
"""鉴权中间件 - Bearer Token 认证"""
_public_paths = {"/health", "/favicon.ico", "/api/status", "/api/health"}
def process(self, ctx: dict, next_fn: Callable) -> Optional[Response]:
config = get_config()
api_key = config.get("API_KEY")
if not api_key:
return next_fn()
req = ctx.get("request")
if req and req.path in self._public_paths:
return next_fn()
if req and req.method == "OPTIONS":
return next_fn()
auth_header = req.headers.get("Authorization", "") if req else ""
token = auth_header.removeprefix("Bearer ").strip()
if token != api_key or not token:
Log.warn("Core", f"鉴权失败: {req.method} {req.path}" if req else "鉴权失败")
return Response(
status=401,
body=json.dumps({"error": "Unauthorized", "message": "需要有效的 API Key"}),
headers={"Content-Type": "application/json"},
)
return next_fn()
class LoggerMiddleware(Middleware):
"""日志中间件"""
_silent_paths = {"/api/dashboard/stats", "/favicon.ico", "/health"}
def process(self, ctx: dict, next_fn: Callable) -> Optional[Response]:
req = ctx.get("request")
if req and req.path not in self._silent_paths:
Log.info("Core", f"{req.method} {req.path}")
return next_fn()
class MiddlewareChain:
"""中间件链"""
def __init__(self):
self.middlewares: list[Middleware] = []
self.add(CorsMiddleware())
self.add(AuthMiddleware())
self.add(LoggerMiddleware())
self.add(RateLimitMiddleware())
def add(self, middleware: Middleware):
self.middlewares.append(middleware)
def run(self, ctx: dict[str, Any]) -> Optional[Response]:
idx = 0
def next_fn():
nonlocal idx
if idx < len(self.middlewares):
mw = self.middlewares[idx]
idx += 1
return mw.process(ctx, next_fn)
return None
resp = next_fn()
response_headers = ctx.get("response_headers")
if response_headers:
ctx["_cors_headers"] = response_headers
return resp

View File

@@ -0,0 +1,138 @@
"""
限流工具 - 令牌桶限流器
"""
import time
import threading
from typing import Dict, Callable, Optional
from collections import defaultdict, deque
from oss.config import get_config
from oss.core.http_api.server import Request, Response
class RateLimiter:
"""令牌桶限流器"""
def __init__(self, max_requests: int = 100, time_window: int = 60):
self.max_requests = max_requests
self.time_window = time_window
self.requests: Dict[str, deque] = defaultdict(deque)
self.lock = threading.Lock()
def is_allowed(self, identifier: str) -> bool:
"""检查是否允许请求"""
with self.lock:
now = time.time()
request_times = self.requests[identifier]
# 清理过期的请求记录
while request_times and request_times[0] <= now - self.time_window:
request_times.popleft()
# 检查是否超过限制
if len(request_times) >= self.max_requests:
return False
# 记录当前请求
request_times.append(now)
return True
class RateLimitMiddleware:
"""限流中间件 - 防止DoS攻击"""
def __init__(self):
self.config = get_config()
self.enabled = self.config.get("RATE_LIMIT_ENABLED", True)
# 不同端点的限流配置
self.endpoint_limits = {
"/api/dashboard/stats": {
"max_requests": 10,
"time_window": 60
},
}
# 全局限流配置
self.global_limit = {
"max_requests": self.config.get("RATE_LIMIT_MAX_REQUESTS", 100),
"time_window": self.config.get("RATE_LIMIT_TIME_WINDOW", 60)
}
# 请求记录
self.requests = {}
self.lock = threading.Lock()
def _get_client_identifier(self, request: Request) -> str:
"""获取客户端标识符"""
ip = request.headers.get("X-Forwarded-For", request.headers.get("X-Real-IP", ""))
if not ip:
ip = request.headers.get("Remote-Addr", "unknown")
auth_header = request.headers.get("Authorization", "")
if auth_header.startswith("Bearer "):
return f"api_key:{auth_header[7:]}"
return f"ip:{ip}"
def _is_rate_limited(self, identifier: str, path: str) -> bool:
"""检查是否被限流"""
if not self.enabled:
return False
now = time.time()
limit_key = f"{identifier}:{path}"
# 获取端点特定的限制
endpoint_limit = None
for endpoint, config in self.endpoint_limits.items():
if path.startswith(endpoint):
endpoint_limit = config
break
# 使用端点特定限制或全局限制
limit = endpoint_limit or self.global_limit
max_requests = limit["max_requests"]
time_window = limit["time_window"]
with self.lock:
if limit_key not in self.requests:
self.requests[limit_key] = deque()
request_times = self.requests[limit_key]
while request_times and request_times[0] <= now - time_window:
request_times.popleft()
if len(request_times) >= max_requests:
return True
request_times.append(now)
return False
def _create_rate_limit_response(self) -> Response:
"""创建限流响应"""
return Response(
status=429,
headers={
"Content-Type": "application/json",
"Retry-After": str(self.global_limit["time_window"]),
"X-Rate-Limit-Limit": str(self.global_limit["max_requests"]),
"X-Rate-Limit-Window": str(self.global_limit["time_window"]),
},
body='{"error": "Rate limit exceeded", "message": "请稍后再试"}'
)
def process(self, ctx: dict, next_fn: Callable) -> Optional[Response]:
"""处理限流逻辑"""
if not self.enabled:
return next_fn()
request = ctx.get("request")
if not request:
return next_fn()
identifier = self._get_client_identifier(request)
if self._is_rate_limited(identifier, request.path):
return self._create_rate_limit_response()
return next_fn()

View File

@@ -0,0 +1,41 @@
"""HTTP 路由 - 基于 oss/shared/router.py 的 BaseRouter"""
import json
from typing import Callable
from oss.shared.router import BaseRouter, BaseRoute, match_path, extract_path_params
from .server import Request, Response
class HttpRouter(BaseRouter):
"""HTTP 路由"""
def add(self, method: str, path: str, handler: Callable):
self.routes.append(BaseRoute(method, path, handler))
def handle(self, request: Request) -> Response:
"""匹配路由并执行处理器"""
for route in self.routes:
if route.method == request.method and match_path(route.path, request.path):
params = extract_path_params(route.path, request.path)
try:
result = route.handler(request, **params)
if isinstance(result, Response):
return result
return Response(
status=200,
body=json.dumps(result) if not isinstance(result, str) else result,
headers={"Content-Type": "application/json"}
)
except Exception as e:
return Response(
status=500,
body=json.dumps({"error": "Internal Server Error", "message": str(e)}),
headers={"Content-Type": "application/json"}
)
# 404 - 无匹配路由
return Response(
status=404,
body=json.dumps({"error": "Not Found", "message": f"路由未找到: {request.method} {request.path}"}),
headers={"Content-Type": "application/json"}
)

124
oss/core/http_api/server.py Normal file
View File

@@ -0,0 +1,124 @@
"""HTTP 服务器核心"""
import threading
from http.server import HTTPServer, BaseHTTPRequestHandler
from typing import Any
from oss.config import get_config
from oss.logger.logger import Log
class Request:
"""请求对象"""
def __init__(self, method, path, headers, body):
self.method = method
self.path = path
self.headers = headers
self.body = body
class Response:
"""响应对象"""
def __init__(self, status=200, headers=None, body=""):
self.status = status
self.headers = headers or {}
self.body = body
class HttpServer:
"""HTTP 服务器"""
def __init__(self, router, middleware, host=None, port=None):
config = get_config()
self.host = host or config.get("HOST", "127.0.0.1")
self.port = port or config.get("HTTP_API_PORT", 8080)
self.router = router
self.middleware = middleware
self._server = None
self._thread = None
def start(self):
"""启动服务器"""
handler = self._create_handler()
self._server = HTTPServer((self.host, self.port), handler)
self._thread = threading.Thread(target=self._server.serve_forever, daemon=True)
self._thread.start()
Log.info("Core", f"HTTP 服务器启动: {self.host}:{self.port}")
def stop(self):
"""停止服务器"""
if self._server:
self._server.shutdown()
Log.info("Core", "HTTP 服务器已停止")
def _create_handler(self):
"""创建请求处理器"""
router = self.router
middleware = self.middleware
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self._handle("GET")
def do_POST(self):
self._handle("POST")
def do_PUT(self):
self._handle("PUT")
def do_DELETE(self):
self._handle("DELETE")
def do_OPTIONS(self):
"""处理 CORS 预检请求"""
config = get_config()
allowed_origins = config.get("CORS_ALLOWED_ORIGINS", ["http://localhost:3000", "http://127.0.0.1:3000"])
origin = self.headers.get("Origin", "")
if origin in allowed_origins or "*" in allowed_origins:
self.send_response(200)
self.send_header("Access-Control-Allow-Origin", origin if origin else "*")
self.send_header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
self.send_header("Access-Control-Allow-Headers", "Content-Type, Authorization")
self.send_header("Access-Control-Allow-Credentials", "true")
else:
self.send_response(204)
self.end_headers()
def _handle(self, method):
content_length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(content_length) if content_length else b""
req = Request(
method=method,
path=self.path,
headers=dict(self.headers),
body=body.decode("utf-8")
)
# 执行中间件
ctx = {"request": req, "response": None}
result = middleware.run(ctx)
if result:
self._send_response(result)
return
# 路由匹配
resp = router.handle(req)
self._send_response(resp)
def _send_response(self, resp: Response):
try:
self.send_response(resp.status)
for k, v in resp.headers.items():
self.send_header(k, v)
self.end_headers()
if isinstance(resp.body, str):
self.wfile.write(resp.body.encode("utf-8"))
else:
self.wfile.write(resp.body)
except (BrokenPipeError, ConnectionAbortedError, ConnectionResetError):
pass # 忽略客户端断开
def log_message(self, format, *args):
Log.debug("Core", format % args)
return Handler