Как устроено и что хранится
Не обещания «мы всё зашифровали» — а прямые ссылки на то, что реально делает код: где живёт вход в Google, что лежит в базе и сколько, чем зашифрованы мастер-токены, что не хранится никогда, как отключить доступ и какие действуют лимиты частоты.
Где живёт вход в Google
Пароль и второй фактор Google на сервер не попадают. Это не обещание, а свойство схемы: сервер физически не видит пароль, потому что весь вход происходит в браузере на твоей машине.
Скрипт /onboard_local.js открывает настоящий браузер на твоей машине и захватывает одноразовый oauth_token и email после того, как ты сам вошёл в Google — сервер этот момент не видит. Дальше ты передаёшь пару {email, oauth_token} инструменту add_account_token (или в POST /v1/onboard/token): сервер обменивает одноразовый токен на мастер-токен через библиотеку gpsoauth, проверяет его одним читающим вызовом и сохраняет уже зашифрованным.
oauth_token одноразовый и живёт минуты. Если обмен не произошёл сразу, токен протухает и процедуру нужно повторить — это не баг, а короткое окно жизни самого токена от Google.
Что хранится и сколько
Ниже — реальные таблицы из service/db.py и файл мастер-токенов, а не пересказ. Один пункт списка — одно поле таблицы.
задачи · jobs
- params — промпт и параметры вызова
- status, error, attempts — что произошло с задачей
- account_used, owner — каким аккаунтом и от чьего имени
- created_at / started_at / updated_at — время постановки, старта, обновления
витрина · showcase
- prompt, model — то, что видно публично на главной
- file, w, h — локальный файл кадра и его размер
- строки нет = публикация включена по умолчанию; отключение — платный тариф, удаляет уже опубликованное, а не прячет
ключи доступа · users
- key_hash — только SHA-256 хэш ключа, сам ключ не хранится нигде
- key_prefix, name — по какому обрезку узнать ключ и как ты его назвал
- active, status — включён ли ключ прямо сейчас
Google-аккаунты · accounts
- email, project, reset_day — какой аккаунт подключён и когда сбрасывается квота
- сам мастер-токен в этой таблице не лежит — он в отдельном зашифрованном файле, смотри следующий блок
вход через GitHub · identities
- provider_user_id — числовой id GitHub, ключ записи
- login — логин хранится только для показа, привязка не на нём: смена логина не рвёт доступ и не отдаёт его чужому
персонажи · characters
- name, description — как карточка называется и что в ней
- portrait_media_id — какой кадр несёт сходство лица
- entity_id, project, account — карточка в самом Flow
подписка и оплата · subscriptions, payment_orders
- status, until — активна ли подписка и до какого момента
- amount, currency, provider, status — заказ на оплату, без данных карты: их принимает платёжный провайдер, не openFlow
согласие и выход · owner_settings, session_epochs
- terms_accepted_at — когда принял правила
- epoch — счётчик выходов: «выйти» обнуляет разом все ранее выданные сессии этого владельца
Чем зашифрованы мастер-токены
Мастер-токен Google-аккаунта — это полный доступ к нему. Он не в базе данных: он в отдельном файле, зашифрованном AES-256-GCM.
алгоритм
- AES-256-GCM: шифрование и проверка подлинности в одном шаге
- формат значения —
base64(nonce[12] || ciphertext+tag) - подменённый файл не расшифруется тихо в мусор — GCM это заметит
ключ
- лежит отдельно от файла с токенами — утечка одного файла не значит утечку ключа
- права
600, владелецroot - без ключа зашифрованный файл — просто байты
Честно про границу защиты: от человека, получившего root на самом сервере, это не спасает — там ключ читается вместе с данными. Схема защищает от утечки ФАЙЛА (бэкап, rsync, случайный коммит) — это самый вероятный сценарий из двух, но не единственный.
Что не хранится и как отключить доступ
- Пароль и второй фактор Google — сервер их физически не видит, вход целиком проходит в твоём браузере.
- Сам MCP-ключ — в базе только его SHA-256 хэш; ключ показывается один раз в момент выпуска.
- Генерации с твоими загруженными фото (персонаж из фото,
image_inputs, control-изображения) — не попадают в публичную витрину ни при каких настройках и тарифах.
Отозвать один ключ
В кабинете — кнопка у конкретного ключа (/me/keys/{prefix}). Ключ на другой машине продолжает работать: отзыв всегда точечный.
Выключить публикацию
На платном тарифе в кабинете. Уже опубликованные работы удаляются из витрины, а не прячутся.
Отключить Google-аккаунт целиком
Кнопки пока нет — пиши оператору через GitHub. Честнее сказать об этом прямо, чем изображать самообслуживание, которого ещё нет.
Метки на сгенерированном
Две разные вещи, и обе стоит знать до генерации, а не после скачивания.
Невидимая метка SynthID — есть всегда
Google встраивает её в каждый кадр и каждый ролик Veo и Imagen. Отключить её нельзя ни настройкой, ни через нас: это метка Google, а не наша. Она не видна глазом, но по ней содержимое определяется как сгенерированное ИИ.
Видимая «искорка» в углу — зависит от аккаунта
С 28 июля 2026 у Flow есть настройка «Visible watermarking» в аккаунте Google, под которым идёт генерация. По умолчанию она выключена не везде: умолчание задаёт регион аккаунта, а в части стран знак нельзя отключить вовсе.
Что делаем мы
Проверяем каждый готовый файл и возвращаем ответ в результате задачи полем visible_watermark. Если посмотреть не смогли — так и пишем, а не выдаём это за «чисто».
На 29 июля 2026 свежие генерации выходят без видимого знака. Ролики, сделанные до 28 июля, «искорку» содержат — они уже сгенерированы, и снять её нельзя.
Лимиты частоты
Очередь одна на всех, но выдача справедливая: следующую задачу получает тот, у кого меньше всего работает сейчас. Поэтому чужая пачка на тысячу генераций не отодвигает твою одну. Пределы ниже — минимумы, и они растут вместе с числом подключённых Google-аккаунтов: за это отвечает service/api.py::_admit, через которую проходит любая постановка задачи.
Логика простая: один аккаунт делает одну генерацию одновременно, поэтому смысл имеет ровно та ёмкость, которую ты подключил. Десять аккаунтов — это десять параллельных генераций и 1200 в час, а не «три, потому что так решили».
Отказ — HTTP 429 с заголовком Retry-After и текстом, который называет предел, текущее число и через сколько секунд отпустит: чужой лимит не тратится, а свой не пропадает молча.