From ac4e0fbb47b818973958e37e6b80201ad2ffed6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=95=E0=A4=BE=E0=A4=B0=E0=A4=A4=E0=A5=8B=E0=A4=AB?= =?UTF-8?q?=E0=A5=8D=E0=A4=AB=E0=A5=87=E0=A4=B2=E0=A4=B8=E0=A5=8D=E0=A4=95?= =?UTF-8?q?=E0=A5=8D=E0=A4=B0=E0=A4=BF=E0=A4=AA=E0=A5=8D=E0=A4=9F=E2=84=A2?= Date: Tue, 28 May 2024 14:43:22 +0200 Subject: [PATCH] fix(core): Block Public API related REST calls when Public API is not enabled (#9521) --- packages/cli/src/PublicApi/index.ts | 7 +--- packages/cli/src/controllers/me.controller.ts | 17 ++++++--- packages/cli/src/services/frontend.service.ts | 3 +- packages/cli/test/integration/me.api.test.ts | 36 ++++++++++++++++--- 4 files changed, 48 insertions(+), 15 deletions(-) diff --git a/packages/cli/src/PublicApi/index.ts b/packages/cli/src/PublicApi/index.ts index 104f92bd1843d..95b0e3e5c4e25 100644 --- a/packages/cli/src/PublicApi/index.ts +++ b/packages/cli/src/PublicApi/index.ts @@ -153,11 +153,6 @@ export const loadPublicApiVersions = async ( }; }; -function isApiEnabledByLicense(): boolean { - const license = Container.get(License); - return !license.isAPIDisabled(); -} - export function isApiEnabled(): boolean { - return !config.get('publicApi.disabled') && isApiEnabledByLicense(); + return !config.get('publicApi.disabled') && !Container.get(License).isAPIDisabled(); } diff --git a/packages/cli/src/controllers/me.controller.ts b/packages/cli/src/controllers/me.controller.ts index 3a3149d4e955c..9afe583d56eaa 100644 --- a/packages/cli/src/controllers/me.controller.ts +++ b/packages/cli/src/controllers/me.controller.ts @@ -1,6 +1,6 @@ import validator from 'validator'; import { plainToInstance } from 'class-transformer'; -import { Response } from 'express'; +import { type RequestHandler, Response } from 'express'; import { randomBytes } from 'crypto'; import { AuthService } from '@/auth/auth.service'; @@ -22,6 +22,15 @@ import { ExternalHooks } from '@/ExternalHooks'; import { InternalHooks } from '@/InternalHooks'; import { BadRequestError } from '@/errors/response-errors/bad-request.error'; import { UserRepository } from '@/databases/repositories/user.repository'; +import { isApiEnabled } from '@/PublicApi'; + +export const isApiEnabledMiddleware: RequestHandler = (_, res, next) => { + if (isApiEnabled()) { + next(); + } else { + res.status(404).end(); + } +}; @RestController('/me') export class MeController { @@ -185,7 +194,7 @@ export class MeController { /** * Creates an API Key */ - @Post('/api-key') + @Post('/api-key', { middlewares: [isApiEnabledMiddleware] }) async createAPIKey(req: AuthenticatedRequest) { const apiKey = `n8n_api_${randomBytes(40).toString('hex')}`; @@ -202,7 +211,7 @@ export class MeController { /** * Get an API Key */ - @Get('/api-key') + @Get('/api-key', { middlewares: [isApiEnabledMiddleware] }) async getAPIKey(req: AuthenticatedRequest) { return { apiKey: req.user.apiKey }; } @@ -210,7 +219,7 @@ export class MeController { /** * Deletes an API Key */ - @Delete('/api-key') + @Delete('/api-key', { middlewares: [isApiEnabledMiddleware] }) async deleteAPIKey(req: AuthenticatedRequest) { await this.userService.update(req.user.id, { apiKey: null }); diff --git a/packages/cli/src/services/frontend.service.ts b/packages/cli/src/services/frontend.service.ts index 65f0330b53d6e..340fcb6390b83 100644 --- a/packages/cli/src/services/frontend.service.ts +++ b/packages/cli/src/services/frontend.service.ts @@ -31,6 +31,7 @@ import type { CommunityPackagesService } from '@/services/communityPackages.serv import { Logger } from '@/Logger'; import { UrlService } from './url.service'; import { InternalHooks } from '@/InternalHooks'; +import { isApiEnabled } from '@/PublicApi'; @Service() export class FrontendService { @@ -143,7 +144,7 @@ export class FrontendService { }, }, publicApi: { - enabled: !config.get('publicApi.disabled') && !this.license.isAPIDisabled(), + enabled: isApiEnabled(), latestVersion: 1, path: config.getEnv('publicApi.path'), swaggerUi: { diff --git a/packages/cli/test/integration/me.api.test.ts b/packages/cli/test/integration/me.api.test.ts index 1a7eb1b4ff734..4e6a6be1fe2ad 100644 --- a/packages/cli/test/integration/me.api.test.ts +++ b/packages/cli/test/integration/me.api.test.ts @@ -1,7 +1,12 @@ +import { Container } from 'typedi'; import type { SuperAgentTest } from 'supertest'; import { IsNull } from '@n8n/typeorm'; import validator from 'validator'; + import type { User } from '@db/entities/User'; +import { UserRepository } from '@db/repositories/user.repository'; +import { ProjectRepository } from '@db/repositories/project.repository'; + import { SUCCESS_RESPONSE_BODY } from './shared/constants'; import { randomApiKey, @@ -12,15 +17,38 @@ import { } from './shared/random'; import * as testDb from './shared/testDb'; import * as utils from './shared/utils/'; -import { addApiKey, createUser, createUserShell } from './shared/db/users'; -import Container from 'typedi'; -import { UserRepository } from '@db/repositories/user.repository'; -import { ProjectRepository } from '@/databases/repositories/project.repository'; +import { addApiKey, createOwner, createUser, createUserShell } from './shared/db/users'; +import config from '@/config'; const testServer = utils.setupTestServer({ endpointGroups: ['me'] }); beforeEach(async () => { await testDb.truncate(['User']); + config.set('publicApi.disabled', false); +}); + +describe('When public API is disabled', () => { + let owner: User; + let authAgent: SuperAgentTest; + + beforeEach(async () => { + owner = await createOwner(); + await addApiKey(owner); + authAgent = testServer.authAgentFor(owner); + config.set('publicApi.disabled', true); + }); + + test('POST /me/api-key should 404', async () => { + await authAgent.post('/me/api-key').expect(404); + }); + + test('GET /me/api-key should 404', async () => { + await authAgent.get('/me/api-key').expect(404); + }); + + test('DELETE /me/api-key should 404', async () => { + await authAgent.delete('/me/api-key').expect(404); + }); }); describe('Owner shell', () => {