diff --git a/packages/cli/src/services/frontend.service.ts b/packages/cli/src/services/frontend.service.ts index 86b4b8942caf3..18b9314f7344c 100644 --- a/packages/cli/src/services/frontend.service.ts +++ b/packages/cli/src/services/frontend.service.ts @@ -100,6 +100,9 @@ export class FrontendService { urlBaseEditor: instanceBaseUrl, binaryDataMode: config.getEnv('binaryDataManager.mode'), versionCli: '', + authCookie: { + secure: config.getEnv('secure_cookie'), + }, releaseChannel: config.getEnv('generic.releaseChannel'), oauthCallbackUrls: { oauth1: `${instanceBaseUrl}/${restEndpoint}/oauth1-credential/callback`, diff --git a/packages/editor-ui/src/__tests__/defaults.ts b/packages/editor-ui/src/__tests__/defaults.ts index ded1b5f3229bf..eb65ba38e0a53 100644 --- a/packages/editor-ui/src/__tests__/defaults.ts +++ b/packages/editor-ui/src/__tests__/defaults.ts @@ -1,4 +1,4 @@ -import type { INodeTypeData, INodeTypeDescription } from 'n8n-workflow'; +import type { INodeTypeData, INodeTypeDescription, IN8nUISettings } from 'n8n-workflow'; import { AGENT_NODE_TYPE, CHAT_TRIGGER_NODE_TYPE, MANUAL_TRIGGER_NODE_TYPE } from '@/constants'; import nodeTypesJson from '../../../nodes-base/dist/types/nodes.json'; import aiNodeTypesJson from '../../../@n8n/nodes-langchain/dist/types/nodes.json'; @@ -42,3 +42,111 @@ export function mockNodeTypesToArray(nodeTypes: INodeTypeData): INodeTypeDescrip export const defaultMockNodeTypesArray: INodeTypeDescription[] = mockNodeTypesToArray(defaultMockNodeTypes); + +export const defaultSettings: IN8nUISettings = { + allowedModules: {}, + communityNodesEnabled: false, + defaultLocale: '', + endpointForm: '', + endpointFormTest: '', + endpointFormWaiting: '', + endpointWebhook: '', + endpointWebhookTest: '', + enterprise: { + sharing: false, + ldap: false, + saml: false, + logStreaming: false, + debugInEditor: false, + advancedExecutionFilters: false, + variables: true, + sourceControl: false, + auditLogs: false, + showNonProdBanner: false, + workflowHistory: false, + binaryDataS3: false, + externalSecrets: false, + workerView: false, + advancedPermissions: false, + }, + expressions: { + evaluator: 'tournament', + }, + executionMode: 'regular', + executionTimeout: 0, + hideUsagePage: false, + hiringBannerEnabled: false, + instanceId: '', + isNpmAvailable: false, + license: { environment: 'development' }, + logLevel: 'info', + maxExecutionTimeout: 0, + oauthCallbackUrls: { oauth1: '', oauth2: '' }, + onboardingCallPromptEnabled: false, + personalizationSurveyEnabled: false, + releaseChannel: 'stable', + posthog: { + apiHost: '', + apiKey: '', + autocapture: false, + debug: false, + disableSessionRecording: false, + enabled: false, + }, + publicApi: { enabled: false, latestVersion: 0, path: '', swaggerUi: { enabled: false } }, + pushBackend: 'websocket', + saveDataErrorExecution: 'DEFAULT', + saveDataSuccessExecution: 'DEFAULT', + saveManualExecutions: false, + sso: { + ldap: { loginEnabled: false, loginLabel: '' }, + saml: { loginEnabled: false, loginLabel: '' }, + }, + telemetry: { + enabled: false, + }, + templates: { enabled: false, host: '' }, + timezone: '', + urlBaseEditor: '', + urlBaseWebhook: '', + authCookie: { + secure: false, + }, + userManagement: { + showSetupOnFirstLoad: false, + smtpSetup: true, + authenticationMethod: 'email', + quota: 10, + }, + versionCli: '', + versionNotifications: { + enabled: true, + endpoint: '', + infoUrl: '', + }, + workflowCallerPolicyDefaultOption: 'any', + workflowTagsDisabled: false, + variables: { + limit: -1, + }, + deployment: { + type: 'default', + }, + banners: { + dismissed: [], + }, + binaryDataMode: 'default', + previewMode: false, + mfa: { + enabled: false, + }, + ai: { + enabled: false, + provider: '', + errorDebugging: false, + }, + workflowHistory: { + pruneTime: 0, + licensePruneTime: 0, + }, +}; diff --git a/packages/editor-ui/src/__tests__/server/endpoints/settings.ts b/packages/editor-ui/src/__tests__/server/endpoints/settings.ts index d27dc14dbd320..62050417fcea7 100644 --- a/packages/editor-ui/src/__tests__/server/endpoints/settings.ts +++ b/packages/editor-ui/src/__tests__/server/endpoints/settings.ts @@ -1,99 +1,7 @@ import type { Server } from 'miragejs'; import { Response } from 'miragejs'; import type { AppSchema } from '../types'; -import type { IN8nUISettings } from 'n8n-workflow'; - -const defaultSettings: IN8nUISettings = { - allowedModules: {}, - communityNodesEnabled: false, - defaultLocale: '', - endpointForm: '', - endpointFormTest: '', - endpointFormWaiting: '', - endpointWebhook: '', - endpointWebhookTest: '', - enterprise: { - sharing: false, - ldap: false, - saml: false, - logStreaming: false, - debugInEditor: false, - advancedExecutionFilters: false, - variables: true, - sourceControl: false, - auditLogs: false, - showNonProdBanner: false, - workflowHistory: false, - debugInEditor: false, - binaryDataS3: false, - externalSecrets: false, - workerView: false, - }, - expressions: { - evaluator: 'tournament', - }, - executionMode: 'regular', - executionTimeout: 0, - hideUsagePage: false, - hiringBannerEnabled: false, - instanceId: '', - isNpmAvailable: false, - license: { environment: 'development' }, - logLevel: 'info', - maxExecutionTimeout: 0, - oauthCallbackUrls: { oauth1: '', oauth2: '' }, - onboardingCallPromptEnabled: false, - personalizationSurveyEnabled: false, - releaseChannel: 'stable', - posthog: { - apiHost: '', - apiKey: '', - autocapture: false, - debug: false, - disableSessionRecording: false, - enabled: false, - }, - publicApi: { enabled: false, latestVersion: 0, path: '', swaggerUi: { enabled: false } }, - pushBackend: 'websocket', - releaseChannel: 'stable', - saveDataErrorExecution: 'DEFAULT', - saveDataSuccessExecution: 'DEFAULT', - saveManualExecutions: false, - sso: { - ldap: { loginEnabled: false, loginLabel: '' }, - saml: { loginEnabled: false, loginLabel: '' }, - }, - telemetry: { - enabled: false, - }, - templates: { enabled: false, host: '' }, - timezone: '', - urlBaseEditor: '', - urlBaseWebhook: '', - userManagement: { - showSetupOnFirstLoad: false, - smtpSetup: true, - authenticationMethod: 'email', - }, - versionCli: '', - versionNotifications: { - enabled: true, - endpoint: '', - infoUrl: '', - }, - workflowCallerPolicyDefaultOption: 'any', - workflowTagsDisabled: false, - variables: { - limit: -1, - }, - deployment: { - type: 'default', - }, - banners: { - dismissed: [], - }, - binaryDataMode: 'default', -}; +import { defaultSettings } from '../../defaults'; export function routesForSettings(server: Server) { server.get('/rest/settings', (schema: AppSchema) => { diff --git a/packages/editor-ui/src/__tests__/utils.ts b/packages/editor-ui/src/__tests__/utils.ts index 8168b94ae0523..3e62559f74cb2 100644 --- a/packages/editor-ui/src/__tests__/utils.ts +++ b/packages/editor-ui/src/__tests__/utils.ts @@ -1,5 +1,6 @@ import type { ISettingsState } from '@/Interface'; import { UserManagementAuthenticationMethod } from '@/Interface'; +import { defaultSettings } from './defaults'; export const retry = async ( assertion: () => ReturnType, @@ -25,92 +26,7 @@ export const retry = async ( export const waitAllPromises = async () => await new Promise((resolve) => setTimeout(resolve)); export const SETTINGS_STORE_DEFAULT_STATE: ISettingsState = { - settings: { - allowedModules: {}, - communityNodesEnabled: false, - defaultLocale: '', - endpointForm: '', - endpointFormTest: '', - endpointFormWaiting: '', - endpointWebhook: '', - endpointWebhookTest: '', - enterprise: { - advancedExecutionFilters: false, - sharing: false, - ldap: false, - saml: false, - logStreaming: false, - variables: false, - sourceControl: false, - auditLogs: false, - }, - executionMode: 'regular', - executionTimeout: 0, - hideUsagePage: false, - hiringBannerEnabled: false, - instanceId: '', - isNpmAvailable: false, - license: { environment: 'production' }, - logLevel: 'info', - maxExecutionTimeout: 0, - oauthCallbackUrls: { oauth1: '', oauth2: '' }, - onboardingCallPromptEnabled: false, - personalizationSurveyEnabled: false, - posthog: { - apiHost: '', - apiKey: '', - autocapture: false, - debug: false, - disableSessionRecording: false, - enabled: false, - }, - publicApi: { enabled: false, latestVersion: 0, path: '', swaggerUi: { enabled: false } }, - pushBackend: 'sse', - saveDataErrorExecution: 'all', - saveDataSuccessExecution: 'all', - saveManualExecutions: false, - sso: { - ldap: { loginEnabled: false, loginLabel: '' }, - saml: { loginEnabled: false, loginLabel: '' }, - }, - telemetry: { enabled: false }, - templates: { enabled: false, host: '' }, - timezone: '', - urlBaseEditor: '', - urlBaseWebhook: '', - userManagement: { - enabled: false, - smtpSetup: false, - authenticationMethod: UserManagementAuthenticationMethod.Email, - }, - versionCli: '', - versionNotifications: { - enabled: false, - endpoint: '', - infoUrl: '', - }, - workflowCallerPolicyDefaultOption: 'any', - workflowTagsDisabled: false, - deployment: { - type: 'default', - }, - variables: { - limit: 100, - }, - expressions: { - evaluator: 'tournament', - }, - banners: { - dismissed: [], - }, - ai: { - enabled: false, - }, - workflowHistory: { - pruneTime: -1, - licensePruneTime: -1, - }, - }, + settings: defaultSettings, promptsData: { message: '', title: '', @@ -118,10 +34,10 @@ export const SETTINGS_STORE_DEFAULT_STATE: ISettingsState = { showValueSurvey: false, }, userManagement: { - enabled: false, showSetupOnFirstLoad: false, smtpSetup: false, authenticationMethod: UserManagementAuthenticationMethod.Email, + quota: defaultSettings.userManagement.quota, }, templatesEndpointHealthy: false, api: { diff --git a/packages/editor-ui/src/constants.ts b/packages/editor-ui/src/constants.ts index 67271b815436b..2d59fd8cd8d01 100644 --- a/packages/editor-ui/src/constants.ts +++ b/packages/editor-ui/src/constants.ts @@ -759,3 +759,19 @@ export const ROLE = { Admin: 'global:admin', Default: 'default', // default user with no email when setting up instance } as const; + +export const INSECURE_CONNECTION_WARNING = ` + +

🚫

+

Your n8n server is configured to use a secure cookie,
however you are visiting this via an insecure URL +

+
+
+ To fix this, please consider the following options: + +
+`; diff --git a/packages/editor-ui/src/stores/__tests__/posthog.test.ts b/packages/editor-ui/src/stores/__tests__/posthog.test.ts index d485dc5af60d0..c007ab0d7ca51 100644 --- a/packages/editor-ui/src/stores/__tests__/posthog.test.ts +++ b/packages/editor-ui/src/stores/__tests__/posthog.test.ts @@ -7,6 +7,7 @@ import { useTelemetryStore } from '@/stores/telemetry.store'; import type { IN8nUISettings } from 'n8n-workflow'; import { LOCAL_STORAGE_EXPERIMENT_OVERRIDES } from '@/constants'; import { nextTick } from 'vue'; +import { defaultSettings } from '../../__tests__/defaults'; const DEFAULT_POSTHOG_SETTINGS: IN8nUISettings['posthog'] = { enabled: true, @@ -21,6 +22,7 @@ const CURRENT_INSTANCE_ID = '456'; function setSettings(overrides?: Partial) { useSettingsStore().setSettings({ + ...defaultSettings, posthog: DEFAULT_POSTHOG_SETTINGS, instanceId: CURRENT_INSTANCE_ID, ...overrides, diff --git a/packages/editor-ui/src/stores/settings.store.ts b/packages/editor-ui/src/stores/settings.store.ts index 645e1f0c6a86b..0028a9a920954 100644 --- a/packages/editor-ui/src/stores/settings.store.ts +++ b/packages/editor-ui/src/stores/settings.store.ts @@ -9,7 +9,12 @@ import { import { getPromptsData, getSettings, submitContactInfo, submitValueSurvey } from '@/api/settings'; import { testHealthEndpoint } from '@/api/templates'; import type { EnterpriseEditionFeature } from '@/constants'; -import { CONTACT_PROMPT_MODAL_KEY, STORES, VALUE_SURVEY_MODAL_KEY } from '@/constants'; +import { + CONTACT_PROMPT_MODAL_KEY, + STORES, + VALUE_SURVEY_MODAL_KEY, + INSECURE_CONNECTION_WARNING, +} from '@/constants'; import type { ILdapConfig, IN8nPromptResponse, @@ -248,6 +253,15 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, { useRootStore().setVersionCli(settings.versionCli); } + if ( + settings.authCookie.secure && + location.protocol === 'http:' && + !['localhost', '127.0.0.1'].includes(location.hostname) + ) { + document.write(INSECURE_CONNECTION_WARNING); + return; + } + const isV1BannerDismissedPermanently = (settings.banners?.dismissed || []).includes('V1'); if (!isV1BannerDismissedPermanently && useRootStore().versionCli.startsWith('1.')) { useUIStore().pushBannerToStack('V1'); diff --git a/packages/workflow/src/Interfaces.ts b/packages/workflow/src/Interfaces.ts index da8a85405894f..2c36fbb101279 100644 --- a/packages/workflow/src/Interfaces.ts +++ b/packages/workflow/src/Interfaces.ts @@ -2477,6 +2477,9 @@ export interface IN8nUISettings { urlBaseWebhook: string; urlBaseEditor: string; versionCli: string; + authCookie: { + secure: boolean; + }; binaryDataMode: string; releaseChannel: 'stable' | 'beta' | 'nightly' | 'dev'; n8nMetadata?: {