@
chore(quantik-game): полировка по финальному ревью + security-review
Финальное ревью: READY TO MERGE (0 блокеров). Security: SECURE (0 critical).
Применены дешёвые фиксы из ревью:
- validateSpec: блок game{} санитизируется ПОИМЁННО (chapter/subject →
sanitizeText, order/par_ms/unlockStars → проверка типа, неизвестные ключи
отбрасываются) — закрыт латентный хранимый XSS (раньше clean.game=spec.game).
- quantik.html: @media (prefers-reduced-motion) делает анимации мгновенными
(не выключает — иначе forwards-появление узлов оставило бы их скрытыми).
- progress-logic.js: фикс комментария isUnlocked (сумма звёзд по ВСЕМ уровням
с меньшим глобальным order, а не «той же главы»).
План: Ф6 (лидерборд/гонка) удалена (Amendment 1, решение пользователя);
финальные гейты отмечены; deferred-бэклог зафиксирован.
Затронутые тесты 45/45; lint:routes 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@
This commit is contained in:
@@ -275,10 +275,18 @@ function validateSpec(spec) {
|
||||
clean.goal = cg;
|
||||
}
|
||||
|
||||
// game{} — зарезервированный блок мета-слоя (Фаза 1/5). Пропускаем как есть
|
||||
// (проверен общими лимитами: размер/глубина). Не исполняем.
|
||||
// game{} — мета-слой игрового уровня (Фаза 1/5). Санитизируем ПОИМЁННО (как goal):
|
||||
// строки → sanitizeText (escape), числа → проверка типа, неизвестные ключи отбрасываем.
|
||||
// Иначе произвольная строка в game.* стала бы хранимым XSS у любого, кому раздали уровень.
|
||||
if (spec.game && typeof spec.game === 'object' && !Array.isArray(spec.game)) {
|
||||
clean.game = spec.game;
|
||||
const gm = spec.game;
|
||||
const cgm = {};
|
||||
if (gm.chapter !== undefined) cgm.chapter = sanitizeText(gm.chapter, 60);
|
||||
if (gm.subject !== undefined) cgm.subject = sanitizeText(gm.subject, 60);
|
||||
if (typeof gm.order === 'number') cgm.order = gm.order;
|
||||
if (typeof gm.par_ms === 'number') cgm.par_ms = gm.par_ms;
|
||||
if (typeof gm.unlockStars === 'number') cgm.unlockStars = gm.unlockStars;
|
||||
clean.game = cgm;
|
||||
}
|
||||
|
||||
if (errs.length) return { ok: false, error: errs.slice(0, 8).join('; ') };
|
||||
|
||||
Reference in New Issue
Block a user