From a82b127e2bbf7868c75e3ed18dc6ce70e77080be Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Fri, 16 Oct 2026 10:11:35 +0300 Subject: [PATCH] spec: align user-authentication password requirement with ASCII 8-72 policy (WealthLedger/specs#46) Register accepts 8-72 printable ASCII characters without trimming or normalization; login only requires a non-empty password of at most 72 UTF-8 bytes so accounts created under the previous policy can still sign in. Refs WealthLedger/backend#60. --- openspec/specs/user-authentication/spec.md | 24 ++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/openspec/specs/user-authentication/spec.md b/openspec/specs/user-authentication/spec.md index 577ff4f..23ac6b2 100644 --- a/openspec/specs/user-authentication/spec.md +++ b/openspec/specs/user-authentication/spec.md @@ -7,7 +7,7 @@ ## Requirements ### Requirement: Регистрация пользователя -Система SHALL позволять зарегистрировать User по уникальному нормализованному email и паролю. Email MUST нормализоваться удалением внешних пробелов и приведением к нижнему регистру; он MUST содержать не более 254 символов, ровно один `@`, непустые local и domain части и не содержать пробельных или управляющих символов. Пароль MUST передаваться без изменения, содержать от 12 до 72 UTF-8 байтов и не иметь требований к составу символов. Успешная регистрация MUST создать первую Session и вернуть профиль `{ id, email }` и access token. +Система SHALL позволять зарегистрировать User по уникальному нормализованному email и паролю. Email MUST нормализоваться удалением внешних пробелов и приведением к нижнему регистру; он MUST содержать не более 254 символов, ровно один `@`, непустые local и domain части и не содержать пробельных или управляющих символов. Пароль MUST передаваться без изменения (без trim и нормализации) и состоять из 8–72 печатных ASCII-символов U+0020–U+007E (латинские буквы, цифры, спецсимволы и пробел); другие символы, включая не-ASCII и управляющие, MUST отвергаться. Требований к составу символов (обязательных классов) нет. Успешная регистрация MUST создать первую Session и вернуть профиль `{ id, email }` и access token. #### Scenario: Успешная регистрация - **WHEN** пользователь отправляет новый email и валидный пароль @@ -29,8 +29,20 @@ - **WHEN** пользователь отправляет email или пароль, не соответствующий правилам регистрации - **THEN** система отвечает `400` Problem Details с code `VALIDATION_ERROR` и указателями на невалидные поля +#### Scenario: Границы длины пароля при регистрации +- **WHEN** пользователь регистрируется с паролем из 7, 8, 72 или 73 печатных ASCII-символов +- **THEN** пароли из 8 и 72 символов принимаются, а из 7 и 73 отвергаются `400` Problem Details с code `VALIDATION_ERROR` и указателем `#/password` + +#### Scenario: Недопустимые символы пароля при регистрации +- **WHEN** пользователь регистрирует пароль с кириллицей, emoji, табуляцией, переводом строки или DEL +- **THEN** система отвечает `400` Problem Details с code `VALIDATION_ERROR` и указателем `#/password`, не создавая User + +#### Scenario: Пробелы пароля не изменяются +- **WHEN** пользователь регистрирует пароль с пробелами в начале или конце +- **THEN** система принимает пароль как есть, а вход требует тот же пароль с теми же пробелами + ### Requirement: Вход пользователя -Система SHALL позволять User начать новую независимую Session по нормализованному email и паролю. Успешный вход MUST вернуть `{ id, email }`, access token и установить refresh-cookie. Неверный пароль и неизвестный email MUST иметь одинаковый ответ, не раскрывающий наличие User. +Система SHALL позволять User начать новую независимую Session по нормализованному email и паролю. Успешный вход MUST вернуть `{ id, email }`, access token и установить refresh-cookie. Неверный пароль и неизвестный email MUST иметь одинаковый ответ, не раскрывающий наличие User. Пароль при входе MUST быть непустой строкой не длиннее 72 UTF-8 байтов; минимальная длина и набор символов при входе MUST NOT проверяться, чтобы User, зарегистрированный по прежним правилам (в том числе с не-ASCII паролем), мог войти. #### Scenario: Успешный вход - **WHEN** пользователь отправляет зарегистрированный email и правильный пароль @@ -40,6 +52,14 @@ - **WHEN** пользователь отправляет неизвестный email или неверный пароль - **THEN** система отвечает `401` Problem Details с code `INVALID_CREDENTIALS` +#### Scenario: Вход с прежним паролем +- **WHEN** User, зарегистрированный по прежним правилам с не-ASCII паролем, отправляет правильный пароль +- **THEN** система выполняет вход, не применяя к паролю правила регистрации + +#### Scenario: Пароль при входе длиннее 72 байтов +- **WHEN** пользователь отправляет пароль длиннее 72 UTF-8 байтов +- **THEN** система отвечает `400` Problem Details с code `VALIDATION_ERROR` и указателем `#/password` + ### Requirement: Access и refresh сессии Система SHALL выдавать access token сроком 15 минут и refresh token сроком 7 дней. Access token MUST передаваться клиенту только в ответе API и использоваться как Bearer token. Refresh token MUST передаваться только в `httpOnly`, `SameSite=Lax`, host-only cookie `refresh_token` с path `/api/v1/auth`; в HTTPS-среде cookie MUST иметь атрибут `Secure`. Каждый новый refresh token MUST иметь уникальный JWT ID и ротироваться при успешном обновлении Session; Session MUST оставаться активной 7 дней после последнего успешного обновления. Одновременные Session одного User MUST быть независимы и не иметь числового лимита.