Commit Graph

66 Commits

Author SHA1 Message Date
Maxim Dolgolyov 70a89439f3 feat: добавлены 2 новых сборника — ЦЭ,ЦТ 2023 Физика V1 + ЦТ 2021 Математика V1
- seed_phys_ce2023.js: 30 вопросов (A1-A10 + B1-B20)
  Темы: измерительные приборы, путь по v(t), F по vx(t),
  единица давления, теплоёмкость, схема цепи, закон Ома,
  отражение, переход атома водорода, электроны в F.
  Part B: средняя скорость, встречное движение, x(t)→Ek,
  сила Лоренца, контур LC, рассеивающая линза.

- seed_math_ct2021.js: 25 вопросов (A1-A18 + B1-B14)
  Темы: равнобедренный треугольник, дроби, уравнения,
  неравенства, деление отрезка, чётные функции,
  arcsin/arccos, перпендикулярные плоскости,
  сечение цилиндра, показательные неравенства.

Итого в базе: 939 вопросов.
Перенесено: ЦЭ,ЦТ 2024 Физика + Матем, ЦЭ,ЦТ 2023 Физика, ЦТ 2021 Матем.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 21:51:10 +03:00
Maxim Dolgolyov 9f1a877d57 feat: ЦЭ,ЦТ 2024 — 210 новых вопросов по физике и математике
- seed_phys_ct2024.js: 93 вопроса физики (векторы, формулы МКТ,
  единицы измерения, дифракция, оптика, центростремительное ускорение,
  бросок тела, КПД, теплообмен, электростатика, фотоэффект, распад)
- seed_math_ct2024.js: 117 вопросов математики (тригонометрия,
  прогрессии, стереометрия, логарифмы, неравенства, функции,
  задачи ЦТ и ЦЭ форматов, варианты 1-10 с ключами ответов)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 21:24:25 +03:00
Maxim Dolgolyov 952a54f97c security+perf: полное ревью — 17 фиксов P0/P1 (XSS, IDOR, race conditions, rate limits, TURN, WAL)
## P0
- admin.html:2608, red-book-ecosystem.html:489-495 — XSS: u.name/node.name_ru/description обернуты в LS.esc()
- classController.js getAnnouncements — добавлена проверка teacher_id (B14: учитель A не может читать объявления класса B)

## P1 — auth & validation
- authController.js — минимум пароля 6→8 символов (register + change password + login.html)
- gamificationController adminAward — валидация max XP/coins (1M), Number coercion
- shopController adminAwardCoins — валидация max + проверка changes>0

## P1 — race conditions
- petController.buyBg — atomic UPDATE WHERE coins>=? (race-safe)
- shopController.purchaseItem — atomic conditional UPDATE
- liveController — добавлен question_id в live_answers (миграция с пересозданием таблицы), история ответов сохраняется при смене вопроса учителем
- ws-server: invalidateDrawCache экспортирован, classroomController grant/revoke вызывают его → permission revoke применяется мгновенно (раньше до 10s stale)

## P1 — rate limits & retry
- rateLimit middleware: новый параметр byUser=true (использует req.user.id вместо IP — не блокирует пользователей за NAT)
- routes/classroom.js: reactionLimiter (15/5s) на /chat/:msgId/react, handLimiter (5/5s) на raise/lower hand
- api.js sendAnswer — retry 3x с exp backoff (300/1200/2700ms), не повторяет на 4xx (F5)

## P1 — performance
- classroomController.getStrokes — LIMIT 5000 + флаг hasMore (защита от OOM на 10K+ strokes)
- whiteboard.js _liveStrokes — TTL 1.5s на каждый live preview (auto-cleanup при крашe ремоут юзера)

## Infrastructure
- config.js: TURN_URL/USER/PASS env vars
- server.js: GET /api/ice-servers возвращает STUN + опциональный TURN из env
- classroom-rtc.js: фетчит /api/ice-servers вместо хардкода (поддержка TURN для NAT/CGNAT школьных сетей)
- .env.example: документация TURN
- db.js: PRAGMA synchronous=NORMAL (5x быстрее с WAL), cache_size 16MB, temp_store=MEMORY
- ws-server.js closeAll() + server.js shutdown — graceful WS shutdown при SIGTERM

## False positives (не баги, агенты ошиблись)
- assignmentController FK на tests — на самом деле users (migrate.js:317-318)
- .env в git — gitignore корректно исключает
- admin.html без requireAuth — есть LS.initPage() который вызывает requireAuth
- submissionsController IDOR — обе ручки уже проверяют teacher_id
- screenSender = null inside try/catch — на самом деле снаружи
- SSE без backoff — есть exponential 2s→30s
- sessionController NOT IN на пустом массиве — есть guard usedIds.length>0
- getChat без LIMIT — есть LIMIT 100/200
- trust proxy — установлен на server.js:105

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-23 12:16:08 +03:00
Maxim Dolgolyov 2ae06ba2f1 refactor: B5 + B7 — pet DDL в migrate.js, requirePermission для admin-роутов
B5: убрать inline ALTER TABLE из petController.js → перенести в migrate.js
    (pet_name, pet_color, pet_last_petted, pet_petting_streak, pet_last_star,
     pet_bg, pet_bg_owned, pet_last_fed)

B7: gamification/shop admin endpoints:
    - /admin/award, /admin/stats, /admin/user/:id → requirePermission('gamification.manage')
    - /shop/admin/items(GET), /admin/award-coins, /admin/stats → requirePermission('shop.manage')
    - Деструктивные операции (reset, create/update/delete items) — requireRole('admin')
    Оба пермишна существуют в PERM_DEFAULTS (default false для teacher, admin всегда проходит)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 11:46:42 +03:00
Maxim Dolgolyov 3a4623a60a fix: полное ревью системы — 15 исправлений безопасности и надёжности
Безопасность:
- tests/🆔 скрыть is_correct и explanation для студентов (P0)
- SQL injection: limit/offset через placeholder вместо template literal
- Stored XSS: stripTags для lesson comments, flashcards, redBook sightings
- profile.html: escape e.message в showMsg (XSS через server error)
- attachment_url: валидация только /uploads/* путей
- requestId: генерировать UUID сервером, не доверять клиенту
- register: скрыть token_version из ответа

Надёжность:
- register: обработка UNIQUE constraint race condition
- pet buyBg: re-check баланса внутри транзакции
- DB errors: скрыть e.message в testController/questionController/courseController
- preferences: лимит 50KB на размер JSON

UX:
- board.html: debounce 250ms на search input

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 10:59:19 +03:00
Maxim Dolgolyov 6cd0cf34d4 fix: глубокое ревью онлайн-урока — 14 исправлений (P0-P3)
P0 — краши:
- CREATE TABLE classroom_hands в migrate.js (отсутствовала)
- emit→emitToUser для allowDraw/revokeDraw/mutePeer (WS доставка)
- deleteHistorySession обёрнут в db.transaction() + добавлена очистка hands/invites

P1 — гонки и безопасность:
- deletePage: 4 SQL в транзакции (race при параллельной записи)
- postStrokes: MAX(seq) внутрь транзакции (дубли seq)
- duplicatePage: добавлен seq в INSERT (NOT NULL crash)
- hasAccess для lowerHand/getHands/reactToMessage (утечка данных)
- loadTemplate: проверка owner шаблона
- attachment_url: только /uploads/* (XSS через javascript:/data: URI)
- wbFlushBatch: backoff при ошибке (было 12.5 req/s retry)
- pagehide leave: keepalive fetch для гарантированной доставки
- _wbOwnIds: cap 2000 (утечка памяти на длинных уроках)

P2-P3:
- simState: лимит 64KB (предотвращает OOM broadcast)
- ws-server кеши: cleanup drawCache при invalidateSession

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 09:22:39 +03:00
Maxim Dolgolyov f1e6ed7f2d fix: ревью онлайн-урока — 8 исправлений багов, уязвимостей и улучшений
- draw_permitted: emit→emitToUser (WS доставка вместо SSE-only)
- raised hands: убран in-memory Map, единый источник — таблица classroom_hands
- endSession: очистка classroom_hands при завершении сессии
- VALID_THEMES: исправлен список (добавлен corkboard, убраны dark/grid/dots)
- XSS: crLoadOnlineStudents — inline onclick заменён на data-* + addEventListener
- signal(): проверка что target_user_id является участником сессии
- WS rate-limit: 120 msg/sec per connection
- invalidateSession при join/leave для мгновенной видимости новых участников

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 09:02:50 +03:00
Maxim Dolgolyov e18945863f fix: WebRTC сигналы теперь доставляются через WS если пользователь подключён через WebSocket
signal() в classroomController использовал emit() из sse.js напрямую —
сигналы не доходили до пользователей на WebSocket-соединении (учитель).
Исправлено: используем emitToUser() из ws-server.js, который роутит в WS
и падает на SSE только как fallback.
2026-04-15 13:53:10 +03:00
Maxim Dolgolyov 7f23cfdacd fix: тема доски синхронизируется между учителем и учениками в реальном времени
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 21:18:44 +03:00
Maxim Dolgolyov c2eb319162 feat: avatar moderation — ученик загружает фото, учитель/админ подтверждает или отклоняет
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 20:55:45 +03:00
Maxim Dolgolyov 89ba25cd20 feat: user preferences sync — server-side storage, whiteboard defaults, dashboard widget visibility
- New table `user_preferences` (user_id PK, JSON blob, updated_at)
- GET/PATCH/DELETE /api/preferences with deep-merge UPSERT
- LS.prefs singleton in api.js: dot-notation get/set, debounced flush (1.5s), server sync
- classroom.html: load wb.color/width/lineStyle/theme from prefs on init; save on change
- dashboard.html: widget configurator panel (gear button) — toggle visibility per-user, persisted server-side

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 20:17:25 +03:00
Maxim Dolgolyov b520f4b849 feat: режим аннотации поверх симуляции в онлайн-уроке + fix планиметрии (arcmark, triangle tools)
Онлайн-урок:
- Кнопка «Рисовать» в баре симуляции (только учителю)
- При активации: холст доски показывается поверх iframe (z-index), фон прозрачный
- Учитель рисует прямо поверх симуляции обычными инструментами
- Студенты видят то же самое через SSE (classroom_sim_annotate)
- Выход из режима → кнопка «Вернуться к симуляции»

Планиметрия (bugfix):
- arcmark теперь рисуется всегда (не зависит от showAngles)
- altitude/median: 1 клик на вершину треугольника (авто-находит противоположную сторону)
- centroid/orthocenter: 1 клик внутри/на треугольник

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 11:31:39 +03:00
Maxim Dolgolyov 35849cf231 feat: планиметрия — интерактивная геометрическая симуляция
- Новый файл frontend/js/labs/geometry.js (~1200 строк):
  GeoEngine (граф объектов с каскадным удалением),
  GeoViewport (система координат math↔canvas, зум/пан),
  GeoSim (полный движок: точки, отрезки, прямые, лучи,
  окружности, треугольники, многоугольники, привязка к сетке
  и точкам, undo/redo, экспорт PNG, classroom sync)
- frontend/lab.html: карточка, ctrl, sim-geometry секция,
  функции geoSetTool/geoToggle/_openGeometry, скрипт-тег
- frontend/admin.html: geometry в ADMIN_SIMS
- backend/src/db/migrate.js: таблицы geometry_tasks,
  geometry_submissions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 09:40:41 +03:00
Maxim Dolgolyov 0ac292ab9e refactor: move emitToSession broadcast into ws-server.broadcastToSession
Consolidates WS-first + SSE-fallback + guest forwarding logic
into ws-server.js so classroomController doesn't duplicate delivery.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 21:27:14 +03:00
Maxim Dolgolyov fd29acbbdd feat: WebSocket real-time + rAF render gate + guest board + screen picker
Classroom performance:
- WebSocket server (ws-server.js) for low-latency cursor & stroke preview
  Replaces HTTP POST per event → eliminates per-message auth overhead
  Session member cache (30s TTL) avoids SQLite query per WS message
  Fallback to HTTP POST when WS not connected
- Cursor throttle reduced 100ms → 33ms (~30fps)
- Stroke preview throttle reduced 50ms → 20ms
- whiteboard.js: render() is now rAF-gated (_doRender/_rafPending)
  Multiple render() calls within one frame collapse into one repaint
  document.hidden check — zero CPU when tab is in background
  visibilitychange listener restores canvas on tab focus

Guest board:
- guestClassroom.js route: public token-based read-only access
- guest-board.html: name entry + read-only whiteboard + SSE
- SSE: addGuestClient/removeGuestClient/emitToGuests

Screen share picker:
- Discord-style modal with tab switching (screen/window/tab)
- Live video preview before confirming share
- useExistingScreenStream() in ClassroomRTC

Fullscreen exit overlay:
- #cr-fs-exit-overlay button inside cr-board-wrap
- Visible only via CSS :fullscreen selector (touchpad users)

File sharing from library:
- Teacher picks file from library, sends as styled card in chat
- crDownloadLibraryFile() fetches with Bearer auth

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 18:04:59 +03:00
Maxim Dolgolyov be4d43105e LearnSpace: full-stack educational whiteboard platform
Node.js/Express backend + vanilla JS frontend.
Features: real-time collaborative whiteboard (SSE), multi-page support,
LaTeX formulas, shapes/connectors, coordinate systems, number lines,
compass, zoom/pan, Catmull-Rom pencil smoothing, ruler/protractor with
rotation & resize controls, minimap navigation overlay, auto-measurements,
multi-page thumbnails sidebar, PNG export, page templates.
Student/teacher workflows: classes, assignments, library, dashboard.
Mobile responsive. SQLite (better-sqlite3).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 10:10:37 +03:00