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:
Alex Grozav 2024-02-23 18:20:12 +02:00 committed by GitHub
parent 35fb7102cb
commit 4b01335aa4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 59 additions and 11 deletions

View file

@ -83,6 +83,7 @@ export class FrontendService {
}
this.settings = {
previewMode: process.env.N8N_PREVIEW_MODE === 'true',
endpointForm: config.getEnv('endpoints.form'),
endpointFormTest: config.getEnv('endpoints.formTest'),
endpointFormWaiting: config.getEnv('endpoints.formWaiting'),

View file

@ -7,8 +7,9 @@ vi.mock('@/stores/users.store', () => ({
describe('Checks', () => {
describe('isAuthenticated()', () => {
const mockUser = { id: 'user123', name: 'Test 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<
typeof useUsersStore
>);
@ -23,5 +24,29 @@ describe('Checks', () => {
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);
});
});
});

View file

@ -1,7 +1,11 @@
import { useUsersStore } from '@/stores/users.store';
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();
return !!usersStore.currentUser;
};

View file

@ -7,8 +7,9 @@ export const authenticatedMiddleware: RouterMiddleware<AuthenticatedPermissionOp
to,
from,
next,
options,
) => {
const valid = isAuthenticated();
const valid = isAuthenticated(options);
if (!valid) {
const redirect =
to.query.redirect ??

View file

@ -359,6 +359,14 @@ export const routes = [
},
meta: {
middleware: ['authenticated'],
middlewareOptions: {
authenticated: {
bypass: () => {
const settingsStore = useSettingsStore();
return settingsStore.isPreviewMode;
},
},
},
},
},
{

View file

@ -85,6 +85,9 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, {
isSwaggerUIEnabled(): boolean {
return this.api.swaggerUi.enabled;
},
isPreviewMode(): boolean {
return this.settings.previewMode;
},
publicApiLatestVersion(): number {
return this.api.latestVersion;
},

View file

@ -2,7 +2,9 @@ import type { EnterpriseEditionFeature } from '@/constants';
import type { Resource, ScopeOptions, Scope } from '@n8n/permissions';
import type { IRole } from '@/Interface';
export type AuthenticatedPermissionOptions = {};
export type AuthenticatedPermissionOptions = {
bypass?: () => boolean;
};
export type CustomPermissionOptions<C = {}> = RBACPermissionCheck<C>;
export type DefaultUserMiddlewareOptions = {};
export type InstanceOwnerMiddlewareOptions = {};

View file

@ -805,13 +805,16 @@ export default defineComponent({
this.clipboard.onPaste.value = this.onClipboardPasteEvent;
this.canvasStore.startLoading();
const loadPromises = [
this.loadActiveWorkflows(),
this.loadCredentials(),
this.loadCredentialTypes(),
this.loadVariables(),
this.loadSecrets(),
];
const loadPromises =
this.settingsStore.isPreviewMode && this.isDemo
? []
: [
this.loadActiveWorkflows(),
this.loadCredentials(),
this.loadCredentialTypes(),
this.loadVariables(),
this.loadSecrets(),
];
if (this.nodeTypesStore.allNodeTypes.length === 0) {
loadPromises.push(this.loadNodeTypes());

View file

@ -2505,6 +2505,7 @@ export interface IN8nUISettings {
workflowTagsDisabled: boolean;
logLevel: LogLevel;
hiringBannerEnabled: boolean;
previewMode: boolean;
templates: {
enabled: boolean;
host: string;