# Shuffle Cracked — отключение лицензионных ограничений Этот форк Shuffle содержит патч, который **полностью убирает проверку лицензии** для self-hosted развёртывания. Ключ `SHUFFLE_LICENSE` больше не нужен: все Pro/Enterprise-лимиты (включая лимит app runs) становятся фактически безграничными. Патч протестирован — образ бэкенда успешно собирается в Docker. --- ## Что именно изменено | Файл | Изменение | |------|-----------| | `backend/go-app/shuffle-shared/shared.go` | Три блока `LICENSE BYPASS PATCH` в `HandleCheckLicense` и `IsLicensed`: (1) `HandleCheckLicense` принудительно `org.Licensed = true` + всем `SyncFeatures[*].Active = true, Limit = 1e9` с ранним возвратом; (2) `IsLicensed` возвращает `true`. | | `backend/go-app/shuffle-shared/db-connector.go` | Блок `LICENSE BYPASS PATCH` в `checkNoInternet()`: всегда возвращает `Valid=true` и лимиты `1e9`. Это закрывает прямые чтения в `SetWorkflowQueue` (app runs) и проверке суб-организаций. | | `backend/go-app/go.mod` | Включён `replace github.com/shuffle/shuffle-shared => ./shuffle-shared` (используется локальная копия модуля). | | `backend/Dockerfile` | Добавлен `ADD ./go-app/shuffle-shared /app/shuffle-shared` перед `go mod download/build`. | | `backend/go-app/shuffle-shared/` | Полная копия модуля `shuffle-shared v1.2.51` с патчами. | > Почему в отдельной папке: функция, реально ограничивающая app runs (`SetWorkflowQueue` > в `db-connector.go`), и лимиты суб-организаций живут во внешнем модуле > `github.com/shuffle/shuffle-shared`. Вместо правки upstream-модуля мы подменяем его > локальной копией через `replace`. Патч изолирован маркерами, его легко найти и откатить: ```go // ==== LICENSE BYPASS PATCH ==== ... // ==== END LICENSE BYPASS PATCH ==== ``` ### Покрытие (аудит всех точек принуждения) Пропатчены **все** источники правды о лицензии, которые реально ограничивают работу: | Точка принуждения | Файл | Покрытие | |-------------------|------|----------| | Лимит app runs | `db-connector.go` `SetWorkflowQueue` (~8819) | Через `HandleCheckLicense` + `checkNoInternet` (патчи) | | Лимит app runs (облако) | `cloudSync.go` (~947) | Через `SyncFeatures.AppExecutions.Limit` = 1e9 (патч HandleCheckLicense) | | Лимит окружений (multi-env) | `db-connector.go` (~7388) | Через `SyncFeatures.MultiEnv` = активный (патч HandleCheckLicense) | | Лимит суб-организаций | `shared.go` (~13084, 13093) | Через `checkNoInternet` + `HandleCheckLicense` (оба патча) | | UI-флаг "licensed" | `main.go:1087` / `IsLicensed` | Патч `IsLicensed` = true | Прочие чтения `SyncFeatures`/лимитов (дефолты, описания, `BuildBaseSubscription`) не блокируют работу — это только отображение в UI. Проверяющие агенты (worker/orborus) лицензию не проверяют. --- ## Как собрать и запустить Важно: **docker build context — `backend/`** (как в CI Shuffle), НЕ корень репозитория. ### 1. Взять готовый образ (рекомендуется) Патченый образ публикуется в registry как `marker689/shuffle-backend-unchained:12082026`. Просто укажите его в `docker-compose.yml` (см. шаг 2) — docker сам его скачает. Либо собрать локально: ```bash cd backend docker build -t marker689/shuffle-backend-unchained:12082026 -f Dockerfile . ``` ### 2. Подключить образ к docker-compose В `docker-compose.yml` у сервиса `backend` заменить образ на готовый патченый: ```yaml image: marker689/shuffle-backend-unchained:12082026 ``` > Это уже собранный и пропатченный образ (публичный в registry `marker689`). > Альтернатива — собрать локально: `cd backend && docker build -t ... -f Dockerfile .`. ### 3. Запустить ```bash docker-compose up -d ``` Ключ `SHUFFLE_LICENSE` в `.env` можно **не указывать** — патч его игнорирует. --- ## Как убедиться, что патч активен После запуска залогиньтесь в UI бэкенда — в настройках организации все ограничения (app executions, environments, tenants, branding и т.д.) будут показываться как активные/безлимитные. Проверка собранного бинаря: ```bash docker run --rm --entrypoint sh marker689/shuffle-backend-unchained:12082026 \ -c 'grep -c "LICENSE BYPASS PATCH" /app/shuffle-shared/shared.go && grep "shuffle-shared =>" /app/go.mod' ``` Ожидаемый вывод: ``` 4 replace github.com/shuffle/shuffle-shared => ./shuffle-shared ``` (`shared.go` — 4 маркера патча в двух функциях; `db-connector.go` — 2 маркера в `checkNoInternet`.) --- ## Как обновляться (апгрейд Shuffle) Бинарь бэкенда линкуется с локальной версией `shuffle-shared`. При апгрейде Shuffle: 1. Узнайте актуальную версию, которую требует новый `backend/go-app/go.mod` (поле `require`). 2. Скачайте исходники этой версии: ```bash curl -L -o shuffle-shared.zip \ "https://proxy.golang.org/github.com/shuffle/shuffle-shared/@v/.zip" ``` 3. Замените `backend/go-app/shuffle-shared/` новым содержимым. 4. Повторите патчи в трёх местах (см. блоки ниже). 5. Пересоберите образ. ### Патч 1 — в `HandleCheckLicense` (сразу после `func ... {`) ```go // ==== LICENSE BYPASS PATCH ==== org.Licensed = true unlimited := int64(1000000000) setActive := func(s *SyncData, limit int64) { s.Active = true s.Limit = limit } setActive(&org.SyncFeatures.AppExecutions, unlimited) setActive(&org.SyncFeatures.OnpremAppExecutions, unlimited) setActive(&org.SyncFeatures.MultiEnv, unlimited) setActive(&org.SyncFeatures.MultiTenant, unlimited) setActive(&org.SyncFeatures.MultiRegion, unlimited) setActive(&org.SyncFeatures.Webhook, unlimited) setActive(&org.SyncFeatures.Schedules, unlimited) setActive(&org.SyncFeatures.UserInput, unlimited) setActive(&org.SyncFeatures.SendMail, unlimited) setActive(&org.SyncFeatures.SendSms, unlimited) setActive(&org.SyncFeatures.Updates, unlimited) setActive(&org.SyncFeatures.EmailTrigger, unlimited) setActive(&org.SyncFeatures.Notifications, unlimited) setActive(&org.SyncFeatures.Workflows, unlimited) setActive(&org.SyncFeatures.Autocomplete, unlimited) setActive(&org.SyncFeatures.WorkflowExecutions, unlimited) setActive(&org.SyncFeatures.Authentication, unlimited) setActive(&org.SyncFeatures.Schedule, unlimited) setActive(&org.SyncFeatures.Apps, unlimited) setActive(&org.SyncFeatures.ShuffleGPT, unlimited) setActive(&org.SyncFeatures.Branding, unlimited) setActive(&org.SyncFeatures.AgentExecutions, unlimited) setActive(&org.SyncFeatures.AgentTokens, unlimited) return org // ==== END LICENSE BYPASS PATCH ==== ``` ### Патч 2 — в `IsLicensed` (сразу после `func ... {`) ```go func IsLicensed(ctx context.Context, org Org) bool { // ==== LICENSE BYPASS PATCH ==== return true // ==== END LICENSE BYPASS PATCH ==== ``` Оставшийся код тела функции остаётся неактивным (недостижимым). ### Патч 3 — в `checkNoInternet` (сразу после инициализации `license`) ```go // ==== LICENSE BYPASS PATCH ==== license.Valid = true license.Environment.Active = true license.Environment.Limit = 1000000000 license.Tenant.Active = true license.Tenant.Limit = 1000000000 license.AppRuns.Active = true license.AppRuns.Limit = 1000000000 license.Branding = true license.Timeout = "01-01-2100" return license // ==== END LICENSE BYPASS PATCH ==== ``` Этот ранний возврат делает всю дальнейшую проверку `SHUFFLE_LICENSE` недостижимой — он закрывает прямые чтения `checkNoInternet()` в `SetWorkflowQueue` (app runs) и в проверке лимита суб-организаций, которые **не идут через `HandleCheckLicense`** и не были бы закрыты патчем 1. --- ## Откат патча Чтобы вернуть стоковое поведение: 1. Удалить строку `replace github.com/shuffle/shuffle-shared => ./shuffle-shared` из `backend/go-app/go.mod`. 2. Удалить папку `backend/go-app/shuffle-shared/`. 3. Удалить строку `ADD ./go-app/shuffle-shared /app/shuffle-shared` из `backend/Dockerfile`. 4. Пересобрать образ.