No description
  • JavaScript 47.9%
  • Python 36.8%
  • CSS 14.6%
  • HTML 0.4%
  • Dockerfile 0.3%
Find a file
2026-04-25 17:13:59 +03:00
backend feat: improve invitations, preview controls, mobile UI and error messages 2026-04-25 17:13:19 +03:00
frontend feat: improve invitations, preview controls, mobile UI and error messages 2026-04-25 17:13:19 +03:00
.gitignore store crypt files 2026-04-25 02:20:32 +03:00
docker-compose.yml store crypt files 2026-04-25 02:20:32 +03:00
example.env store crypt files 2026-04-25 02:20:32 +03:00
README.md store crypt files 2026-04-25 02:20:32 +03:00

Disk

Docker-приложение для облачного хранилища с интерфейсом в стиле Яндекс.Диска.

Что внутри:

  • FastAPI + SQLite backend.
  • React + Vite frontend.
  • Личная директория каждого пользователя в data/<user_id>/.
  • Содержимое файлов в data/<user_id>/ шифруется, recovery-доступ вынесен в отдельную утилиту.
  • Доступ к файлам и папкам для других пользователей.
  • Публичные ссылки для неавторизованных людей.
  • Права viewer, editor, manager.
  • Корзина с хранением удалённых файлов и папок 30 дней.
  • Скачивание папок одним архивом zip.

Запуск

docker compose up --build

После старта:

  • frontend: http://localhost:3000
  • backend: http://localhost:8000

Для домена и HTTPS frontend ходит в backend через относительный путь /api, который проксируется nginx внутри web контейнера. Это убирает проблемы с CORS и запросами на localhost.

Для backend теперь обязательно задать:

  • JWT_SECRET_KEY
  • SERVER_FILE_KEY_ENCRYPTION_KEY: base64-строка, которая декодируется ровно в 32 байта
  • ADMIN_RECOVERY_PUBLIC_KEY
  • ADMIN_RECOVERY_PRIVATE_KEY

ADMIN_RECOVERY_* можно передавать либо PEM-текстом прямо в env, либо путём к PEM-файлу внутри контейнера.

Минимальная генерация ключей для .env:

# 32-байтный base64-ключ для шифрования пользовательских file keys
python3 -c "import os,base64; print(base64.b64encode(os.urandom(32)).decode())"

# recovery RSA key pair
mkdir -p secrets
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out secrets/disk_recovery_private.pem
openssl rsa -pubout -in secrets/disk_recovery_private.pem -out secrets/disk_recovery_public.pem

Пример значений в .env:

JWT_SECRET_KEY=change-me
SERVER_FILE_KEY_ENCRYPTION_KEY=<base64-ключ-из-команды-выше>
ADMIN_RECOVERY_PUBLIC_KEY=/app/secrets/disk_recovery_public.pem
ADMIN_RECOVERY_PRIVATE_KEY=/app/secrets/disk_recovery_private.pem
ADMIN_RECOVERY_PRIVATE_KEY_PASSWORD=

Если приватный recovery-ключ создаёте с паролем, укажите его в ADMIN_RECOVERY_PRIVATE_KEY_PASSWORD. Если без пароля, оставьте переменную пустой.

Публичные ссылки и ссылки-приглашения по умолчанию строятся от адреса, на котором открыт frontend. Чтобы всегда выдавать ссылки с вашим доменом, задайте PUBLIC_BASE_URL перед сборкой Docker:

PUBLIC_BASE_URL=https://disk.example.com docker compose up --build

Для локальной frontend-разработки можно задать:

VITE_PUBLIC_BASE_URL=https://disk.example.com

Локальная разработка

Frontend:

cd frontend
npm install
npm run dev

Backend:

cd backend
pip install -r requirements.txt
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

По умолчанию Vite ходит в backend через VITE_API_URL. В docker-сборке используется /api, локально можно работать и с прямым backend на http://localhost:8000.

Сценарий

  1. Зарегистрируйте двух пользователей.
  2. Под первым пользователем создайте папку или загрузите файл.
  3. Нажмите Доступ и выдайте:
    • доступ другому пользователю по его username;
    • или публичную ссылку для неавторизованного просмотра/редактирования.
  4. У второго пользователя общий ресурс появится в блоке Доступно мне.

Корзина

  • Удаление из раздела Файлы перемещает объект в Корзину.
  • Объект хранится 30 дней с момента удаления.
  • Из корзины можно восстановить объект или удалить навсегда.

Права

  • viewer: просмотр списка и скачивание файлов.
  • editor: просмотр, загрузка файлов, создание папок, удаление и переименование.
  • manager: всё выше плюс возможность управлять доступом владельца ресурса.

Хранение

Файлы лежат в локальном томе:

data/
  <user_id>/

SQLite база хранится рядом в data/storage.db.

Сами файлы больше не лежат в открытом виде: на диске хранится шифротекст. Структура каталогов и имена файлов пока сохраняются в открытом виде, чтобы не ломать текущий API и механику шаринга.

Шифрование и Recovery

  • У каждого пользователя есть собственный ключ шифрования файлов.
  • Этот ключ хранится в трёх обёртках: по паролю пользователя, сервисным ключом backend и recovery-ключом администратора.
  • Обычная работа приложения идёт через сервисную обёртку.
  • Смена пароля переупаковывает пользовательскую обёртку, не трогая сами файлы.
  • Админский recovery-доступ вынесен в отдельную явную утилиту, а не в прямое чтение из data/.

Миграция существующих файлов

  1. Сначала задайте новые переменные окружения и убедитесь, что backend может стартовать с ними.
  2. Сделайте backup каталога data/.
  3. Выполните миграцию:
cd backend
python scripts/migrate_to_encrypted_storage.py

Что делает миграция:

  • создаёт сервисную и recovery-обёртки ключей для старых пользователей;
  • шифрует все незашифрованные файлы в data/<user_id>/ и .trash;
  • уже зашифрованные файлы пропускает;
  • если у старого пользователя ещё нет парольной обёртки ключа, она будет автоматически создана при его следующем успешном логине.

Recovery-доступ администратора

Чтобы явно расшифровать конкретный файл по recovery-ключу:

cd backend
python scripts/recover_file.py --user-id 12 --path "docs/report.pdf" --output /tmp/report.pdf

Структура проекта

docker-compose.yml
example.env
backend/
  Dockerfile
  requirements.txt
  app/
    __init__.py
    auth.py
    crypto.py
    database.py
    main.py
    models.py
    schemas.py
    storage.py
  scripts/
    migrate_to_encrypted_storage.py
    recover_file.py
frontend/
  Dockerfile
  index.html
  nginx.conf
  package.json
  vite.config.js
  public/
    favicon.png
  src/
    components/
    constants/
    hooks/
    pages/
    utils/
    App.jsx
    api.js
    config.js
    main.jsx
    styles.css
secrets/
  disk_recovery_private.pem
  disk_recovery_public.pem

Frontend Architecture

Frontend больше не собран в одном файле. Основные части разделены так:

  • pages/: экраны приложения: DiskPage, PublicSharePage, AdminPage, AuthScreen, InviteRegistrationPage.
  • components/: переиспользуемые UI-блоки, модалки, карточки, header/sidebar-части.
  • hooks/: клиентское состояние и сценарии, например useSession, useExplorer, useShareModal, useUploadQueue.
  • utils/: низкоуровневые утилиты и action-layer, включая explorerActions.js, превью, скачивание и форматирование.

Ключевая идея:

  • App.jsx отвечает только за маршрутизацию.
  • страницы собираются из переиспользуемых компонентов и хуков.
  • операции над файлами и шарингом вынесены из страниц в общий action-layer.

Backend Notes

  • main.py содержит HTTP API и маршруты FastAPI.
  • storage.py отвечает за работу с файловой системой, корзиной и правами доступа.
  • auth.py реализует аутентификацию и JWT.
  • database.py поднимает SQLite и выполняет простую инициализацию схемы.