Register принимает только печатный ASCII (буквы, цифры, спецсимволы, пробел), 8–72 символа. Для ASCII символы = bytes, поэтому потолок bcrypt в 72 байта соблюдается без silent truncation и без pre-hash. Login проверяет только строку, непустое значение и максимум 72 байта, чтобы пользователи с прежним паролем (кириллица, 12+ символов) могли войти.
Frontend-часть: WealthLedger/frontend (ветка fix/60-ascii-password-policy, отдельный PR).
Changes
auth.dto.ts: CredentialsDto разделён на RegisterDto (pattern ^[\x20-\x7E]{8,72}$) и LoginDto (максимум 72 UTF-8 bytes). Убран @MinLength по символам.
auth.controller.ts: register и login используют свои DTO.
dto-validation.spec.ts: таблицы границ register (7/8/72/73, кириллица, emoji, tab/LF/DEL, non-string, raw whitespace) и login (legacy-пароли, 72/73 bytes, 36/37 кириллических букв).
test/app.e2e-spec.ts: HTTP-кейс на настроенном приложении: success на границах, 400/VALIDATION_ERROR с pointer #/password, login legacy-пользователя с кириллическим паролем.
Verification
npm run verify → exit 0 (40 suites, 288 tests).
node test/sqlite.cjs app.e2e-spec.ts → 13/13.
npm run test:openapi-contract → 3/3.
npm run openapi:generate + npm run openapi:check → pass.
Мутанты убиты (проверено локально): любой символ вместо ASCII, минимум 12, строгий login, ASCII без пробела, максимум login по символам.
Ограничения: лимит 8 символов не сверялся с NIST SP 800-63B / OWASP ASVS (исследование не запускалось). Без MFA и проверки на утёкшие пароли это ниже современных ориентиров; решение принято owner.
Breaking Changes (если есть)
Публичный OpenAPI: схема CredentialsDto заменена на RegisterDto и LoginDto; wire-формат login не менялся по полям, register стал строже (8–72 печатных ASCII вместо 12+ символов). Потребитель один — frontend. Порядок выкладки: backend можно выкладывать первым (login мягче, register строже).
Вне scope / follow-up
Устаревшие тексты в docs/domains/authentication/overview.md и specs/openspec/specs/user-authentication/spec.md (12–72 UTF-8 bytes) требуют отдельных изменений в репозиториях docs и specs.
Пробел разрешён и login мягкий — допущения, зафиксированные в Issue #60.
## Summary
Register принимает только печатный ASCII (буквы, цифры, спецсимволы, пробел), 8–72 символа. Для ASCII символы = bytes, поэтому потолок bcrypt в 72 байта соблюдается без silent truncation и без pre-hash. Login проверяет только строку, непустое значение и максимум 72 байта, чтобы пользователи с прежним паролем (кириллица, 12+ символов) могли войти.
## Linked Issue
Refs WealthLedger/backend#60
Frontend-часть: WealthLedger/frontend (ветка `fix/60-ascii-password-policy`, отдельный PR).
## Changes
- `auth.dto.ts`: `CredentialsDto` разделён на `RegisterDto` (pattern `^[\x20-\x7E]{8,72}$`) и `LoginDto` (максимум 72 UTF-8 bytes). Убран `@MinLength` по символам.
- `auth.controller.ts`: register и login используют свои DTO.
- `dto-validation.spec.ts`: таблицы границ register (7/8/72/73, кириллица, emoji, tab/LF/DEL, non-string, raw whitespace) и login (legacy-пароли, 72/73 bytes, 36/37 кириллических букв).
- `test/app.e2e-spec.ts`: HTTP-кейс на настроенном приложении: success на границах, 400/VALIDATION_ERROR с pointer `#/password`, login legacy-пользователя с кириллическим паролем.
## Verification
- `npm run verify` → exit 0 (40 suites, 288 tests).
- `node test/sqlite.cjs app.e2e-spec.ts` → 13/13.
- `npm run test:openapi-contract` → 3/3.
- `npm run openapi:generate` + `npm run openapi:check` → pass.
- Мутанты убиты (проверено локально): любой символ вместо ASCII, минимум 12, строгий login, ASCII без пробела, максимум login по символам.
- Ограничения: лимит 8 символов не сверялся с NIST SP 800-63B / OWASP ASVS (исследование не запускалось). Без MFA и проверки на утёкшие пароли это ниже современных ориентиров; решение принято owner.
## Breaking Changes (если есть)
Публичный OpenAPI: схема `CredentialsDto` заменена на `RegisterDto` и `LoginDto`; wire-формат login не менялся по полям, register стал строже (8–72 печатных ASCII вместо 12+ символов). Потребитель один — frontend. Порядок выкладки: backend можно выкладывать первым (login мягче, register строже).
## Вне scope / follow-up
- Устаревшие тексты в `docs/domains/authentication/overview.md` и `specs/openspec/specs/user-authentication/spec.md` (12–72 UTF-8 bytes) требуют отдельных изменений в репозиториях `docs` и `specs`.
- Пробел разрешён и login мягкий — допущения, зафиксированные в Issue #60.
Register accepts only printable ASCII (letters, digits, symbols, space),
8-72 characters, so characters equal bytes and the bcrypt 72-byte limit
holds without silent truncation. Login only caps the password at 72 bytes
so accounts created under the previous policy can still sign in.
CredentialsDto is split into RegisterDto and LoginDto; OpenAPI publishes
the register pattern and length bounds.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Register принимает только печатный ASCII (буквы, цифры, спецсимволы, пробел), 8–72 символа. Для ASCII символы = bytes, поэтому потолок bcrypt в 72 байта соблюдается без silent truncation и без pre-hash. Login проверяет только строку, непустое значение и максимум 72 байта, чтобы пользователи с прежним паролем (кириллица, 12+ символов) могли войти.
Linked Issue
Refs WealthLedger/backend#60
Frontend-часть: WealthLedger/frontend (ветка
fix/60-ascii-password-policy, отдельный PR).Changes
auth.dto.ts:CredentialsDtoразделён наRegisterDto(pattern^[\x20-\x7E]{8,72}$) иLoginDto(максимум 72 UTF-8 bytes). Убран@MinLengthпо символам.auth.controller.ts: register и login используют свои DTO.dto-validation.spec.ts: таблицы границ register (7/8/72/73, кириллица, emoji, tab/LF/DEL, non-string, raw whitespace) и login (legacy-пароли, 72/73 bytes, 36/37 кириллических букв).test/app.e2e-spec.ts: HTTP-кейс на настроенном приложении: success на границах, 400/VALIDATION_ERROR с pointer#/password, login legacy-пользователя с кириллическим паролем.Verification
npm run verify→ exit 0 (40 suites, 288 tests).node test/sqlite.cjs app.e2e-spec.ts→ 13/13.npm run test:openapi-contract→ 3/3.npm run openapi:generate+npm run openapi:check→ pass.Breaking Changes (если есть)
Публичный OpenAPI: схема
CredentialsDtoзаменена наRegisterDtoиLoginDto; wire-формат login не менялся по полям, register стал строже (8–72 печатных ASCII вместо 12+ символов). Потребитель один — frontend. Порядок выкладки: backend можно выкладывать первым (login мягче, register строже).Вне scope / follow-up
docs/domains/authentication/overview.mdиspecs/openspec/specs/user-authentication/spec.md(12–72 UTF-8 bytes) требуют отдельных изменений в репозиторияхdocsиspecs.