Commit Graph

4 Commits

Author SHA1 Message Date
Дмитрий be51c97dce feat(auth): A6 — реальный обратный отсчёт TOTP-окна в 2FA (Sprint 5A) 2026-05-17 02:23:26 +03:00
Дмитрий 245b76ec43 test(frontend): fix 17 ESLint errors + TwoFactorView router stub
ESLint emitted 17 errors in tests/Frontend/* (production code clean):
- 13× @typescript-eslint/no-explicit-any in axios mock casts
  (BulkActionsBar, ProjectsView, projectsStore specs)
- 3× vitest/no-disabled-tests rule-not-found
  (eslint-plugin-vitest not registered; inline-disable comments stale)
- 1× @typescript-eslint/no-unused-vars on imported beforeEach

Plus Phase 5 audit finding: TwoFactorView.spec.ts test router was
missing /recovery-use stub → Vue Router warn on every TwoFactorView mount.

Changes:
- BulkActionsBar.spec.ts, ProjectsView.spec.ts, projectsStore.spec.ts:
  replace `as any` with `as unknown as ReturnType<typeof vi.fn>` on
  axios method mocks; one case used `as unknown as { regionsOpen: bool }`
  for vm shape.
- NewProjectDialog.spec.ts, ProjectsView.spec.ts: remove stale
  `// eslint-disable-next-line vitest/no-disabled-tests` comments
  (it.skip() lines kept).
- ProjectsView.toolbar.spec.ts: drop unused `beforeEach` from import.
- TwoFactorView.spec.ts: add `/recovery-use` route stub.

Verification:
- npx eslint --max-warnings=0 → exit 0 (was 17 errors).
- npx vitest run on affected specs → 24/27 passed + 3 skipped (was same).
- TwoFactorView spec → 3/3 passed, no Vue Router warn.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 20:23:51 +03:00
Дмитрий 374724a7a3 phase2(auth-2fa): TOTP-verify endpoint + TwoFactorView интеграция
- pragmarx/google2fa@^9.0 для TOTP RFC 6238.
- AuthController::login изменён: при totp_enabled=true НЕ делает Auth::login,
  сохраняет auth.pending_user_id+pending_remember в session, возвращает
  requires_2fa=true. /me=401 пока 2FA не пройдена.
- AuthController::verifyTwoFactor: читает pending_user_id, верифицирует TOTP
  через Google2FA::verifyKey($secret, $code, window: 1) (окно ±1 = 30s).
  Success → Auth::login + regenerate + clear pending + last_login_at.
- VerifyTwoFactorRequest: regex /^\d{6}$/.
- /api/auth/2fa/verify публичный (нет session-auth до verify).

Frontend:
- auth-store::login: при requires_2fa=true user остаётся null (иначе
  isAuthenticated=true и guard пустит на /dashboard минуя 2FA).
- auth-store::verifyTwoFactor action.
- api/auth.ts::verifyTwoFactor(code).
- TwoFactorView: onMounted redirect на /login если нет pending state;
  submit → verify → /dashboard; на error - clear code + focus first cell.
  userEmail из auth.user?.email.

Pest +6 (всего 67/67 за 6.97s, 194 assertions): login для 2FA НЕ создаёт
session + verify success/неверный код/без login/валидация формата +
после verify /me=200.

Vitest +3 (всего 142/142 за 10.75s): login pending vs success state +
verifyTwoFactor success/reject. TwoFactorView spec получил setActivePinia
+ requires2fa=true для bypass onMounted-redirect.

PHPStan baseline +26 Pest TestCall warnings (накопительно).

Регресс: pint+stan passed; vitest 142/142; vite build 908ms;
story:build 21/28 за 31.28s; Pest 67/67 за 6.97s.

CLAUDE.md v1.33->v1.34, реестр Открытых_вопросов v1.42->v1.43.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 20:14:33 +03:00
Дмитрий 19096552b4 phase2(auth): закрыты 4 оставшихся auth-экрана из v8_login.html
- RegisterView: email + password (strength-meter 0..4) + 2 click-wrap'а
  (оферта + ПДн). 3-й «маркетинг» из handoff НЕ реализован (расхождение
  #2 реестра v1.13 - handoff противоречит ТЗ §1.5/§4.1).
- TwoFactorView: 6 input-cell с auto-focus вперёд при вводе цифры,
  Backspace назад при empty, paste 6 цифр заполняет все.
- ForgotPasswordView: email + alert «5 попыток / 15 минут» по ТЗ §1.7.
- RecoveryCodesView: 8 кодов в 2-column grid + Скачать .txt (Blob/URL.createObjectURL)
  + Копировать (navigator.clipboard) + warning о невозможности повторного просмотра.

Router: 4 новых маршрута (/register, /2fa, /forgot, /recovery), все
meta.layout='auth', lazy-imports.

Vitest +14 тестов (всего 24/24 за 3.29s):
- RegisterView 4 (вкл. assertion на отсутствие маркетингового click-wrap)
- TwoFactorView 3, ForgotPasswordView 3, RecoveryCodesView 4

Stories +4 (Histoire 6/6 за 29.17s).

Регресс: lint+type-check+format OK; vitest 24/24; vite build 5 lazy-chunks
для views + Vuetify в отдельные chunks (app chunk 198KB→78KB); Pest 48/48 за 4.85s.

CLAUDE.md v1.19→v1.20, реестр Открытых_вопросов v1.28→v1.29.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 17:09:56 +03:00