172 lines
5.8 KiB
Markdown
172 lines
5.8 KiB
Markdown
# PL 注入机制使用说明
|
||
|
||
## 概述
|
||
|
||
PL 注入机制允许插件通过 `PL/` 文件夹向插件加载器注册自定义功能。插件加载器在启动时会自动扫描所有插件,检查其 `manifest.json` 中是否声明了 `pl_injection` 配置项。
|
||
|
||
## 使用步骤
|
||
|
||
### 1. 在 manifest.json 中声明 pl_injection
|
||
|
||
在插件的 `manifest.json` 的 `config.args` 中添加 `"pl_injection": true`:
|
||
|
||
```json
|
||
{
|
||
"metadata": {
|
||
"name": "my-plugin",
|
||
"version": "1.0.0",
|
||
"author": "MyName",
|
||
"description": "我的插件",
|
||
"type": "utility"
|
||
},
|
||
"config": {
|
||
"enabled": true,
|
||
"args": {
|
||
"pl_injection": true
|
||
}
|
||
},
|
||
"dependencies": [],
|
||
"permissions": []
|
||
}
|
||
```
|
||
|
||
### 2. 创建 PL/ 文件夹和 PL/main.py
|
||
|
||
在插件目录下创建 `PL/` 文件夹,并在其中创建 `main.py`:
|
||
|
||
```
|
||
store/@{MyName}/my-plugin/
|
||
├── manifest.json # 声明 pl_injection: true
|
||
├── main.py # 插件主逻辑
|
||
├── PL/ # PL 注入文件夹
|
||
│ └── main.py # 注入逻辑(必须包含 register() 函数)
|
||
└── README.md
|
||
```
|
||
|
||
### 3. 实现 PL/main.py
|
||
|
||
`PL/main.py` 必须导出一个 `register(injector)` 函数,接收一个 `PLInjector` 实例:
|
||
|
||
```python
|
||
# PL/main.py
|
||
"""PL 注入 - 向插件加载器注册功能"""
|
||
|
||
def register(injector):
|
||
"""向插件加载器注册功能
|
||
|
||
Args:
|
||
injector: PLInjector 实例,提供以下注册方法:
|
||
- register_function(name, func, description="")
|
||
- register_route(method, path, handler)
|
||
- register_event_handler(event_name, handler)
|
||
"""
|
||
|
||
# 示例 1: 注册一个普通功能
|
||
def my_helper():
|
||
print("这是从 PL 注入的功能")
|
||
|
||
injector.register_function("my_helper", my_helper, "一个辅助功能")
|
||
|
||
# 示例 2: 注册 HTTP 路由
|
||
def hello_handler(request):
|
||
return {"message": "Hello from PL injection!"}
|
||
|
||
injector.register_route("GET", "/pl/hello", hello_handler)
|
||
|
||
# 示例 3: 注册事件处理器
|
||
def on_plugin_started(plugin_name):
|
||
print(f"插件 {plugin_name} 已启动")
|
||
|
||
injector.register_event_handler("plugin.started", on_plugin_started)
|
||
```
|
||
|
||
### 4. 引用其他文件
|
||
|
||
`PL/main.py` 可以引用 `PL/` 文件夹下的其他 Python 文件:
|
||
|
||
```
|
||
store/@{MyName}/my-plugin/PL/
|
||
├── main.py # 入口,包含 register() 函数
|
||
├── helpers.py # 辅助函数(被 main.py 引用)
|
||
└── routes.py # 路由定义(被 main.py 引用)
|
||
```
|
||
|
||
```python
|
||
# PL/main.py
|
||
from .helpers import format_response
|
||
from .routes import register_routes
|
||
|
||
def register(injector):
|
||
def my_handler():
|
||
return format_response("Hello")
|
||
injector.register_function("my_handler", my_handler)
|
||
register_routes(injector)
|
||
```
|
||
|
||
## 行为说明
|
||
|
||
| 场景 | 结果 |
|
||
|------|------|
|
||
| manifest.json 中 `pl_injection: true` + 存在 `PL/main.py` | ✅ 正常加载,执行注入 |
|
||
| manifest.json 中 `pl_injection: true` + 缺少 `PL/` 文件夹 | ❌ 警告并拒绝加载该插件 |
|
||
| manifest.json 中 `pl_injection: true` + 存在 `PL/` 但缺少 `main.py` | ❌ 警告并拒绝加载该插件 |
|
||
| manifest.json 中未声明 `pl_injection` | ✅ 正常加载,跳过 PL 检查 |
|
||
| manifest.json 中 `pl_injection: false` | ✅ 正常加载,跳过 PL 检查 |
|
||
|
||
## 安全限制
|
||
|
||
PL 注入机制实施了多层安全限制,防止恶意代码注入:
|
||
|
||
### 1. 文件类型限制
|
||
- PL 文件夹中禁止包含 `.sh`、`.bat`、`.exe`、`.dll`、`.so`、`.dylib`、`.bin` 等可执行/二进制文件
|
||
- 违反则拒绝加载该插件
|
||
|
||
### 2. 静态源码安全检查
|
||
PL/main.py 源码在编译前会进行静态扫描,禁止以下操作:
|
||
- 导入系统级模块(`os`、`sys`、`subprocess`、`shutil`、`socket`、`ctypes`、`cffi`、`multiprocessing`、`threading`)
|
||
- 使用 `__import__`、`exec`、`eval`、`compile`
|
||
- 直接操作文件(`open`)
|
||
- 访问 `__builtins__`
|
||
|
||
### 3. 沙箱执行环境
|
||
PL/main.py 在受限的沙箱中执行,仅提供安全的 builtins:
|
||
- 基础类型:`dict`、`list`、`str`、`int`、`float`、`bool`、`tuple`、`set`
|
||
- 安全函数:`len`、`range`、`enumerate`、`zip`、`map`、`filter`、`sorted` 等
|
||
- 异常类型:`Exception`、`ValueError`、`TypeError`、`KeyError`、`IndexError`
|
||
|
||
### 4. 参数校验
|
||
| 校验项 | 限制 |
|
||
|--------|------|
|
||
| 功能名称 | 仅允许字母、数字、下划线、冒号、斜杠、连字符、点,最长 128 字符 |
|
||
| 路由路径 | 必须以 `/` 开头,禁止 `..`、`//`、`/\.`、`~`、`%`,最长 256 字符 |
|
||
| HTTP 方法 | 仅允许 GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS |
|
||
| 事件名称 | 字母开头,仅允许字母、数字、点、下划线,最长 128 字符 |
|
||
| 功能描述 | 最长 256 字符 |
|
||
|
||
### 5. 数量限制
|
||
| 限制项 | 上限 |
|
||
|--------|------|
|
||
| 每个插件最多注册的功能数 | 50 |
|
||
| 每个功能名称最多被注册次数 | 10 |
|
||
|
||
### 6. 异常安全
|
||
- 所有注册的函数会被自动包装,执行时抛出异常不会影响主流程
|
||
- 异常会被记录到日志,函数返回 `None`
|
||
|
||
### 7. 调用者溯源
|
||
- 通过栈帧回溯自动识别调用者插件名
|
||
- 防止其他插件冒充注册
|
||
|
||
## 注入器 API
|
||
|
||
`PLInjector` 实例提供以下方法供 `PL/main.py` 调用:
|
||
|
||
| 方法 | 说明 |
|
||
|------|------|
|
||
| `register_function(name, func, description="")` | 注册一个注入功能 |
|
||
| `register_route(method, path, handler)` | 注册 HTTP 路由 |
|
||
| `register_event_handler(event_name, handler)` | 注册事件处理器 |
|
||
| `get_injected_functions(name=None)` | 获取已注册的注入功能 |
|
||
| `get_injection_info(plugin_name=None)` | 获取注入信息 |
|
||
| `has_injection(plugin_name)` | 检查插件是否有 PL 注入 |
|
||
| `get_registry_info()` | 获取注册表完整信息(用于监控) | |