From 2b9cb0a2543d33ff19dbbd0ff58007fc2dfdfc36 Mon Sep 17 00:00:00 2001 From: Samuel Date: Wed, 18 Jun 2025 10:44:00 +0000 Subject: [PATCH] 1.98.1 --- .gitignore | 1 + build.sh | 66 +++++++++++++++++++++ patches/1.98.1/config.test.ts.patch | 28 +++++++++ patches/1.98.1/diagnostics.config.ts.patch | 31 ++++++++++ patches/1.98.1/license-state.ts.patch | 40 +++++++++++++ patches/1.98.1/license.config.ts.patch | 18 ++++++ patches/1.98.1/license.ts.patch | 66 +++++++++++++++++++++ patches/default/config.test.ts.patch | 28 +++++++++ patches/default/diagnostics.config.ts.patch | 31 ++++++++++ patches/default/license-state.ts.patch | 40 +++++++++++++ patches/default/license.config.ts.patch | 18 ++++++ patches/default/license.ts.patch | 66 +++++++++++++++++++++ 12 files changed, 433 insertions(+) create mode 100644 .gitignore create mode 100755 build.sh create mode 100644 patches/1.98.1/config.test.ts.patch create mode 100644 patches/1.98.1/diagnostics.config.ts.patch create mode 100644 patches/1.98.1/license-state.ts.patch create mode 100644 patches/1.98.1/license.config.ts.patch create mode 100644 patches/1.98.1/license.ts.patch create mode 100644 patches/default/config.test.ts.patch create mode 100644 patches/default/diagnostics.config.ts.patch create mode 100644 patches/default/license-state.ts.patch create mode 100644 patches/default/license.config.ts.patch create mode 100644 patches/default/license.ts.patch diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7424d5a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/n8n* diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..c5f70b4 --- /dev/null +++ b/build.sh @@ -0,0 +1,66 @@ +#!/bin/bash +VERSION=1.98.1 + +REPO_DIR="n8n-$VERSION" + +if [ -d "$REPO_DIR" ]; then + echo "---- Removing old directory of $VERSION ----" + rm -Rf $REPO_DIR +fi + +echo "---- Cloning n8n for version $VERSION ----" +git -c advice.detachedHead=false clone --depth 1 --branch "n8n@$VERSION" --single-branch https://github.com/n8n-io/n8n.git $REPO_DIR + +echo "---- Verifying patches for $VERSION ----" +cd $REPO_DIR + +PATCH_VERSION=$VERSION + +if [ ! -d "../patches/$PATCH_VERSION/" ]; then + echo " Direct patches for $PATCH_VERSION couldn't be found trying default patches" + PATCH_VERSION="default" +fi + +has_patch_error=0 +for patch_filename in ../patches/$PATCH_VERSION/*.patch; do + git apply --check $patch_filename; + if [ $? -eq 0 ]; then + echo " - Dryrun for \"$patch_filename\" successful" + else + echo " - Dryrun for \"$patch_filename\" was unsuccessful, please check the patch file" + has_patch_error=1 + fi +done + +if [ $has_patch_error -ne 0 ]; then + echo " Found error while patching. Exiting" + exit 1 +fi + +for patch_filename in ../patches/$PATCH_VERSION/*.patch; do + echo " - Applying \"$patch_filename\"" + git apply --whitespace=nowarn $patch_filename; +done + + +echo "---- Building base image for $VERSION ----" + +docker image rm n8n-license-patched-base:22 2>/dev/null +docker build -t n8n-license-patched-base:22 -f docker/images/n8n-base/Dockerfile . +if [ $? -ne 0 ]; then + echo "Build unsuccessful. Exiting" +fi + +echo "---- Patching and building main image for $VERSION ----" + +sed -i 's/n8nio\/base/n8n-license-patched-base/g' docker/images/n8n/Dockerfile +if [ $? -ne 0 ]; then + echo "Base image tag patch unsuccessful. Exiting" +fi + +docker image rm n8n-license-patched:$VERSION 2>/dev/null +docker build -t n8n-license-patched:$VERSION -f docker/images/n8n/Dockerfile . +if [ $? -ne 0 ]; then + echo "Build unsuccessful. Exiting" +fi + diff --git a/patches/1.98.1/config.test.ts.patch b/patches/1.98.1/config.test.ts.patch new file mode 100644 index 0000000..534e9c3 --- /dev/null +++ b/patches/1.98.1/config.test.ts.patch @@ -0,0 +1,28 @@ +diff --git a/packages/@n8n/config/test/config.test.ts b/packages/@n8n/config/test/config.test.ts +index bea302dbb..394e12a28 100644 +--- a/packages/@n8n/config/test/config.test.ts ++++ b/packages/@n8n/config/test/config.test.ts +@@ -263,7 +263,7 @@ describe('GlobalConfig', () => { + gracefulShutdownTimeout: 30, + }, + license: { +- serverUrl: 'https://license.n8n.io/v1', ++ serverUrl: 'https://0.0.0.0', + autoRenewalEnabled: true, + detachFloatingOnShutdown: true, + activationKey: '', +@@ -289,11 +289,11 @@ describe('GlobalConfig', () => { + }, + diagnostics: { + enabled: true, +- frontendConfig: '1zPn9bgWPzlQc0p8Gj1uiK6DOTn;https://telemetry.n8n.io', +- backendConfig: '1zPn7YoGC3ZXE9zLeTKLuQCB4F6;https://telemetry.n8n.io', ++ frontendConfig: '1zPn9bgWPzlQc0p8Gj1uiK6DOTn;https://0.0.0.0', ++ backendConfig: '1zPn7YoGC3ZXE9zLeTKLuQCB4F6;https://0.0.0.0', + posthogConfig: { + apiKey: 'phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo', +- apiHost: 'https://ph.n8n.io', ++ apiHost: 'https://0.0.0.0', + }, + }, + aiAssistant: { diff --git a/patches/1.98.1/diagnostics.config.ts.patch b/patches/1.98.1/diagnostics.config.ts.patch new file mode 100644 index 0000000..94cba01 --- /dev/null +++ b/patches/1.98.1/diagnostics.config.ts.patch @@ -0,0 +1,31 @@ +diff --git a/packages/@n8n/config/src/configs/diagnostics.config.ts b/packages/@n8n/config/src/configs/diagnostics.config.ts +index 5ff6abf83..c89777372 100644 +--- a/packages/@n8n/config/src/configs/diagnostics.config.ts ++++ b/packages/@n8n/config/src/configs/diagnostics.config.ts +@@ -8,22 +8,22 @@ class PostHogConfig { + + /** API host for PostHog. */ + @Env('N8N_DIAGNOSTICS_POSTHOG_API_HOST') +- apiHost: string = 'https://ph.n8n.io'; ++ apiHost: string = 'https://0.0.0.0'; + } + + @Config + export class DiagnosticsConfig { + /** Whether diagnostics are enabled. */ + @Env('N8N_DIAGNOSTICS_ENABLED') +- enabled: boolean = true; ++ enabled: boolean = false; + + /** Diagnostics config for frontend. */ + @Env('N8N_DIAGNOSTICS_CONFIG_FRONTEND') +- frontendConfig: string = '1zPn9bgWPzlQc0p8Gj1uiK6DOTn;https://telemetry.n8n.io'; ++ frontendConfig: string = '1zPn9bgWPzlQc0p8Gj1uiK6DOTn;https://0.0.0.0'; + + /** Diagnostics config for backend. */ + @Env('N8N_DIAGNOSTICS_CONFIG_BACKEND') +- backendConfig: string = '1zPn7YoGC3ZXE9zLeTKLuQCB4F6;https://telemetry.n8n.io'; ++ backendConfig: string = '1zPn7YoGC3ZXE9zLeTKLuQCB4F6;https://0.0.0.0'; + + @Nested + posthogConfig: PostHogConfig; diff --git a/patches/1.98.1/license-state.ts.patch b/patches/1.98.1/license-state.ts.patch new file mode 100644 index 0000000..3bdd6f8 --- /dev/null +++ b/patches/1.98.1/license-state.ts.patch @@ -0,0 +1,40 @@ +diff --git a/packages/@n8n/backend-common/src/license-state.ts b/packages/@n8n/backend-common/src/license-state.ts +index b2ad56f84..4db90066e 100644 +--- a/packages/@n8n/backend-common/src/license-state.ts ++++ b/packages/@n8n/backend-common/src/license-state.ts +@@ -4,6 +4,8 @@ import { UnexpectedError } from 'n8n-workflow'; + + import type { FeatureReturnType, LicenseProvider } from './types'; + ++import { LICENSE_FEATURES, LICENSE_QUOTAS } from '@n8n/constants'; ++ + class ProviderNotSetError extends UnexpectedError { + constructor() { + super('Cannot query license state because license provider has not been set'); +@@ -27,15 +29,20 @@ export class LicenseState { + // -------------------- + + isLicensed(feature: BooleanLicenseFeature) { +- this.assertProvider(); +- +- return this.licenseProvider.isLicensed(feature); ++ if(feature == "feat:showNonProdBanner") { return false; } ++ if(feature == "feat:apiDisabled") { return false; } ++ return true; + } + + getValue(feature: T): FeatureReturnType[T] { +- this.assertProvider(); +- +- return this.licenseProvider.getValue(feature); ++ if(feature == "planName") { return "PatchedLicenseCheck" as FeatureReturnType[T]; } ++ if(feature in LICENSE_FEATURES || feature.startsWith("feat:")) { ++ return this.isLicensed(feature as BooleanLicenseFeature) as FeatureReturnType[T]; ++ } ++ if(feature in LICENSE_QUOTAS || feature.startsWith("quota:")) { ++ return UNLIMITED_LICENSE_QUOTA as FeatureReturnType[T]; ++ } ++ return undefined; + } + + // -------------------- diff --git a/patches/1.98.1/license.config.ts.patch b/patches/1.98.1/license.config.ts.patch new file mode 100644 index 0000000..3a00389 --- /dev/null +++ b/patches/1.98.1/license.config.ts.patch @@ -0,0 +1,18 @@ +diff --git a/packages/@n8n/config/src/configs/license.config.ts b/packages/@n8n/config/src/configs/license.config.ts +index 005b5f5dc..b513fb6a2 100644 +--- a/packages/@n8n/config/src/configs/license.config.ts ++++ b/packages/@n8n/config/src/configs/license.config.ts +@@ -4,11 +4,11 @@ import { Config, Env } from '../decorators'; + export class LicenseConfig { + /** License server URL to retrieve license. */ + @Env('N8N_LICENSE_SERVER_URL') +- serverUrl: string = 'https://license.n8n.io/v1'; ++ serverUrl: string = 'https://0.0.0.0/'; + + /** Whether autorenewal for licenses is enabled. */ + @Env('N8N_LICENSE_AUTO_RENEW_ENABLED') +- autoRenewalEnabled: boolean = true; ++ autoRenewalEnabled: boolean = false; + + /** Activation key to initialize license. */ + @Env('N8N_LICENSE_ACTIVATION_KEY') diff --git a/patches/1.98.1/license.ts.patch b/patches/1.98.1/license.ts.patch new file mode 100644 index 0000000..a878107 --- /dev/null +++ b/patches/1.98.1/license.ts.patch @@ -0,0 +1,66 @@ +diff --git a/packages/cli/src/license.ts b/packages/cli/src/license.ts +index eec82fe9e..2dd0429e3 100644 +--- a/packages/cli/src/license.ts ++++ b/packages/cli/src/license.ts +@@ -89,34 +89,6 @@ export class License implements LicenseProvider { + this.logger.warn(LICENSE_RENEWAL_DISABLED_WARNING); + } + +- try { +- this.manager = new LicenseManager({ +- server, +- tenantId: this.globalConfig.license.tenantId, +- productIdentifier: `n8n-${N8N_VERSION}`, +- autoRenewEnabled: shouldRenew, +- renewOnInit: shouldRenew, +- autoRenewOffset, +- detachFloatingOnShutdown: this.globalConfig.license.detachFloatingOnShutdown, +- offlineMode, +- logger: this.logger, +- loadCertStr: async () => await this.loadCertStr(), +- saveCertStr, +- deviceFingerprint: () => this.instanceSettings.instanceId, +- collectUsageMetrics, +- collectPassthroughData, +- onFeatureChange, +- onLicenseRenewed, +- }); +- +- await this.manager.initialize(); +- +- this.logger.debug('License initialized'); +- } catch (error: unknown) { +- if (error instanceof Error) { +- this.logger.error('Could not initialize license manager sdk', { error }); +- } +- } + } + + async loadCertStr(): Promise { +@@ -213,7 +185,9 @@ export class License implements LicenseProvider { + } + + isLicensed(feature: BooleanLicenseFeature) { +- return this.manager?.hasFeatureEnabled(feature) ?? false; ++ if(feature == "feat:showNonProdBanner") { return false; } ++ if(feature == "feat:apiDisabled") { return false; } ++ return true; + } + + /** @deprecated Use `LicenseState.isSharingLicensed` instead. */ +@@ -341,7 +315,14 @@ export class License implements LicenseProvider { + } + + getValue(feature: T): FeatureReturnType[T] { +- return this.manager?.getFeatureValue(feature) as FeatureReturnType[T]; ++ if(feature == "planName") { return "PatchedLicenseCheck" as FeatureReturnType[T]; } ++ if(feature in LICENSE_FEATURES || feature.startsWith("feat:")) { ++ return this.isLicensed(feature as BooleanLicenseFeature) as FeatureReturnType[T]; ++ } ++ if(feature in LICENSE_QUOTAS || feature.startsWith("quota:")) { ++ return UNLIMITED_LICENSE_QUOTA as FeatureReturnType[T]; ++ } ++ return undefined; + } + + getManagementJwt(): string { diff --git a/patches/default/config.test.ts.patch b/patches/default/config.test.ts.patch new file mode 100644 index 0000000..534e9c3 --- /dev/null +++ b/patches/default/config.test.ts.patch @@ -0,0 +1,28 @@ +diff --git a/packages/@n8n/config/test/config.test.ts b/packages/@n8n/config/test/config.test.ts +index bea302dbb..394e12a28 100644 +--- a/packages/@n8n/config/test/config.test.ts ++++ b/packages/@n8n/config/test/config.test.ts +@@ -263,7 +263,7 @@ describe('GlobalConfig', () => { + gracefulShutdownTimeout: 30, + }, + license: { +- serverUrl: 'https://license.n8n.io/v1', ++ serverUrl: 'https://0.0.0.0', + autoRenewalEnabled: true, + detachFloatingOnShutdown: true, + activationKey: '', +@@ -289,11 +289,11 @@ describe('GlobalConfig', () => { + }, + diagnostics: { + enabled: true, +- frontendConfig: '1zPn9bgWPzlQc0p8Gj1uiK6DOTn;https://telemetry.n8n.io', +- backendConfig: '1zPn7YoGC3ZXE9zLeTKLuQCB4F6;https://telemetry.n8n.io', ++ frontendConfig: '1zPn9bgWPzlQc0p8Gj1uiK6DOTn;https://0.0.0.0', ++ backendConfig: '1zPn7YoGC3ZXE9zLeTKLuQCB4F6;https://0.0.0.0', + posthogConfig: { + apiKey: 'phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo', +- apiHost: 'https://ph.n8n.io', ++ apiHost: 'https://0.0.0.0', + }, + }, + aiAssistant: { diff --git a/patches/default/diagnostics.config.ts.patch b/patches/default/diagnostics.config.ts.patch new file mode 100644 index 0000000..94cba01 --- /dev/null +++ b/patches/default/diagnostics.config.ts.patch @@ -0,0 +1,31 @@ +diff --git a/packages/@n8n/config/src/configs/diagnostics.config.ts b/packages/@n8n/config/src/configs/diagnostics.config.ts +index 5ff6abf83..c89777372 100644 +--- a/packages/@n8n/config/src/configs/diagnostics.config.ts ++++ b/packages/@n8n/config/src/configs/diagnostics.config.ts +@@ -8,22 +8,22 @@ class PostHogConfig { + + /** API host for PostHog. */ + @Env('N8N_DIAGNOSTICS_POSTHOG_API_HOST') +- apiHost: string = 'https://ph.n8n.io'; ++ apiHost: string = 'https://0.0.0.0'; + } + + @Config + export class DiagnosticsConfig { + /** Whether diagnostics are enabled. */ + @Env('N8N_DIAGNOSTICS_ENABLED') +- enabled: boolean = true; ++ enabled: boolean = false; + + /** Diagnostics config for frontend. */ + @Env('N8N_DIAGNOSTICS_CONFIG_FRONTEND') +- frontendConfig: string = '1zPn9bgWPzlQc0p8Gj1uiK6DOTn;https://telemetry.n8n.io'; ++ frontendConfig: string = '1zPn9bgWPzlQc0p8Gj1uiK6DOTn;https://0.0.0.0'; + + /** Diagnostics config for backend. */ + @Env('N8N_DIAGNOSTICS_CONFIG_BACKEND') +- backendConfig: string = '1zPn7YoGC3ZXE9zLeTKLuQCB4F6;https://telemetry.n8n.io'; ++ backendConfig: string = '1zPn7YoGC3ZXE9zLeTKLuQCB4F6;https://0.0.0.0'; + + @Nested + posthogConfig: PostHogConfig; diff --git a/patches/default/license-state.ts.patch b/patches/default/license-state.ts.patch new file mode 100644 index 0000000..3bdd6f8 --- /dev/null +++ b/patches/default/license-state.ts.patch @@ -0,0 +1,40 @@ +diff --git a/packages/@n8n/backend-common/src/license-state.ts b/packages/@n8n/backend-common/src/license-state.ts +index b2ad56f84..4db90066e 100644 +--- a/packages/@n8n/backend-common/src/license-state.ts ++++ b/packages/@n8n/backend-common/src/license-state.ts +@@ -4,6 +4,8 @@ import { UnexpectedError } from 'n8n-workflow'; + + import type { FeatureReturnType, LicenseProvider } from './types'; + ++import { LICENSE_FEATURES, LICENSE_QUOTAS } from '@n8n/constants'; ++ + class ProviderNotSetError extends UnexpectedError { + constructor() { + super('Cannot query license state because license provider has not been set'); +@@ -27,15 +29,20 @@ export class LicenseState { + // -------------------- + + isLicensed(feature: BooleanLicenseFeature) { +- this.assertProvider(); +- +- return this.licenseProvider.isLicensed(feature); ++ if(feature == "feat:showNonProdBanner") { return false; } ++ if(feature == "feat:apiDisabled") { return false; } ++ return true; + } + + getValue(feature: T): FeatureReturnType[T] { +- this.assertProvider(); +- +- return this.licenseProvider.getValue(feature); ++ if(feature == "planName") { return "PatchedLicenseCheck" as FeatureReturnType[T]; } ++ if(feature in LICENSE_FEATURES || feature.startsWith("feat:")) { ++ return this.isLicensed(feature as BooleanLicenseFeature) as FeatureReturnType[T]; ++ } ++ if(feature in LICENSE_QUOTAS || feature.startsWith("quota:")) { ++ return UNLIMITED_LICENSE_QUOTA as FeatureReturnType[T]; ++ } ++ return undefined; + } + + // -------------------- diff --git a/patches/default/license.config.ts.patch b/patches/default/license.config.ts.patch new file mode 100644 index 0000000..3a00389 --- /dev/null +++ b/patches/default/license.config.ts.patch @@ -0,0 +1,18 @@ +diff --git a/packages/@n8n/config/src/configs/license.config.ts b/packages/@n8n/config/src/configs/license.config.ts +index 005b5f5dc..b513fb6a2 100644 +--- a/packages/@n8n/config/src/configs/license.config.ts ++++ b/packages/@n8n/config/src/configs/license.config.ts +@@ -4,11 +4,11 @@ import { Config, Env } from '../decorators'; + export class LicenseConfig { + /** License server URL to retrieve license. */ + @Env('N8N_LICENSE_SERVER_URL') +- serverUrl: string = 'https://license.n8n.io/v1'; ++ serverUrl: string = 'https://0.0.0.0/'; + + /** Whether autorenewal for licenses is enabled. */ + @Env('N8N_LICENSE_AUTO_RENEW_ENABLED') +- autoRenewalEnabled: boolean = true; ++ autoRenewalEnabled: boolean = false; + + /** Activation key to initialize license. */ + @Env('N8N_LICENSE_ACTIVATION_KEY') diff --git a/patches/default/license.ts.patch b/patches/default/license.ts.patch new file mode 100644 index 0000000..a878107 --- /dev/null +++ b/patches/default/license.ts.patch @@ -0,0 +1,66 @@ +diff --git a/packages/cli/src/license.ts b/packages/cli/src/license.ts +index eec82fe9e..2dd0429e3 100644 +--- a/packages/cli/src/license.ts ++++ b/packages/cli/src/license.ts +@@ -89,34 +89,6 @@ export class License implements LicenseProvider { + this.logger.warn(LICENSE_RENEWAL_DISABLED_WARNING); + } + +- try { +- this.manager = new LicenseManager({ +- server, +- tenantId: this.globalConfig.license.tenantId, +- productIdentifier: `n8n-${N8N_VERSION}`, +- autoRenewEnabled: shouldRenew, +- renewOnInit: shouldRenew, +- autoRenewOffset, +- detachFloatingOnShutdown: this.globalConfig.license.detachFloatingOnShutdown, +- offlineMode, +- logger: this.logger, +- loadCertStr: async () => await this.loadCertStr(), +- saveCertStr, +- deviceFingerprint: () => this.instanceSettings.instanceId, +- collectUsageMetrics, +- collectPassthroughData, +- onFeatureChange, +- onLicenseRenewed, +- }); +- +- await this.manager.initialize(); +- +- this.logger.debug('License initialized'); +- } catch (error: unknown) { +- if (error instanceof Error) { +- this.logger.error('Could not initialize license manager sdk', { error }); +- } +- } + } + + async loadCertStr(): Promise { +@@ -213,7 +185,9 @@ export class License implements LicenseProvider { + } + + isLicensed(feature: BooleanLicenseFeature) { +- return this.manager?.hasFeatureEnabled(feature) ?? false; ++ if(feature == "feat:showNonProdBanner") { return false; } ++ if(feature == "feat:apiDisabled") { return false; } ++ return true; + } + + /** @deprecated Use `LicenseState.isSharingLicensed` instead. */ +@@ -341,7 +315,14 @@ export class License implements LicenseProvider { + } + + getValue(feature: T): FeatureReturnType[T] { +- return this.manager?.getFeatureValue(feature) as FeatureReturnType[T]; ++ if(feature == "planName") { return "PatchedLicenseCheck" as FeatureReturnType[T]; } ++ if(feature in LICENSE_FEATURES || feature.startsWith("feat:")) { ++ return this.isLicensed(feature as BooleanLicenseFeature) as FeatureReturnType[T]; ++ } ++ if(feature in LICENSE_QUOTAS || feature.startsWith("quota:")) { ++ return UNLIMITED_LICENSE_QUOTA as FeatureReturnType[T]; ++ } ++ return undefined; + } + + getManagementJwt(): string {