From 1909b743502ef42a4786411f7b7b1a48b9c84991 Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Mon, 3 Mar 2025 14:32:50 +0100 Subject: [PATCH] fix(core): Stop enforcing max numbers of API keys limit (no-changelog) (#13631) --- packages/@n8n/api-types/src/frontend-settings.ts | 1 - packages/cli/src/constants.ts | 1 - .../__tests__/api-keys.controller.test.ts | 5 +---- .../cli/src/controllers/api-keys.controller.ts | 11 ----------- packages/cli/src/controllers/e2e.controller.ts | 3 --- packages/cli/src/license.ts | 4 ---- packages/cli/src/services/frontend.service.ts | 1 - .../cli/test/integration/api-keys.api.test.ts | 16 ---------------- .../frontend/editor-ui/src/__tests__/defaults.ts | 1 - .../editor-ui/src/stores/apiKeys.store.ts | 7 ------- .../editor-ui/src/stores/settings.store.ts | 1 - .../editor-ui/src/views/SettingsApiView.vue | 6 +----- 12 files changed, 2 insertions(+), 55 deletions(-) diff --git a/packages/@n8n/api-types/src/frontend-settings.ts b/packages/@n8n/api-types/src/frontend-settings.ts index e6c133e126..d39ada55e0 100644 --- a/packages/@n8n/api-types/src/frontend-settings.ts +++ b/packages/@n8n/api-types/src/frontend-settings.ts @@ -86,7 +86,6 @@ export interface FrontendSettings { }; }; publicApi: { - apiKeysPerUserLimit: number; enabled: boolean; latestVersion: number; path: string; diff --git a/packages/cli/src/constants.ts b/packages/cli/src/constants.ts index 6411c91bac..abcf298d3d 100644 --- a/packages/cli/src/constants.ts +++ b/packages/cli/src/constants.ts @@ -104,7 +104,6 @@ export const LICENSE_QUOTAS = { WORKFLOW_HISTORY_PRUNE_LIMIT: 'quota:workflowHistoryPrune', TEAM_PROJECT_LIMIT: 'quota:maxTeamProjects', AI_CREDITS: 'quota:aiCredits', - API_KEYS_PER_USER_LIMIT: 'quota:apiKeysPerUserLimit', } as const; export const UNLIMITED_LICENSE_QUOTA = -1; diff --git a/packages/cli/src/controllers/__tests__/api-keys.controller.test.ts b/packages/cli/src/controllers/__tests__/api-keys.controller.test.ts index eb13081b48..503d3fb05f 100644 --- a/packages/cli/src/controllers/__tests__/api-keys.controller.test.ts +++ b/packages/cli/src/controllers/__tests__/api-keys.controller.test.ts @@ -3,9 +3,7 @@ import { mock } from 'jest-mock-extended'; import type { ApiKey } from '@/databases/entities/api-key'; import type { User } from '@/databases/entities/user'; -import { ApiKeyRepository } from '@/databases/repositories/api-key.repository'; import { EventService } from '@/events/event.service'; -import { License } from '@/license'; import type { AuthenticatedRequest } from '@/requests'; import { PublicApiKeyService } from '@/services/public-api-key.service'; import { mockInstance } from '@test/mocking'; @@ -15,8 +13,7 @@ import { ApiKeysController } from '../api-keys.controller'; describe('ApiKeysController', () => { const publicApiKeyService = mockInstance(PublicApiKeyService); const eventService = mockInstance(EventService); - mockInstance(ApiKeyRepository); - mockInstance(License); + const controller = Container.get(ApiKeysController); let req: AuthenticatedRequest; diff --git a/packages/cli/src/controllers/api-keys.controller.ts b/packages/cli/src/controllers/api-keys.controller.ts index e2a824068a..a4d28890c4 100644 --- a/packages/cli/src/controllers/api-keys.controller.ts +++ b/packages/cli/src/controllers/api-keys.controller.ts @@ -1,11 +1,8 @@ import { CreateApiKeyRequestDto, UpdateApiKeyRequestDto } from '@n8n/api-types'; import type { RequestHandler } from 'express'; -import { ApiKeyRepository } from '@/databases/repositories/api-key.repository'; import { Body, Delete, Get, Param, Patch, Post, RestController } from '@/decorators'; -import { BadRequestError } from '@/errors/response-errors/bad-request.error'; import { EventService } from '@/events/event.service'; -import { License } from '@/license'; import { isApiEnabled } from '@/public-api'; import { AuthenticatedRequest } from '@/requests'; import { PublicApiKeyService } from '@/services/public-api-key.service'; @@ -23,8 +20,6 @@ export class ApiKeysController { constructor( private readonly eventService: EventService, private readonly publicApiKeyService: PublicApiKeyService, - private readonly apiKeysRepository: ApiKeyRepository, - private readonly license: License, ) {} /** @@ -36,12 +31,6 @@ export class ApiKeysController { _res: Response, @Body { label, expiresAt }: CreateApiKeyRequestDto, ) { - const currentNumberOfApiKeys = await this.apiKeysRepository.countBy({ userId: req.user.id }); - - if (currentNumberOfApiKeys >= this.license.getApiKeysPerUserLimit()) { - throw new BadRequestError('You have reached the maximum number of API keys allowed.'); - } - const newApiKey = await this.publicApiKeyService.createPublicApiKeyForUser(req.user, { label, expiresAt, diff --git a/packages/cli/src/controllers/e2e.controller.ts b/packages/cli/src/controllers/e2e.controller.ts index 90ba208ce1..025139aec2 100644 --- a/packages/cli/src/controllers/e2e.controller.ts +++ b/packages/cli/src/controllers/e2e.controller.ts @@ -110,7 +110,6 @@ export class E2EController { [LICENSE_QUOTAS.WORKFLOW_HISTORY_PRUNE_LIMIT]: -1, [LICENSE_QUOTAS.TEAM_PROJECT_LIMIT]: 0, [LICENSE_QUOTAS.AI_CREDITS]: 0, - [LICENSE_QUOTAS.API_KEYS_PER_USER_LIMIT]: 1, }; private numericFeatures: Record = { @@ -124,8 +123,6 @@ export class E2EController { [LICENSE_QUOTAS.TEAM_PROJECT_LIMIT]: E2EController.numericFeaturesDefaults[LICENSE_QUOTAS.TEAM_PROJECT_LIMIT], [LICENSE_QUOTAS.AI_CREDITS]: E2EController.numericFeaturesDefaults[LICENSE_QUOTAS.AI_CREDITS], - [LICENSE_QUOTAS.API_KEYS_PER_USER_LIMIT]: - E2EController.numericFeaturesDefaults[LICENSE_QUOTAS.API_KEYS_PER_USER_LIMIT], }; constructor( diff --git a/packages/cli/src/license.ts b/packages/cli/src/license.ts index 694433000d..1f2ea7da56 100644 --- a/packages/cli/src/license.ts +++ b/packages/cli/src/license.ts @@ -337,10 +337,6 @@ export class License { return this.getFeatureValue(LICENSE_QUOTAS.USERS_LIMIT) ?? UNLIMITED_LICENSE_QUOTA; } - getApiKeysPerUserLimit() { - return this.getFeatureValue(LICENSE_QUOTAS.API_KEYS_PER_USER_LIMIT) ?? 1; - } - getTriggerLimit() { return this.getFeatureValue(LICENSE_QUOTAS.TRIGGER_LIMIT) ?? UNLIMITED_LICENSE_QUOTA; } diff --git a/packages/cli/src/services/frontend.service.ts b/packages/cli/src/services/frontend.service.ts index 1b13ad847f..46f13d52ff 100644 --- a/packages/cli/src/services/frontend.service.ts +++ b/packages/cli/src/services/frontend.service.ts @@ -145,7 +145,6 @@ export class FrontendService { }, }, publicApi: { - apiKeysPerUserLimit: this.license.getApiKeysPerUserLimit(), enabled: isApiEnabled(), latestVersion: 1, path: this.globalConfig.publicApi.path, diff --git a/packages/cli/test/integration/api-keys.api.test.ts b/packages/cli/test/integration/api-keys.api.test.ts index 0f0dbf4e9e..7799ea1c93 100644 --- a/packages/cli/test/integration/api-keys.api.test.ts +++ b/packages/cli/test/integration/api-keys.api.test.ts @@ -4,7 +4,6 @@ import { Container } from '@n8n/di'; import type { User } from '@/databases/entities/user'; import { ApiKeyRepository } from '@/databases/repositories/api-key.repository'; -import { License } from '@/license'; import { PublicApiKeyService } from '@/services/public-api-key.service'; import { mockInstance } from '@test/mocking'; @@ -14,10 +13,6 @@ import * as testDb from './shared/test-db'; import type { SuperAgentTest } from './shared/types'; import * as utils from './shared/utils/'; -const license = mockInstance(License); - -license.getApiKeysPerUserLimit.mockImplementation(() => 2); - const testServer = utils.setupTestServer({ endpointGroups: ['apiKeys'] }); let publicApiKeyService: PublicApiKeyService; @@ -119,17 +114,6 @@ describe('Owner shell', () => { expect(newApiKey.rawApiKey).toBeDefined(); }); - test('POST /api-keys should fail if max number of API keys reached', async () => { - await testServer.authAgentFor(ownerShell).post('/api-keys').send({ label: 'My API Key' }); - - const secondApiKey = await testServer - .authAgentFor(ownerShell) - .post('/api-keys') - .send({ label: 'My API Key' }); - - expect(secondApiKey.statusCode).toBe(400); - }); - test('GET /api-keys should fetch the api key redacted', async () => { const expirationDateInTheFuture = Date.now() + 1000; diff --git a/packages/frontend/editor-ui/src/__tests__/defaults.ts b/packages/frontend/editor-ui/src/__tests__/defaults.ts index 43970ce786..adad4dd3d7 100644 --- a/packages/frontend/editor-ui/src/__tests__/defaults.ts +++ b/packages/frontend/editor-ui/src/__tests__/defaults.ts @@ -63,7 +63,6 @@ export const defaultSettings: FrontendSettings = { enabled: false, }, publicApi: { - apiKeysPerUserLimit: 0, enabled: false, latestVersion: 0, path: '', diff --git a/packages/frontend/editor-ui/src/stores/apiKeys.store.ts b/packages/frontend/editor-ui/src/stores/apiKeys.store.ts index 0cc897aa75..e1ab14831f 100644 --- a/packages/frontend/editor-ui/src/stores/apiKeys.store.ts +++ b/packages/frontend/editor-ui/src/stores/apiKeys.store.ts @@ -4,14 +4,12 @@ import { useRootStore } from '@/stores/root.store'; import * as publicApiApi from '@/api/api-keys'; import { computed, ref } from 'vue'; -import { useSettingsStore } from './settings.store'; import type { ApiKey, CreateApiKeyRequestDto, UpdateApiKeyRequestDto } from '@n8n/api-types'; export const useApiKeysStore = defineStore(STORES.API_KEYS, () => { const apiKeys = ref([]); const rootStore = useRootStore(); - const settingsStore = useSettingsStore(); const apiKeysSortByCreationDate = computed(() => apiKeys.value.sort((a, b) => b.createdAt.localeCompare(a.createdAt)), @@ -27,10 +25,6 @@ export const useApiKeysStore = defineStore(STORES.API_KEYS, () => { ); }); - const canAddMoreApiKeys = computed( - () => apiKeys.value.length < settingsStore.api.apiKeysPerUserLimit, - ); - const getAndCacheApiKeys = async () => { if (apiKeys.value.length) return apiKeys.value; apiKeys.value = await publicApiApi.getApiKeys(rootStore.restApiContext); @@ -62,6 +56,5 @@ export const useApiKeysStore = defineStore(STORES.API_KEYS, () => { apiKeysSortByCreationDate, apiKeysById, apiKeys, - canAddMoreApiKeys, }; }); diff --git a/packages/frontend/editor-ui/src/stores/settings.store.ts b/packages/frontend/editor-ui/src/stores/settings.store.ts index 601d22a5c6..400a35a598 100644 --- a/packages/frontend/editor-ui/src/stores/settings.store.ts +++ b/packages/frontend/editor-ui/src/stores/settings.store.ts @@ -32,7 +32,6 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, () => { }); const templatesEndpointHealthy = ref(false); const api = ref({ - apiKeysPerUserLimit: 0, enabled: false, latestVersion: 0, path: '/', diff --git a/packages/frontend/editor-ui/src/views/SettingsApiView.vue b/packages/frontend/editor-ui/src/views/SettingsApiView.vue index 996757b0e9..f98e3c452b 100644 --- a/packages/frontend/editor-ui/src/views/SettingsApiView.vue +++ b/packages/frontend/editor-ui/src/views/SettingsApiView.vue @@ -179,11 +179,7 @@ function onEdit(id: string) {
- + {{ i18n.baseText('settings.api.create.button') }}