5.8 KiB
5.8 KiB
PL 注入机制使用说明
概述
PL 注入机制允许插件通过 PL/ 文件夹向插件加载器注册自定义功能。插件加载器在启动时会自动扫描所有插件,检查其 manifest.json 中是否声明了 pl_injection 配置项。
使用步骤
1. 在 manifest.json 中声明 pl_injection
在插件的 manifest.json 的 config.args 中添加 "pl_injection": true:
{
"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 实例:
# 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 引用)
# 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() |
获取注册表完整信息(用于监控) |