feat: custom menu pages with iframe embedding and CSP injection#727
Merged
Wei-Shaw merged 9 commits intoWei-Shaw:mainfrom Mar 3, 2026
Merged
feat: custom menu pages with iframe embedding and CSP injection#727Wei-Shaw merged 9 commits intoWei-Shaw:mainfrom
Wei-Shaw merged 9 commits intoWei-Shaw:mainfrom
Conversation
Add configurable custom menu items that appear in sidebar, each rendering an iframe-embedded external page. Includes shared URL builder with src_host/src_url tracking, CSP frame-src multi-origin deduplication, admin settings UI, and i18n support. chore: bump version to 0.1.87.19 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add admin menu permission check in CustomPageView (visibility + role) - Sanitize SVG content with DOMPurify before v-html rendering (XSS prevention) - Decouple router.go from dto package using anonymous struct - Consolidate duplicate parseCustomMenuItems into dto.ParseCustomMenuItems - Enhance menu item validation (count, length, ID uniqueness limits) - Add audit logging for purchase_subscription and custom_menu_items changes - Update API contract test to include custom_menu_items field Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. (Critical) Filter admin-only menu items from public API responses - both GetPublicSettings handler and GetPublicSettingsForInjection now exclude visibility=admin items, preventing unauthorized access to admin menu URLs. 2. (Medium) Validate JSON array structure in sanitizeCustomMenuItemsJSON - use json.Unmarshal into []json.RawMessage instead of json.Valid to reject non-array JSON values that would cause frontend runtime errors. 3. (Medium) Decouple router from business JSON parsing - move origin extraction logic from router.go to SettingService.GetFrameSrcOrigins, eliminating direct JSON parsing of custom_menu_items in the routing layer. 4. (Low) Restrict custom menu item ID charset to [a-zA-Z0-9_-] via regex validation, preventing route-breaking characters like / ? # or spaces. 5. (Low) Handle crypto/rand error in generateMenuItemID - return error instead of silently ignoring, preventing potential duplicate IDs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaced by filterUserVisibleMenuItems which includes both array validation and admin-item filtering. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
xuebkgithub
pushed a commit
to xuebkgithub/sub2api
that referenced
this pull request
Mar 3, 2026
feat: custom menu pages with iframe embedding and CSP injection
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.
背景 / Background
当前系统的 iframe 嵌入页面(如充值/订阅)缺乏自动化的 CSP frame-src 策略管理,每次新增 iframe 来源需要手动修改配置。同时管理员无法灵活地在侧边栏添加自定义页面(如文档、FAQ、第三方工具等),限制了系统的可扩展性。
The system's iframe embedded pages (e.g., purchase/subscription) lack automated CSP frame-src policy management — every new iframe origin requires manual configuration changes. Additionally, admins cannot flexibly add custom pages (docs, FAQ, third-party tools, etc.) to the sidebar, limiting extensibility.
目的 / Purpose
CSP frame-src 策略自动管理:根据系统设置中的所有 iframe URL(purchase_subscription_url + 自定义菜单项)自动提取、注入对应 origin 并去重
充值/订阅页面重构:将 URL 构建逻辑提取为共享工具函数,供充值页面和自定义页面复用
支持管理员通过后台配置,向侧边栏导航添加任意数量的自定义 iframe 页面
提供完整的安全防护:URL 格式校验、SVG 图标净化、菜单项数量限制
Automatic CSP frame-src management: auto-extract, inject, and deduplicate origins from all iframe URLs (purchase_subscription_url + custom menu items) based on system settings
Purchase/subscription page refactor: extract URL construction logic into a shared utility for reuse by both purchase page and custom pages
Allow admins to add an arbitrary number of custom iframe pages to the sidebar navigation via backend settings
Comprehensive security: URL format validation, SVG icon sanitization, menu item count limits
改动内容 / Changes
后端 / Backend
SecurityHeaders中间件新增可选getFrameSrcOrigins回调参数,每个请求动态注入 iframe 所需的 frame-src originsrouter.go使用atomic.Pointer缓存 iframe origin 列表(从purchase_subscription_url和custom_menu_items中提取并去重),设置更新时自动刷新setting_handler.go实现菜单项的验证与序列化(URL 必须为绝对 http/https、icon_svg 最大 10KB、最多 20 个菜单项、ID 唯一性校验)purchase_subscription_*和custom_menu_items字段GetPublicSettingsForInjection包含custom_menu_items,使用json.RawMessage避免双重序列化domain_constants.go中的弯引号为直引号SecurityHeadersmiddleware accepts an optionalgetFrameSrcOriginscallback to dynamically inject frame-src origins per requestrouter.gousesatomic.Pointerto cache iframe origin list (extracted and deduplicated frompurchase_subscription_urlandcustom_menu_items), auto-refreshing on settings updatesetting_handler.goimplements validation and serialization (URLs must be absolute http/https, icon_svg max 10KB, max 20 items, unique ID enforcement)purchase_subscription_*andcustom_menu_itemsfieldsGetPublicSettingsForInjectionincludescustom_menu_itemsusingjson.RawMessageto avoid double serializationdomain_constants.go前端 / Frontend
PurchaseSubscriptionView.vue的 URL 构建逻辑(user_id、token、theme、ui_mode 参数拼接)提取到共享工具embedded-url.ts,消除重复代码CustomPageView.vue复用embedded-url.ts,支持 iframe 嵌入自定义 URLAppSidebar.vue根据 visibility(user/admin)渲染自定义菜单项,支持 SVG 图标显示SettingsView.vue提供自定义菜单编辑器(增删改、拖拽排序)sanitize.ts使用 DOMPurify 净化用户上传的 SVG 内容PurchaseSubscriptionView.vueURL construction logic (user_id, token, theme, ui_mode params) extracted to shared utilityembedded-url.ts, eliminating duplicated codeCustomPageView.vuereusesembedded-url.tsfor iframe-embedded custom URLsAppSidebar.vuerenders custom menu items by visibility (user/admin) with SVG icon supportSettingsView.vueprovides custom menu editor (add/remove/edit/drag-to-reorder)sanitize.tsuses DOMPurify to sanitize user-uploaded SVG content