fix(utf8): закрыть lossy-границы конфигурации и API

This commit is contained in:
2026-09-07 17:25:27 +05:00
parent ab788725cf
commit af9f476658
38 changed files with 759 additions and 159 deletions
+14 -6
View File
@@ -278,8 +278,8 @@ control plane показывал всех пиров офлайн. Теперь
| Набор символов логина | `a-z A-Z 0-9 !@#$%^&*()_+,-./:;<=` | `AdminUsernameCharset` |
| Длина пароля | 6-64 символа Unicode | `AdminPasswordMinLength` / `AdminPasswordMaxLength` |
| Размер пароля | не более 72 байт в UTF-8 | `AdminPasswordMaxBytes` |
| Домен пароля | значение, загружаемое systemd из `EnvironmentFile=` | `IsEnvTransportableText` |
| Набор символов пароля | не ограничен, кроме `Cc` и `U+FEFF` | `hasForbiddenRune` |
| Домен пароля | документированный домен systemd `EnvironmentFile=`: валидный UTF-8 без NUL, U+FEFF, суррогатов и noncharacters | `IsEnvTransportableText` |
| Набор символов пароля | не ограничен, кроме `Cc` | `hasForbiddenRune` |
| Пробелы по краям пароля | часть значения, не снимаются | — |
Контракт живёт в отдельном **leaf-пакете**, а не в `service`, и это не
@@ -323,7 +323,11 @@ U+FDD0..U+FDEF noncharacters
(cp & 0xFFFE) == 0xFFFE U+FFFE, U+FFFF, U+1FFFE, … U+10FFFF
```
плюс встроенный NUL и любую невалидную последовательность UTF-8.
плюс встроенный NUL, U+FEFF и любую невалидную последовательность UTF-8.
U+FEFF запрещён публичной документацией EnvironmentFile. Реализация systemd
v257.13 случайно пропускает его (`0xFEFF & 0xFFFE == 0xFEFE`); HY2XS следует
документированному контракту, а не закрепляет ошибку конкретной версии.
Пока контракт этого не знал, пароль `abcde` + `U+FDD0` — шесть символов, восемь
байт, ни одного управляющего — проходил панель, оркестратор, DTO и хеширование,
@@ -335,13 +339,17 @@ U+FDD0..U+FDEF noncharacters
суррогат на `U+FFFD`. Без этой проверки не было бы отказа — было бы тихое
изменение пароля по дороге в файл.
**Политика HY2XS — наше решение.** Сверх домена systemd запрещены управляющие
**Политика HY2XS — наше решение.** Сверх транспортного домена запрещены управляющие
символы Unicode целиком (категория `Cc`: `U+0000..U+001F`, `U+007F`,
`U+0080..U+009F`) и `U+FEFF`. Формат их несёт — `0xFEFF & 0xFFFE` это `0xFEFE`,
и systemd такое значение принимает, — но ни один из них невозможно ни увидеть в
`U+0080..U+009F`). Их невозможно ни увидеть в
поле ввода, ни повторить при следующем входе: они умеют ровно одно — запереть
оператора снаружи.
На HTTP-границе проверяется не только уже декодированная Go-строка. Сырые JSON
байты должны быть валидным UTF-8, а `\uXXXX` — не содержать непарных UTF-16
суррогатов. Это делается до `encoding/json`, который иначе молча заменил бы оба
дефекта на допустимый U+FFFD и мог бы аутентифицировать другое значение.
### Почему границ у пароля две
Их две потому, что они в **разных единицах**, и вывести одну из другой нельзя.