Council
4df288c62a
refactor(phase4.1): 短码设计改为明文 goods_id 方案,O(1) 解码
...
设计变更:
- 旧方案:位打包 (goods_id<<17|ticket_id),需要暴力搜索 goods_id
- 新方案:goods_id(4位base36) + ticket_id(5位base36) → Feistel8 → 短码
新设计优势:
- 解码 O(1):直接取前4位=goods_id,后5位=ticket_id
- 无需暴力搜索,只需验证 hint 匹配
- goods_id 范围扩大:0-1,679,615(4位base36)
- ticket_id 范围扩大:0-1,073,741,823(5位base36)
- 安全性不变:Feistel8 混淆仍保护 ticket_id
技术实现:
- shortCodeEncode: base36 固定4位/5位 padding → intval → Feistel8
- shortCodeDecode: 有 hint 直接验证,无 hint 暴力搜索
- 校验边界:goods_id ≤ 0xFFFFFF, ticket_id ≤ 0x3FFFFFFF
2026-04-22 23:37:33 +08:00
Council
223c4f3647
fix(phase4.1): 修复安全问题和代码优化
...
安全修复:
- getVrSecret(): 默认密钥必须 throw 异常阻断,不再仅 warning
未配置 VR_TICKET_SECRET 时直接抛出异常,防止生产环境静默使用默认密钥
校验增强:
- shortCodeEncode(): 增加 goods_id 超 16bit 校验
goods_id > 65535 时抛出异常,防止位截断静默错误
代码优化:
- shortCodeDecode(): 简化候选列表构建逻辑
用 start/end 范围替代候选数组,消除冗余内存分配
测试补充:
- 添加 goods_id 超 16bit 边界测试
- 添加默认密钥异常说明测试
2026-04-22 23:26:31 +08:00
Council
c3bf8ba2aa
feat(phase4): Phase 4.1 基础设施 - Feistel-8 + QR签名 + 短码编解码
...
Phase 4.1 完成:
- BaseService.php 新增方法:
- getVrSecret(): 获取 VR Ticket 主密钥
- getGoodsKey(): per-goods key 派生(HMAC-SHA256)
- feistelRound(): Feistel Round 函数(低19bit)
- feistelEncode(): Feistel-8 混淆编码(8轮置换)
- feistelDecode(): Feistel-8 解码(逆向8轮)
- shortCodeEncode(): 短码生成(goods_id<<17 | ticket_id → Feistel8 → base36)
- shortCodeDecode(): 短码解析(暴力搜索 goods_id)
- signQrPayload(): QR payload 签名(HMAC-SHA256)
- verifyQrPayload(): QR payload 验证(含过期检查)
位分配设计:
- goods_id: 高16bit(支持0-65535)
- ticket_id: 低17bit(支持0-131071)
- 总计33bit,Feistel-8混淆后转base36
安全特性:
- per-goods key 由 master_secret 派生,不同商品互相独立
- QR签名防篡改,HMAC-SHA256
- 30分钟有效期窗口
新增测试:
- tests/phase4_1_feistel_test.php
2026-04-22 18:51:22 +08:00
Council
ffeda44ddc
feat(Phase 3): 演播室选择器+层级售罄灰化+短码Feistel架构规划
2026-04-22 16:39:39 +08:00
Council
2452fde466
refactor(vr_ticket): full plugin restructure - Admin.php root pattern + Hook.php
...
Phase 2 completion - complete backend management rebuild:
Plugin architecture change (旧 → 新):
- 删: admin/controller/ 子目录多控制器 → 留: admin/Admin.php 单控制器
- 删: admin/view/ → 留: view/{module}/
- 删: EventListener.php, app.php, plugin.json → 留: Hook.php, config.json
New files:
- Hook.php: 插件钩子入口(侧边栏菜单 + 订单支付处理)
- config.json: 插件配置(is_enable 等)
- install.sql / uninstall.sql: 安装卸载脚本
- view/venue/list.html, save.html: 场馆管理视图(AmazeUI)
- view/admin/setup.html: 插件设置页
Modified files:
- service/AuditService.php, BaseService.php, SeatSkuService.php, TicketService.php
- admin/Admin.php: 全新 Admin.php 根目录控制器
ShopXO core changes:
- app/index/controller/Goods.php: ticket 类型商品详情页路由
- app/service/AdminPowerService.php: 权限系统适配
- config/shopxo.php: 配置
AmazeUI frontend migration:
- All views migrated from LayUI to AmazeUI
- Vue 3 editor for venue/seat configuration
- CDN: unpkg.com → cdn.staticfile.net
Fixes included:
- Infinite loading (missing footer include)
- Vue3 textarea interpolation bug
- Template path resolution (../../../plugins/...)
- Hook return fields (id/url/is_show)
- DB field names verified from source
2026-04-17 00:46:00 +08:00
Council
f6bcad6bfb
fix: 表名前缀修复 + 创建缺失的audit_log表
...
- BaseService::table() 从 'plugins_vr_' 改为 'vr_'
(原名 plugins_vr_seat_templates → ShopXO前缀后变成 vrt_plugins_vr_seat_templates,实际表名是 vrt_vr_seat_templates)
- Admin.php 所有硬编码 Db::name('plugins_vr_xxx') 改为 Db::name('vr_xxx')
- 在数据库创建缺失的 vrt_vr_audit_log 表
2026-04-16 17:23:40 +08:00
Council
5e9c111370
council(draft): BackendArchitect - P0-A initGoodsSpecs + P0-B BatchGenerate
...
P0-A: BaseService::initGoodsSpecs() — 启用 is_exist_many_spec=1,
插入 $vr-场馆/$vr-分区/$vr-时段/$vr-座位号 四维规格类型,幂等保护
P0-B: 新建 SeatSkuService.php,含:
- BatchGenerate(): 批量生成座位级 SKU(500条/批,直接 SQL INSERT)
- UpdateSessionSku(): 按场次更新 $vr-时段 维度
- 幂等:已存在座位不重复生成
关联:Issue #9
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 20:00:29 +08:00
Council
098bcfe780
fix(P0): P0-1 idempotent ticket issuance, P0-3 XSS, P0-4 QR secret exception
...
P0-1: issueTicket() now checks for existing tickets by (order_id, spec_base_id)
before inserting. Prevents duplicate tickets on HTTP retry/multi-instance.
P0-3: Removed |raw from simple_desc and content in ticket_detail.html.
Prevents stored XSS via malicious admin content injection.
P0-4: getQrSecret() now throws exception if VR_TICKET_QR_SECRET is unset,
instead of falling back to insecure default key.
2026-04-15 16:59:22 +08:00
Council
1afd547444
feat: import ShopXO v6.8.0 sourcecode (vendor/runtime excluded)
...
- ShopXO core + plugins/vr_ticket
- Goods.php item_type=ticket routing (Phase 1)
- vr_ticket plugin skeleton (Phase 0/1)
- Admin auth Base controller (Phase 2)
- All Phase 0/1/2 code included
Closes: tracks all ShopXO core modifications in monorepo
2026-04-15 13:09:44 +08:00