package constant const ( SysError string = "system error" UnauthorizedError string = "unauthorized" ForbiddenError string = "permission denied" InvalidError string = "invalid" IllegalTokenError string = "authentication failed" TokenExpiredError string = "token expired" WrongPassword string = "wrong password" ConfigNotExist string = "config not exist" ) // Коды структурированных ошибок. // // Зачем они есть. Раньше единственным машиночитаемым признаком ошибки был // числовой `code` ответа, а всё остальное жило в человеческом тексте: слой vo // выбирал HTTP-семантику СРАВНЕНИЕМ строки сообщения, а панель показывала // оператору голое «invalid» на любую ошибку любого поля формы. Оба места // разбирали прозу — то есть договор между сервером и панелью держался на // совпадении литералов, которое ничто не проверяло. // // Теперь у ошибки есть код и — там, где ошибка относится к полю, — имя поля. // Панель выбирает по коду свою локализованную строку и не разбирает текст; // `message` остаётся человекочитаемым ответом для клиента без UI и запасным // вариантом для кода, которого панель ещё не знает. // // Коды — часть публичного контракта API: их значения не меняются вместе с // формулировками сообщений. const ( // ErrCodeBodyInvalid — тело запроса не разобралось: не JSON, не тот тип // поля, сломанная query-строка. Это отказ ДО проверки правил. ErrCodeBodyInvalid string = "body_invalid" // ErrCodeValidationFailed — общий код ответа, у которого есть errors[]. ErrCodeValidationFailed string = "validation_failed" // Коды правил. Совпадают с именами тегов валидатора: одно правило — один // код, и никакого второго словаря соответствий. ErrCodeRequired string = "required" // Границы числа и границы длины строки различаются кодом, хотя тег // валидатора у них один. Оператору это разные фразы: «не меньше 1 // устройства» и «не короче 6 символов», — и панель обязана уметь их // различить, не заводя у себя таблицу «какое поле какого рода». ErrCodeMin string = "min" ErrCodeMax string = "max" ErrCodeMinLength string = "min_length" ErrCodeMaxLength string = "max_length" ErrCodeLen string = "len" ErrCodeOneOf string = "oneof" ErrCodeGreaterThan string = "gt" ErrCodePeerName string = "peer_name" ErrCodeCredentialStr string = "credential_format" // ErrCodeAdminPassword — пароль администратора не удовлетворяет контракту. // // Отдельный код, а не пара min_length/max_length, потому что правило одно и // проверяет три вещи сразу: длину в символах, длину в байтах (предел // bcrypt) и отсутствие управляющих символов. Пока границы стояли двумя // тегами, отказ по байтам было нечем назвать — его просто не существовало, // и пароль из 64 кириллических букв доходил до хеширования, где становился // системной ошибкой. ErrCodeAdminPassword string = "admin_password_format" ErrCodeRuleUnknown string = "rule_violated" // Доменные коды: правило соблюдено, но операция всё равно невозможна. ErrCodePeerNameTaken string = "peer_name_taken" ErrCodePeerNameReserved string = "peer_name_reserved" ErrCodePeerBootstrapLocked string = "peer_bootstrap_identity_locked" ErrCodeInvalidCredentials string = "invalid_credentials" ErrCodeImportFileExtension string = "import_file_extension" // ErrCodePeerDisconnectFailed — ЧАСТИЧНЫЙ результат, а не отказ операции. // // Отзыв доступа состоит из двух половин: долговременной записи в базе, // которая закрывает новые подключения, и обращения к Traffic Stats `/kick`, // которое рвёт уже установленную сессию. Первая половина к моменту этого // кода уже применена и НЕ откатывается: достигнутое безопасное состояние // нельзя отменять из-за неудачи второго шага — откат вернул бы пиру полный // доступ. // // Поэтому код нужен отдельный. Без него оператор видел бы обычную ошибку и // сделал бы ровно неверный вывод: «не сработало, состояние прежнее». ErrCodePeerDisconnectFailed string = "peer_disconnect_failed" // Коды состояния сессии. Панель различает «войдите» и «сессия кончилась»: // во втором случае оператор находится на рабочей странице, и молча // выбрасывать его на форму входа без объяснения нельзя. ErrCodeUnauthorized string = "unauthorized" ErrCodeSessionExpired string = "session_expired" ErrCodeTokenInvalid string = "token_invalid" ErrCodeAccountDisabled string = "account_disabled" )