mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
fix(core): Stop enforcing max numbers of API keys limit (no-changelog) (#13631)
This commit is contained in:
parent
e633e91f69
commit
1909b74350
|
@ -86,7 +86,6 @@ export interface FrontendSettings {
|
|||
};
|
||||
};
|
||||
publicApi: {
|
||||
apiKeysPerUserLimit: number;
|
||||
enabled: boolean;
|
||||
latestVersion: number;
|
||||
path: string;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<NumericLicenseFeature, number> = {
|
||||
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -145,7 +145,6 @@ export class FrontendService {
|
|||
},
|
||||
},
|
||||
publicApi: {
|
||||
apiKeysPerUserLimit: this.license.getApiKeysPerUserLimit(),
|
||||
enabled: isApiEnabled(),
|
||||
latestVersion: 1,
|
||||
path: this.globalConfig.publicApi.path,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -63,7 +63,6 @@ export const defaultSettings: FrontendSettings = {
|
|||
enabled: false,
|
||||
},
|
||||
publicApi: {
|
||||
apiKeysPerUserLimit: 0,
|
||||
enabled: false,
|
||||
latestVersion: 0,
|
||||
path: '',
|
||||
|
|
|
@ -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<ApiKey[]>([]);
|
||||
|
||||
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,
|
||||
};
|
||||
});
|
||||
|
|
|
@ -32,7 +32,6 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, () => {
|
|||
});
|
||||
const templatesEndpointHealthy = ref(false);
|
||||
const api = ref({
|
||||
apiKeysPerUserLimit: 0,
|
||||
enabled: false,
|
||||
latestVersion: 0,
|
||||
path: '/',
|
||||
|
|
|
@ -179,11 +179,7 @@ function onEdit(id: string) {
|
|||
</n8n-link>
|
||||
</div>
|
||||
<div class="mt-m text-right">
|
||||
<n8n-button
|
||||
size="large"
|
||||
:disabled="!apiKeysStore.canAddMoreApiKeys"
|
||||
@click="onCreateApiKey"
|
||||
>
|
||||
<n8n-button size="large" @click="onCreateApiKey">
|
||||
{{ i18n.baseText('settings.api.create.button') }}
|
||||
</n8n-button>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue