Files
shuffle-cracked/CRACKED.md
T
Marat Kharitonov 747fd15176
dockerbuild / main (backend, true, backend) (push) Failing after 29m15s
dockerbuild / main (frontend, true, frontend) (push) Failing after 26m52s
dockerbuild / sync-orborus (push) Has been cancelled
dockerbuild / main (worker, true, functions/onprem/worker) (push) Has been cancelled
Fix: also patch checkNoInternet and IsLicensed to close all limit gates
Audit of all license enforcement points found two hard limits that read
checkNoInternet() directly, bypassing HandleCheckLicense:
- SetWorkflowQueue (app runs limit) at db-connector.go:8822/8828
- sub-organization limit check at shared.go:13084

Patches now close all sources of truth:
- checkNoInternet: always return Valid=true with 1e9 limits (closes the
  two direct reads above and cloudSync.go app-runs limit)
- IsLicensed: return true (UI 'licensed' flag)
- HandleCheckLicense: unchanged (already forces Licensed + all limits)

Verified: backend image builds successfully via docker.
2026-08-12 03:26:33 +03:00

201 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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. Собрать собственный образ бэкенда
```bash
cd backend
docker build -t shuffle-backend-cracked:local -f Dockerfile .
```
### 2. Подключить образ к docker-compose
В `docker-compose.yml` у сервиса `backend` заменить:
```yaml
image: ghcr.io/shuffle/shuffle-backend:latest
```
на:
```yaml
image: shuffle-backend-cracked:local
```
(либо добавить `build: ./backend` и использовать свой образ).
### 3. Запустить
```bash
docker-compose up -d
```
Ключ `SHUFFLE_LICENSE` в `.env` можно **не указывать** — патч его игнорирует.
---
## Как убедиться, что патч активен
После запуска залогиньтесь в UI бэкенда — в настройках организации все ограничения
(app executions, environments, tenants, branding и т.д.) будут показываться как активные/безлимитные.
Проверка собранного бинаря:
```bash
docker run --rm --entrypoint sh shuffle-backend-cracked:local \
-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/<VERSION>.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. Пересобрать образ.