Open
Conversation
Contributor
There was a problem hiding this comment.
Hey - 我发现了 2 个问题,并给出了一些整体性反馈:
- 在
get_plugin_extension_page中,plugin_obj.name被直接插入到注入的<script>块中;建议对其进行转义或通过json.dumps(或等效方法)序列化,以避免在插件名称包含引号或特殊字符时破坏脚本或造成注入风险。 - 当前的 HTML 注入依赖
html_content.replace("</head>", injected_script + "</head>"),如果源文档缺少闭合的</head>,或者使用了不同的大小写/空白格式,就会失效;建议使用更健壮的注入策略,或者在找不到</head>时退而求其次,将脚本追加到</body>之前。 - 在前端,请求
axios.get(/api/plugin/extension_page?name=${pluginName})应该对pluginName做 URL 编码(例如使用encodeURIComponent),以正确处理带有空格或特殊字符的插件名称。
给 AI Agent 的提示词
请根据下面的代码审查意见进行修改:
## 总体意见
- 在 `get_plugin_extension_page` 中,`plugin_obj.name` 被直接插入到注入的 `<script>` 块中;建议对其进行转义或通过 `json.dumps`(或等效方法)序列化,以避免在插件名称包含引号或特殊字符时破坏脚本或造成注入风险。
- 当前的 HTML 注入依赖 `html_content.replace("</head>", injected_script + "</head>")`,如果源文档缺少闭合的 `</head>`,或者使用了不同的大小写/空白格式,就会失效;建议使用更健壮的注入策略,或者在找不到 `</head>` 时退而求其次,将脚本追加到 `</body>` 之前。
- 在前端,请求 `axios.get(`/api/plugin/extension_page?name=${pluginName}`)` 应该对 `pluginName` 做 URL 编码(例如使用 `encodeURIComponent`),以正确处理带有空格或特殊字符的插件名称。
## 逐条评论
### 评论 1
<location> `dashboard/src/views/ExtensionPage.vue:701` </location>
<code_context>
+// 获取扩展页面内容
+async function fetchExtensionPage(pluginName) {
+ try {
+ const res = await axios.get(`/api/plugin/extension_page?name=${pluginName}`);
+ if (res.data.status === "ok") {
+ extensionPageDialog.html = res.data.data.html;
</code_context>
<issue_to_address>
**issue (bug_risk):** 在构建查询字符串时对 `pluginName` 进行 URL 编码。
未编码的值如果包含空格、`?`、`&` 或非 ASCII 字符,可能会导致该请求被破坏或路由错误。请在 URL 中使用 `encodeURIComponent(pluginName)`(例如:``axios.get(`/api/plugin/extension_page?name=${encodeURIComponent(pluginName)}`)``),以确保适用于所有插件名称。
</issue_to_address>
### 评论 2
<location> `dashboard/src/views/ExtensionPage.vue:2712` </location>
<code_context>
+ <iframe
+ :srcdoc="extensionPageDialog.html"
+ style="width: 100%; height: 100%; border: none;"
+ sandbox="allow-scripts allow-forms allow-same-origin"
+ ></iframe>
</code_context>
<issue_to_address>
**🚨 issue (security):** 重新审视 iframe 的 sandbox 设置;`allow-same-origin` 会削弱对不受信任插件内容的隔离。
在同时启用 `allow-scripts` 和 `allow-same-origin` 的情况下,插件的 JS 实际上以和控制面板相同的源运行,可以读写 `localStorage`、cookies 以及 `ASTRBOT_CONFIG` 以外的其他同源数据。如果插件的 HTML 并非完全可信,这会显著扩大其可访问的范围。建议移除 `allow-same-origin`,让其在独立的源中运行,同时仍可通过你注入的脚本读取 `window.ASTRBOT_CONFIG`,或者以其他方式严格限制插件代码的可访问范围。
</issue_to_address>帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈改进后续的代码审查。
Original comment in English
Hey - I've found 2 issues, and left some high level feedback:
- In
get_plugin_extension_page,plugin_obj.nameis interpolated directly into the injected<script>block; consider escaping or serializing viajson.dumps(or equivalent) to avoid breaking the script or creating an injection vector if plugin names contain quotes or special characters. - The HTML injection relies on
html_content.replace("</head>", injected_script + "</head>"), which will fail if the source lacks a closing</head>or uses different casing/whitespace; consider a more robust injection strategy or falling back to appending the script before</body>when</head>is not found. - On the frontend, the request
axios.get(/api/plugin/extension_page?name=${pluginName})should URL-encodepluginName(e.g.,encodeURIComponent) to handle plugin names with spaces or special characters correctly.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `get_plugin_extension_page`, `plugin_obj.name` is interpolated directly into the injected `<script>` block; consider escaping or serializing via `json.dumps` (or equivalent) to avoid breaking the script or creating an injection vector if plugin names contain quotes or special characters.
- The HTML injection relies on `html_content.replace("</head>", injected_script + "</head>")`, which will fail if the source lacks a closing `</head>` or uses different casing/whitespace; consider a more robust injection strategy or falling back to appending the script before `</body>` when `</head>` is not found.
- On the frontend, the request `axios.get(`/api/plugin/extension_page?name=${pluginName}`)` should URL-encode `pluginName` (e.g., `encodeURIComponent`) to handle plugin names with spaces or special characters correctly.
## Individual Comments
### Comment 1
<location> `dashboard/src/views/ExtensionPage.vue:701` </location>
<code_context>
+// 获取扩展页面内容
+async function fetchExtensionPage(pluginName) {
+ try {
+ const res = await axios.get(`/api/plugin/extension_page?name=${pluginName}`);
+ if (res.data.status === "ok") {
+ extensionPageDialog.html = res.data.data.html;
</code_context>
<issue_to_address>
**issue (bug_risk):** URL-encode `pluginName` when building the query string.
Unencoded values containing spaces, `?`, `&`, or non-ASCII characters can break or misroute this request. Use `encodeURIComponent(pluginName)` in the URL (e.g., ``axios.get(`/api/plugin/extension_page?name=${encodeURIComponent(pluginName)}`)``) to ensure it works for all plugin names.
</issue_to_address>
### Comment 2
<location> `dashboard/src/views/ExtensionPage.vue:2712` </location>
<code_context>
+ <iframe
+ :srcdoc="extensionPageDialog.html"
+ style="width: 100%; height: 100%; border: none;"
+ sandbox="allow-scripts allow-forms allow-same-origin"
+ ></iframe>
</code_context>
<issue_to_address>
**🚨 issue (security):** Revisit the iframe sandbox settings; `allow-same-origin` weakens isolation for untrusted plugin content.
With both `allow-scripts` and `allow-same-origin`, plugin JS effectively runs as the dashboard origin and can read/write `localStorage`, cookies, and other origin-scoped data beyond `ASTRBOT_CONFIG`. If plugin HTML isn’t fully trusted, this substantially expands its access. Consider removing `allow-same-origin` so it runs in a unique origin while still reading `window.ASTRBOT_CONFIG` via your injected script, or otherwise tightly limit what plugin code can reach.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Member
|
要如何使用?方便给一个文档吗 |
Author
|
Closed
Author
可以了 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Modifications / 改动点
核心文件修改:
后端修改 (
astrbot/dashboard/routes/plugin.py)/plugin/extension_pageAPI 端点,用于获取插件扩展页面的 HTML 内容get_plugins()方法中添加extension_page字段,标识插件是否具有扩展页面<plugin_root>/web/index.htmlwindow.ASTRBOT_CONFIG配置对象(包含 API 地址、插件名称、JWT 令牌)前端组件修改 (
dashboard/src/components/shared/ExtensionCard.vue)view-extension-page事件发射器viewExtensionPage()函数mdi-web图标前端视图修改 (
dashboard/src/views/ExtensionPage.vue)extensionPageDialog响应式状态(包含 show、html、title 字段)openExtensionPage()和fetchExtensionPage()函数sandbox="allow-scripts allow-forms allow-same-origin"安全属性国际化修改
dashboard/src/i18n/locales/zh-CN/features/extension.json:添加"extensionPage": "插件扩展页面"dashboard/src/i18n/locales/en-US/features/extension.json:添加"extensionPage": "Extension Page"实现的功能:
插件可提供自定义 HTML 页面(固定位置:
web/index.html)自动检测并标识具有扩展页面的插件
扩展页面通过 iframe 沙箱环境安全加载
自动注入配置对象
window.ASTRBOT_CONFIG供前端使用使用 JWT 认证机制确保 API 通信安全
完整的向后兼容(无扩展页面的插件不受影响)
This is NOT a breaking change. / 这不是一个破坏性变更。
Screenshots or Test Results / 运行截图或测试结果
Checklist / 检查清单
requirements.txt和pyproject.toml文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations inrequirements.txtandpyproject.toml.Summary by Sourcery
为插件自定义扩展页面添加后端和前端支持,使其可以从控制台中安全查看。
新功能:
Original summary in English
Summary by Sourcery
Add backend and frontend support for plugin-defined extension pages that can be securely viewed from the dashboard.
New Features: