Добавить статистику и очистку аудита; доработать UI расшифровки.

- Страница /admin/stats: MinIO, pending/consumed, загрузки, audit-метрики
- Кнопка «Очистить» в аудите с подтверждением
- Красивые callout’ы и ошибки пароля; пустой пароль не тратит попытку
- Убрать автоопределение языка; «Расшифруй» в RU UI
This commit is contained in:
Sergey Antropoff
2026-07-18 23:50:44 +03:00
parent 91719740b9
commit 8361b8e3f2
17 changed files with 1007 additions and 258 deletions
+94 -20
View File
@@ -22,11 +22,8 @@
"create.title": "Wrap. Send. Vanish.",
"create.lede": "Wrap text, images or files into a one-time token. Encryption happens in your browser — the server never sees plaintext.",
"create.language": "Highlight language",
"create.languageChange": "Change type",
"create.languagePickTitle": "Text type",
"create.languagePickHint": "Choose how the text should be highlighted.",
"create.languageUnsure": "Not sure — maybe: {suggestions}. Or change type.",
"create.languageUnsurePlain": "Could not detect type — change type if needed.",
"create.text": "Text",
"create.textPlaceholder": "Paste secrets, configs, notes…",
"create.drop": "Drop files here, click to browse, or paste a screenshot (⌘V / Ctrl+V)",
@@ -39,7 +36,8 @@
"create.working": "Encrypting and uploading…",
"create.openToken": "Open a token",
"create.successTitle": "Token issued",
"create.successWarn": "One-time unwrap. After someone opens it, ciphertext is destroyed on the server.",
"create.successWarnTitle": "One-time unwrap",
"create.successWarnHint": "After opening, ciphertext is deleted on the server.",
"create.shareLink": "Share link",
"create.token": "Wrapped token",
"create.another": "Create another",
@@ -79,17 +77,23 @@
"unwrap.password": "Password (if set)",
"unwrap.submit": "Unwrap",
"unwrap.working": "Decrypting…",
"unwrap.destroyed": "Server copy destroyed. Preview lives only in this browser session.",
"unwrap.destroyedTitle": "Server copy destroyed",
"unwrap.destroyedHint": "Preview lives only in this browser session.",
"unwrap.needKey": "Missing encryption key. Open the full share link (with #key) or paste the full wrapped token.",
"unwrap.badPassword": "Wrong password.",
"unwrap.badPasswordRemaining": "Wrong password. Attempts left: {n} of {max}.",
"unwrap.passwordLocked": "Too many wrong passwords. This wrap has been destroyed.",
"unwrap.badPassword": "Wrong password",
"unwrap.badPasswordHint": "Check the password and try again.",
"unwrap.passwordRequired": "Password required",
"unwrap.passwordRequiredHint": "This wrap is password-protected.",
"unwrap.attemptsLeft": "{n} of {max} attempts left",
"unwrap.passwordLocked": "Too many wrong passwords",
"unwrap.passwordLockedHint": "This wrap has been destroyed.",
"unwrap.unavailable": "Unavailable (already used, expired, or invalid).",
"common.copy": "Copy",
"common.copied": "Copied",
"common.download": "Download",
"common.error": "Something went wrong.",
"common.working": "Working…",
"admin.nav.stats": "Stats",
"admin.nav.settings": "Settings",
"admin.nav.audit": "Audit",
"admin.nav.danger": "Danger",
@@ -97,6 +101,33 @@
"admin.nav.logout": "Logout",
"admin.brand.tagline": "Admin console",
"admin.settings.title": "Settings",
"admin.stats.title": "Statistics",
"admin.stats.updated": "Updated",
"admin.stats.minioTitle": "MinIO (pending ciphertext)",
"admin.stats.objects": "object(s)",
"admin.stats.dbPending": "DB pending",
"admin.stats.unwrappedTitle": "Unwrapped (all time)",
"admin.stats.auditOk": "audit ok",
"admin.stats.last24h": "24h",
"admin.stats.pendingTitle": "Not unwrapped",
"admin.stats.items": "item(s)",
"admin.stats.uploadedTitle": "Uploaded (all time)",
"admin.stats.wrapsSection": "Wraps by status",
"admin.stats.extraSection": "More",
"admin.stats.col.status": "Status",
"admin.stats.col.count": "Count",
"admin.stats.col.size": "Size",
"admin.stats.col.items": "Items",
"admin.stats.status.pending": "pending",
"admin.stats.status.consumed": "consumed",
"admin.stats.status.expired": "expired",
"admin.stats.total": "Total",
"admin.stats.withPassword": "With password",
"admin.stats.created24h": "Created (24h)",
"admin.stats.created7d": "Created (7d)",
"admin.stats.createsOk": "Creates ok (audit)",
"admin.stats.createsFail": "Creates fail (audit)",
"admin.stats.unwrapsFail": "Unwrap fails (audit)",
"admin.audit.title": "Audit",
"admin.tab.limits": "Limits",
"admin.tab.rate": "Rate limits",
@@ -166,6 +197,12 @@
"admin.audit.filter": "Filter",
"admin.audit.allEvents": "All events",
"admin.audit.perPage": "Per page",
"admin.audit.clear": "Clear",
"admin.audit.clearConfirmTitle": "Clear audit",
"admin.audit.clearConfirm": "Delete all audit events? This cannot be undone.",
"admin.audit.clearConfirmOk": "Clear all",
"admin.audit.clearedPrefix": "Cleared",
"admin.audit.clearedSuffix": "audit event(s).",
"admin.audit.shown": "events shown",
"admin.audit.of": "of",
"admin.audit.events": "events",
@@ -202,11 +239,8 @@
"create.title": "Упакуй. Отправь. Исчезни.",
"create.lede": "Упакуй текст, картинки или файлы в одноразовый токен. Шифрование в браузере — сервер не видит plaintext.",
"create.language": "Язык подсветки",
"create.languageChange": "Изменить тип",
"create.languagePickTitle": "Тип текста",
"create.languagePickHint": "Выберите, как подсвечивать текст.",
"create.languageUnsure": "Не уверен — возможно: {suggestions}. Или измените тип.",
"create.languageUnsurePlain": "Не удалось определить тип — при необходимости измените вручную.",
"create.text": "Текст",
"create.textPlaceholder": "Вставь секреты, конфиги, заметки…",
"create.drop": "Перетащи файлы, выбери или вставь скриншот из буфера (⌘V / Ctrl+V)",
@@ -219,7 +253,8 @@
"create.working": "Шифрование и загрузка…",
"create.openToken": "Открыть токен",
"create.successTitle": "Токен выдан",
"create.successWarn": "Unwrap один раз. После открытия ciphertext удаляется на сервере.",
"create.successWarnTitle": "Расшифруй один раз",
"create.successWarnHint": "После открытия ciphertext удаляется на сервере.",
"create.shareLink": "Ссылка",
"create.token": "Wrapped-токен",
"create.another": "Создать ещё",
@@ -251,7 +286,7 @@
"relative.inHours": "через {n} ч",
"relative.inDays": "через {n} дн",
"relative.soon": "скоро",
"unwrap.eyebrow": "Unwrap",
"unwrap.eyebrow": "Расшифруй",
"unwrap.title": "Открыть один раз",
"unwrap.lede": "Вставь wrapped-токен или открой ссылку. Ciphertext скачивается один раз и удаляется на сервере.",
"unwrap.token": "Wrapped-токен или ID",
@@ -259,17 +294,23 @@
"unwrap.password": "Пароль (если задан)",
"unwrap.submit": "Расшифровать",
"unwrap.working": "Расшифровка…",
"unwrap.destroyed": "Копия на сервере уничтожена. Превью только в этой сессии браузера.",
"unwrap.destroyedTitle": "Копия на сервере уничтожена",
"unwrap.destroyedHint": "Превью только в этой сессии браузера.",
"unwrap.needKey": "Нет ключа шифрования. Открой полную ссылку (с #key) или вставь полный wrapped-токен.",
"unwrap.badPassword": "Неверный пароль.",
"unwrap.badPasswordRemaining": "Неверный пароль. Осталось попыток: {n} из {max}.",
"unwrap.passwordLocked": "Слишком много неверных паролей. Этот wrap уничтожен.",
"unwrap.badPassword": "Неверный пароль",
"unwrap.badPasswordHint": "Проверьте пароль и попробуйте снова.",
"unwrap.passwordRequired": "Нужен пароль",
"unwrap.passwordRequiredHint": "Этот wrap защищён паролем.",
"unwrap.attemptsLeft": "Осталось попыток: {n} из {max}",
"unwrap.passwordLocked": "Слишком много неверных паролей",
"unwrap.passwordLockedHint": "Этот wrap уничтожен.",
"unwrap.unavailable": "Недоступно (уже использовано, истекло или неверно).",
"common.copy": "Копировать",
"common.copied": "Скопировано",
"common.download": "Скачать",
"common.error": "Что-то пошло не так.",
"common.working": "Подождите…",
"admin.nav.stats": "Статистика",
"admin.nav.settings": "Настройки",
"admin.nav.audit": "Аудит",
"admin.nav.danger": "Опасная зона",
@@ -277,6 +318,33 @@
"admin.nav.logout": "Выйти",
"admin.brand.tagline": "Консоль администратора",
"admin.settings.title": "Настройки",
"admin.stats.title": "Статистика",
"admin.stats.updated": "Обновлено",
"admin.stats.minioTitle": "MinIO (нерасшифрованный ciphertext)",
"admin.stats.objects": "объект(ов)",
"admin.stats.dbPending": "в БД pending",
"admin.stats.unwrappedTitle": "Расшифровано (за всё время)",
"admin.stats.auditOk": "audit ok",
"admin.stats.last24h": "за 24ч",
"admin.stats.pendingTitle": "Не расшифровано",
"admin.stats.items": "элемент(ов)",
"admin.stats.uploadedTitle": "Загружено (за всё время)",
"admin.stats.wrapsSection": "Wraps по статусу",
"admin.stats.extraSection": "Ещё",
"admin.stats.col.status": "Статус",
"admin.stats.col.count": "Кол-во",
"admin.stats.col.size": "Размер",
"admin.stats.col.items": "Элементы",
"admin.stats.status.pending": "pending",
"admin.stats.status.consumed": "consumed",
"admin.stats.status.expired": "expired",
"admin.stats.total": "Всего",
"admin.stats.withPassword": "С паролем",
"admin.stats.created24h": "Создано (24ч)",
"admin.stats.created7d": "Создано (7д)",
"admin.stats.createsOk": "Создания ok (audit)",
"admin.stats.createsFail": "Создания fail (audit)",
"admin.stats.unwrapsFail": "Ошибки расшифровки (audit)",
"admin.audit.title": "Аудит",
"admin.tab.limits": "Лимиты",
"admin.tab.rate": "Rate limits",
@@ -302,15 +370,15 @@
"admin.limits.auditRetention": "Хранение аудита (дни)",
"admin.rate.title": "Rate limits (на IP / минуту)",
"admin.rate.create": "Создание",
"admin.rate.unwrap": "Unwrap",
"admin.rate.unwrap": "Расшифровка",
"admin.rate.adminLogin": "Вход в админку",
"admin.mime.title": "MIME allowlist",
"admin.mime.hint": "Один шаблон на строку. Точные типы и wildcards вроде image/*.",
"admin.mime.examples": "Примеры / рекомендуемые значения",
"admin.passwordMode.title": "Режим пароля",
"admin.passwordMode.client_only": "Пароль также оборачивает ciphertext в браузере. Сервер хранит Argon2id-хеш и отклоняет неверный пароль до одноразового unwrap (опечатка не сжигает пакет).",
"admin.passwordMode.client_only": "Пароль также оборачивает ciphertext в браузере. Сервер хранит Argon2id-хеш и отклоняет неверный пароль до одноразовой расшифровки (опечатка не сжигает пакет).",
"admin.passwordMode.server_gate": "Сервер хранит Argon2id-хеш и отдаёт ciphertext только после верного пароля. Ciphertext по-прежнему шифруется на клиенте тем же паролем.",
"admin.password.maxAttempts": "Неверных вводов пароля (unwrap)",
"admin.password.maxAttempts": "Неверных вводов пароля (расшифровка)",
"admin.password.maxAttemptsHint": "После стольких неверных паролей wrap уничтожается. По умолчанию: 3.",
"admin.captcha.title": "CAPTCHA",
"admin.captcha.provider": "Провайдер",
@@ -346,6 +414,12 @@
"admin.audit.filter": "Фильтр",
"admin.audit.allEvents": "Все события",
"admin.audit.perPage": "На странице",
"admin.audit.clear": "Очистить",
"admin.audit.clearConfirmTitle": "Очистить аудит",
"admin.audit.clearConfirm": "Удалить все события аудита? Это нельзя отменить.",
"admin.audit.clearConfirmOk": "Очистить всё",
"admin.audit.clearedPrefix": "Удалено",
"admin.audit.clearedSuffix": "событий аудита.",
"admin.audit.shown": "событий показано",
"admin.audit.of": "из",
"admin.audit.events": "событий",