From edd339dc82cd8c9b68f451768851364cd84d2a50 Mon Sep 17 00:00:00 2001 From: erjemin Date: Wed, 15 Jul 2026 22:21:00 +0300 Subject: [PATCH] =?UTF-8?q?doc:=20=D0=9A=D0=B0=D0=BA=20=D1=81=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D0=B0=D0=B5=D1=82=D1=81=D1=8F=20=D0=B8=20=D0=BA=D0=B0?= =?UTF-8?q?=D0=BA=20=D1=83=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D1=8F=D1=82=D1=8C?= =?UTF-8?q?=20offer=5Fcode=20=D0=B4=D0=BB=D1=8F=20=D1=81=D0=BA=D1=80=D1=8B?= =?UTF-8?q?=D1=82=D0=B8=D1=8F=20ID=20=D0=B2=20URL=20=D0=B8=20QR-=D0=BA?= =?UTF-8?q?=D0=BE=D0=B4=D0=BE=D0=B2=20(2)=20+=20Django=20Custom=20Command?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=B8=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B3=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../OFFER-CODE-HASHIDS-SALT-GENERATION.md | 195 ++++++++++++++++++ .../OFFER-CODE-HASHIDS-SALT-GENERATION.md | 112 ---------- 2 files changed, 195 insertions(+), 112 deletions(-) create mode 100644 agent-doc/OFFER-CODE-HASHIDS-SALT-GENERATION.md delete mode 100644 agent-reports/OFFER-CODE-HASHIDS-SALT-GENERATION.md diff --git a/agent-doc/OFFER-CODE-HASHIDS-SALT-GENERATION.md b/agent-doc/OFFER-CODE-HASHIDS-SALT-GENERATION.md new file mode 100644 index 0000000..848888e --- /dev/null +++ b/agent-doc/OFFER-CODE-HASHIDS-SALT-GENERATION.md @@ -0,0 +1,195 @@ +# Генерирование криптографической соли для OFFER_HASHIDS_SALT + +## Для Development (локально) + +Текущее значение в `.env`. Если база из dev будет перемещаться в продакшен, то соль не нужно будет заменять на уникальную для продакшена. А то все старые QR-коды перестанут работать. + +Если все-таки нужно обновить соль, используйте Django custom command (см. ниже). + +## Для Production (сервер) + +**НИКОГДА** не используйте соль из примеров! Генерируйте новую для каждого окружения: + +### Способ 1: Python (быстро) +```bash +python3 -c "import secrets; print(secrets.token_hex(16))" +``` + +Результат: +``` +a7f3c82b9e1dEa6b5c8f2e3d0a9b4c7f +``` + +Скопируйте и обновите в `.env` на сервере: +``` +OFFER_HASHIDS_SALT=a7f3c82b9e1dEa6b5c8f2e3d0a9b4c7f +``` + +### Способ 2: Linux/Mac (встроенный) +```bash +openssl rand -hex 16 +``` + +### Способ 3: Более надежная соль (32 байта вместо 16) +```bash +python3 -c "import secrets; print(secrets.token_hex(32))" +``` + +Результат (64 символа, очень стойко): +``` +26aebe8af9efe7c5f81c64cb18846318cc81a83eaf15aedb7f4b8a80990c9676 +``` + +## Важные правила + +1. **Уникальная для каждого окружения** (каждой реализации LPON под каждого сейлера) + - Dev ≠ Staging ≠ Production + - Разные соли = разные коды для одного ID + +2. **Никогда не меняйте в production!** + - Если поменяете соль → старые коды перестанут работать + - Существующие QR-коды станут невалидными + - Существующие ID в базе не будут декодироваться + - **Если все же нужно изменить:** используйте custom command `regenerate_offer_codes` (см. ниже) + +3. **Хранить в .env (не в репозитории)** + - `.env` в .gitignore ✓ + - `.env.example` содержит шаблон ✓ + +## Проверка качества соли + +```python +import secrets + +# Хорошая соль (минимум 32 символа, hex-формат) +salt = secrets.token_hex(16) # ✓ +salt = secrets.token_hex(32) # ✓✓ еще лучше + +# Плохие соли +salt = "my-password" # ✗ слишком короткая +salt = "12345678" # ✗ предсказуемая +salt = "qwerty123" # ✗ слабая энтропия +``` + +## Параметры OFFER_HASHIDS_MIN_LENGTH + +| Кол-во оферов | min_length | Пример | Примечание | +|---------------|------------|--------------|---------------------------------------| +| До 1 000 | 4 | `a1bC` | Слишком короткие, может быть коллизии | +| До 10 000 | 5 | `a1bCd` | Хорошо для небольших каталогов | +| До 100 000 | 6 | `a1bCdE` | **РЕКОМЕНДУЕМО** для начала | +| До 1 000 000 | 8 | `a1bCdEfG` | Для больших каталогов | +| Более 1M | 10 | `a1bCdEfGhI` | Очень большие каталоги | + +**Текущее значение:** `OFFER_HASHIDS_MIN_LENGTH=6` (оптимально) + +## Как увеличить при необходимости? + +Если вырос каталог: + +1. Обновите в `.env`: + ``` + OFFER_HASHIDS_MIN_LENGTH=8 + ``` + +2. Перезагрузите приложение + +3. **Старые коды останутся валидными!** (hashids декодирует любой код независимо от min_length) + +4. Новые офферы будут кодироваться с длиной 8 + +## Django Custom Command: `regenerate_offer_codes` + +**Расположение:** `lpon_site/frontend/management/commands/regenerate_offer_codes.py` + +Используется для проверки, восстановления и перегенерации s_offer_code офферов. + +### Три режима работы + +#### 1. Проверка кодов (режим `--check`) + +Декодирует все коды обратно в ID и проверяет корректность: + +```bash +# Быстрая проверка +cd lpon_site && poetry run python manage.py regenerate_offer_codes --check + +# С подробным выводом +cd lpon_site && poetry run python manage.py regenerate_offer_codes --check --verbose +``` + +#### 2. Исправление некорректных кодов (режим `--fix-broken`) + +Обновляет только коды, которые не декодируются правильно: + +```bash +# Пробный запуск (ничего не сохранит) +cd lpon_site && poetry run python manage.py regenerate_offer_codes --fix-broken --dry-run + +# Реальное исправление +cd lpon_site && poetry run python manage.py regenerate_offer_codes --fix-broken +``` + +**Использование:** Когда некоторые коды повреждены или закодированы неправильно (например, после сбоя БД). + +#### 3. Полное обновление всех кодов (по умолчанию) + +Перегенерирует ВСЕ коды на основе текущего OFFER_HASHIDS_SALT: + +```bash +# Пробный запуск +cd lpon_site && poetry run python manage.py regenerate_offer_codes --dry-run + +# Реальное обновление +cd lpon_site && poetry run python manage.py regenerate_offer_codes +``` + +**ВНИМАНИЕ:** Используется только при смене OFFER_HASHIDS_SALT на production! + +### Примеры использования + +**Сценарий 1: Проверка целостности после сбоя** +```bash +# Сначала проверяем что сломалось +cd lpon_site && poetry run python manage.py regenerate_offer_codes --check + +# Если есть некорректные коды - исправляем +cd lpon_site && poetry run python manage.py regenerate_offer_codes --fix-broken +``` + +**Сценарий 2: Миграция на новый сервер с новой солью** +```bash +# 1. Обновляем .env с новой солью +OFFER_HASHIDS_SALT=новая_соль_из_secrets + +# 2. Перегенерируем все коды (пробный запуск сначала) +cd lpon_site && poetry run python manage.py regenerate_offer_codes --dry-run + +# 3. Если хорошо - реальное обновление +cd lpon_site && poetry run python manage.py regenerate_offer_codes + +# 4. Проверяем что все работает +cd lpon_site && poetry run python manage.py regenerate_offer_codes --check +``` + +### Опции команды + +``` +--check Проверить корректность всех кодов (декодировать обратно в id) +--fix-broken Обновить только коды которые не декодируются правильно +--dry-run Показать что будет изменено, но не сохранять +--verbose Показывать подробный прогресс для каждого оффера +``` + +Использование: + +```bash +# Проверка +python manage.py regenerate_offer_codes --check + +# Исправление +python manage.py regenerate_offer_codes --fix-broken + +# Полное обновление (при смене соли) +python manage.py regenerate_offer_codes +``` diff --git a/agent-reports/OFFER-CODE-HASHIDS-SALT-GENERATION.md b/agent-reports/OFFER-CODE-HASHIDS-SALT-GENERATION.md deleted file mode 100644 index 608b196..0000000 --- a/agent-reports/OFFER-CODE-HASHIDS-SALT-GENERATION.md +++ /dev/null @@ -1,112 +0,0 @@ -# Генерирование криптографической соли для OFFER_HASHIDS_SALT - -## Для Development (локально) - -Текущее значение в `.env`. Если база из dev будет перемещаться в продакшен, то соль не нужно будет заменять -на уникальную для продакшена. А то все старые QR-коды перестанут работать. - -Возможно TODO сделать Django Custom Command для генерации соли и обновления `.env` автоматически. - -``` - -## Для Production (сервер) - -**НИКОГДА** не используйте соль из примеров! Генерируйте новую для каждого окружения: - -### Способ 1: Python (быстро) -```bash -python3 -c "import secrets; print(secrets.token_hex(16))" -``` - -Результат: -``` -a7f3c82b9e1d4a6b5c8f2e3d0a9b4c7f -``` - -Скопируйте и обновите в `.env` на сервере: -``` -OFFER_HASHIDS_SALT=a7f3c82b9e1d4a6b5c8f2e3d0a9b4c7f -``` - -### Способ 2: Linux/Mac (встроенный) -```bash -openssl rand -hex 16 -``` - -### Способ 3: Более надежная соль (32 байта вместо 16) -```bash -python3 -c "import secrets; print(secrets.token_hex(32))" -``` - -Результат (64 символа, очень стойко): -``` -a7f3c82b9e1d4a6b5c8f2e3d0a9b4c7fa7f3c82b9e1d4a6b5c8f2e3d0a9b4c -``` - -## Важные правила - -1. **Уникальная для каждого окружения** (каждой реализации LPON под каждого сейлера) - - Dev ≠ Staging ≠ Production - - Разные соли = разные коды для одного ID - -2. **Никогда не меняйте в production!** - - Если поменяете соль → старые коды перестанут работать (если будет создана Django Custom Command для перегенерации - s_offer_code под новую "соль", то сделать перегенерацию обязательно) - - Существующие QR-коды станут невалидными - - Существующие ID в базе не будут декодироваться - -3. **Хранить в .env (не в репозитории)** - - `.env` в .gitignore ✓ - - `.env.example` содержит шаблон ✓ - -## Проверка качества соли - -```python -import secrets - -# Хорошая соль (минимум 32 символа, hex-формат) -salt = secrets.token_hex(16) # ✓ -salt = secrets.token_hex(32) # ✓✓ еще лучше - -# Плохие соли -salt = "my-password" # ✗ слишком короткая -salt = "12345678" # ✗ предсказуемая -salt = "qwerty123" # ✗ слабая энтропия -``` - -## Параметры OFFER_HASHIDS_MIN_LENGTH - -| Кол-во оферов | min_length | Пример | Примечание | -|---------------|------------|--------------|---------------------------------------| -| До 1 000 | 4 | `a1bC` | Слишком короткие, может быть коллизии | -| До 10 000 | 5 | `a1bCd` | Хорошо для небольших каталогов | -| До 100 000 | 6 | `a1bCdE` | **РЕКОМЕНДУЕМО** для начала | -| До 1 000 000 | 8 | `a1bCdEfG` | Для больших каталогов | -| Более 1M | 10 | `a1bCdEfGhI` | Очень большие каталоги | - -**Текущее значение:** `OFFER_HASHIDS_MIN_LENGTH=6` (оптимально) - -## Как увеличить при необходимости? - -Если вырос каталог: - -1. Обновите в `.env`: - ``` - OFFER_HASHIDS_MIN_LENGTH=8 - ``` - -2. Перезагрузите приложение - -3. **Старые коды останутся валидными!** (hashids декодирует любой код независимо от min_length) - -4. Новые офферы будут кодироваться с длиной 8 - -## Итого - -✓ Текущая соль: `4ce44e07053ac50e1096d6725a4782ac` (dev) -✓ Текущая длина: `6` (оптимальна) -✓ Для production: **Генерируйте новую соль** - -```bash -python3 -c "import secrets; print(secrets.token_hex(16))" -```