mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
feat: Add env variables to support exposing /workflows/demo
route and /nodes.json
route (#8506)
Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
This commit is contained in:
parent
35fb7102cb
commit
4b01335aa4
|
@ -83,6 +83,7 @@ export class FrontendService {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.settings = {
|
this.settings = {
|
||||||
|
previewMode: process.env.N8N_PREVIEW_MODE === 'true',
|
||||||
endpointForm: config.getEnv('endpoints.form'),
|
endpointForm: config.getEnv('endpoints.form'),
|
||||||
endpointFormTest: config.getEnv('endpoints.formTest'),
|
endpointFormTest: config.getEnv('endpoints.formTest'),
|
||||||
endpointFormWaiting: config.getEnv('endpoints.formWaiting'),
|
endpointFormWaiting: config.getEnv('endpoints.formWaiting'),
|
||||||
|
|
|
@ -7,8 +7,9 @@ vi.mock('@/stores/users.store', () => ({
|
||||||
|
|
||||||
describe('Checks', () => {
|
describe('Checks', () => {
|
||||||
describe('isAuthenticated()', () => {
|
describe('isAuthenticated()', () => {
|
||||||
|
const mockUser = { id: 'user123', name: 'Test User' };
|
||||||
|
|
||||||
it('should return true if there is a current user', () => {
|
it('should return true if there is a current user', () => {
|
||||||
const mockUser = { id: 'user123', name: 'Test User' };
|
|
||||||
vi.mocked(useUsersStore).mockReturnValue({ currentUser: mockUser } as unknown as ReturnType<
|
vi.mocked(useUsersStore).mockReturnValue({ currentUser: mockUser } as unknown as ReturnType<
|
||||||
typeof useUsersStore
|
typeof useUsersStore
|
||||||
>);
|
>);
|
||||||
|
@ -23,5 +24,29 @@ describe('Checks', () => {
|
||||||
|
|
||||||
expect(isAuthenticated()).toBe(false);
|
expect(isAuthenticated()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return true if there is a current user and bypass returns false', () => {
|
||||||
|
vi.mocked(useUsersStore).mockReturnValue({ currentUser: mockUser } as ReturnType<
|
||||||
|
typeof useUsersStore
|
||||||
|
>);
|
||||||
|
|
||||||
|
expect(isAuthenticated({ bypass: () => false })).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true if there is no current user and bypass returns true', () => {
|
||||||
|
vi.mocked(useUsersStore).mockReturnValue({ currentUser: null } as ReturnType<
|
||||||
|
typeof useUsersStore
|
||||||
|
>);
|
||||||
|
|
||||||
|
expect(isAuthenticated({ bypass: () => true })).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false if there is no current user and bypass returns false', () => {
|
||||||
|
vi.mocked(useUsersStore).mockReturnValue({ currentUser: null } as ReturnType<
|
||||||
|
typeof useUsersStore
|
||||||
|
>);
|
||||||
|
|
||||||
|
expect(isAuthenticated({ bypass: () => false })).toBe(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
import { useUsersStore } from '@/stores/users.store';
|
import { useUsersStore } from '@/stores/users.store';
|
||||||
import type { RBACPermissionCheck, AuthenticatedPermissionOptions } from '@/types/rbac';
|
import type { RBACPermissionCheck, AuthenticatedPermissionOptions } from '@/types/rbac';
|
||||||
|
|
||||||
export const isAuthenticated: RBACPermissionCheck<AuthenticatedPermissionOptions> = () => {
|
export const isAuthenticated: RBACPermissionCheck<AuthenticatedPermissionOptions> = (options) => {
|
||||||
|
if (options?.bypass?.()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const usersStore = useUsersStore();
|
const usersStore = useUsersStore();
|
||||||
return !!usersStore.currentUser;
|
return !!usersStore.currentUser;
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,8 +7,9 @@ export const authenticatedMiddleware: RouterMiddleware<AuthenticatedPermissionOp
|
||||||
to,
|
to,
|
||||||
from,
|
from,
|
||||||
next,
|
next,
|
||||||
|
options,
|
||||||
) => {
|
) => {
|
||||||
const valid = isAuthenticated();
|
const valid = isAuthenticated(options);
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
const redirect =
|
const redirect =
|
||||||
to.query.redirect ??
|
to.query.redirect ??
|
||||||
|
|
|
@ -359,6 +359,14 @@ export const routes = [
|
||||||
},
|
},
|
||||||
meta: {
|
meta: {
|
||||||
middleware: ['authenticated'],
|
middleware: ['authenticated'],
|
||||||
|
middlewareOptions: {
|
||||||
|
authenticated: {
|
||||||
|
bypass: () => {
|
||||||
|
const settingsStore = useSettingsStore();
|
||||||
|
return settingsStore.isPreviewMode;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -85,6 +85,9 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, {
|
||||||
isSwaggerUIEnabled(): boolean {
|
isSwaggerUIEnabled(): boolean {
|
||||||
return this.api.swaggerUi.enabled;
|
return this.api.swaggerUi.enabled;
|
||||||
},
|
},
|
||||||
|
isPreviewMode(): boolean {
|
||||||
|
return this.settings.previewMode;
|
||||||
|
},
|
||||||
publicApiLatestVersion(): number {
|
publicApiLatestVersion(): number {
|
||||||
return this.api.latestVersion;
|
return this.api.latestVersion;
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,7 +2,9 @@ import type { EnterpriseEditionFeature } from '@/constants';
|
||||||
import type { Resource, ScopeOptions, Scope } from '@n8n/permissions';
|
import type { Resource, ScopeOptions, Scope } from '@n8n/permissions';
|
||||||
import type { IRole } from '@/Interface';
|
import type { IRole } from '@/Interface';
|
||||||
|
|
||||||
export type AuthenticatedPermissionOptions = {};
|
export type AuthenticatedPermissionOptions = {
|
||||||
|
bypass?: () => boolean;
|
||||||
|
};
|
||||||
export type CustomPermissionOptions<C = {}> = RBACPermissionCheck<C>;
|
export type CustomPermissionOptions<C = {}> = RBACPermissionCheck<C>;
|
||||||
export type DefaultUserMiddlewareOptions = {};
|
export type DefaultUserMiddlewareOptions = {};
|
||||||
export type InstanceOwnerMiddlewareOptions = {};
|
export type InstanceOwnerMiddlewareOptions = {};
|
||||||
|
|
|
@ -805,13 +805,16 @@ export default defineComponent({
|
||||||
this.clipboard.onPaste.value = this.onClipboardPasteEvent;
|
this.clipboard.onPaste.value = this.onClipboardPasteEvent;
|
||||||
|
|
||||||
this.canvasStore.startLoading();
|
this.canvasStore.startLoading();
|
||||||
const loadPromises = [
|
const loadPromises =
|
||||||
this.loadActiveWorkflows(),
|
this.settingsStore.isPreviewMode && this.isDemo
|
||||||
this.loadCredentials(),
|
? []
|
||||||
this.loadCredentialTypes(),
|
: [
|
||||||
this.loadVariables(),
|
this.loadActiveWorkflows(),
|
||||||
this.loadSecrets(),
|
this.loadCredentials(),
|
||||||
];
|
this.loadCredentialTypes(),
|
||||||
|
this.loadVariables(),
|
||||||
|
this.loadSecrets(),
|
||||||
|
];
|
||||||
|
|
||||||
if (this.nodeTypesStore.allNodeTypes.length === 0) {
|
if (this.nodeTypesStore.allNodeTypes.length === 0) {
|
||||||
loadPromises.push(this.loadNodeTypes());
|
loadPromises.push(this.loadNodeTypes());
|
||||||
|
|
|
@ -2505,6 +2505,7 @@ export interface IN8nUISettings {
|
||||||
workflowTagsDisabled: boolean;
|
workflowTagsDisabled: boolean;
|
||||||
logLevel: LogLevel;
|
logLevel: LogLevel;
|
||||||
hiringBannerEnabled: boolean;
|
hiringBannerEnabled: boolean;
|
||||||
|
previewMode: boolean;
|
||||||
templates: {
|
templates: {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
host: string;
|
host: string;
|
||||||
|
|
Loading…
Reference in a new issue