mirror of
https://github.com/n8n-io/n8n.git
synced 2026-06-01 17:27:14 +02:00
136 lines
3.8 KiB
TypeScript
136 lines
3.8 KiB
TypeScript
import { CreateApiKeyRequestDto, UpdateApiKeyRequestDto } from '@n8n/api-types';
|
|
import { LICENSE_FEATURES } from '@n8n/constants';
|
|
import { AuthenticatedRequest } from '@n8n/db';
|
|
import {
|
|
Body,
|
|
Delete,
|
|
Get,
|
|
GlobalScope,
|
|
Param,
|
|
Patch,
|
|
Post,
|
|
RestController,
|
|
} from '@n8n/decorators';
|
|
import { getApiKeyScopesForRole, type ApiKeyScope } from '@n8n/permissions';
|
|
import type { RequestHandler } from 'express';
|
|
|
|
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 { PublicApiKeyService } from '@/services/public-api-key.service';
|
|
|
|
export const isApiEnabledMiddleware: RequestHandler = (_, res, next) => {
|
|
if (isApiEnabled()) {
|
|
next();
|
|
} else {
|
|
res.status(404).end();
|
|
}
|
|
};
|
|
|
|
@RestController('/api-keys')
|
|
export class ApiKeysController {
|
|
constructor(
|
|
private readonly eventService: EventService,
|
|
private readonly publicApiKeyService: PublicApiKeyService,
|
|
private readonly license: License,
|
|
) {}
|
|
|
|
/**
|
|
* Create an API Key
|
|
*/
|
|
@GlobalScope('apiKey:manage')
|
|
@Post('/', { middlewares: [isApiEnabledMiddleware] })
|
|
async createApiKey(
|
|
req: AuthenticatedRequest,
|
|
_res: Response,
|
|
@Body body: CreateApiKeyRequestDto,
|
|
) {
|
|
const scopes = this.resolveScopesForUser(req.user, body.scopes);
|
|
|
|
if (!this.publicApiKeyService.apiKeyHasValidScopesForRole(req.user, scopes)) {
|
|
throw new BadRequestError('Invalid scopes for user role');
|
|
}
|
|
|
|
const newApiKey = await this.publicApiKeyService.createPublicApiKeyForUser(req.user, {
|
|
...body,
|
|
scopes,
|
|
});
|
|
|
|
this.eventService.emit('public-api-key-created', { user: req.user, publicApi: false });
|
|
|
|
return {
|
|
...newApiKey,
|
|
apiKey: this.publicApiKeyService.redactApiKey(newApiKey.apiKey),
|
|
rawApiKey: newApiKey.apiKey,
|
|
expiresAt: body.expiresAt,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get API keys
|
|
*/
|
|
@GlobalScope('apiKey:manage')
|
|
@Get('/', { middlewares: [isApiEnabledMiddleware] })
|
|
async getApiKeys(req: AuthenticatedRequest) {
|
|
const apiKeys = await this.publicApiKeyService.getRedactedApiKeysForUser(req.user);
|
|
return apiKeys;
|
|
}
|
|
|
|
/**
|
|
* Delete an API Key
|
|
*/
|
|
@GlobalScope('apiKey:manage')
|
|
@Delete('/:id', { middlewares: [isApiEnabledMiddleware] })
|
|
async deleteApiKey(req: AuthenticatedRequest, _res: Response, @Param('id') apiKeyId: string) {
|
|
await this.publicApiKeyService.deleteApiKeyForUser(req.user, apiKeyId);
|
|
|
|
this.eventService.emit('public-api-key-deleted', { user: req.user, publicApi: false });
|
|
|
|
return { success: true };
|
|
}
|
|
|
|
/**
|
|
* Patch an API Key
|
|
*/
|
|
@GlobalScope('apiKey:manage')
|
|
@Patch('/:id', { middlewares: [isApiEnabledMiddleware] })
|
|
async updateApiKey(
|
|
req: AuthenticatedRequest,
|
|
_res: Response,
|
|
@Param('id') apiKeyId: string,
|
|
@Body body: UpdateApiKeyRequestDto,
|
|
) {
|
|
const scopes = this.resolveScopesForUser(req.user, body.scopes);
|
|
|
|
if (!this.publicApiKeyService.apiKeyHasValidScopesForRole(req.user, scopes)) {
|
|
throw new BadRequestError('Invalid scopes for user role');
|
|
}
|
|
|
|
await this.publicApiKeyService.updateApiKeyForUser(req.user, apiKeyId, {
|
|
...body,
|
|
scopes,
|
|
});
|
|
|
|
return { success: true };
|
|
}
|
|
|
|
@GlobalScope('apiKey:manage')
|
|
@Get('/scopes', { middlewares: [isApiEnabledMiddleware] })
|
|
async getApiKeyScopes(req: AuthenticatedRequest, _res: Response) {
|
|
const scopes = getApiKeyScopesForRole(req.user);
|
|
return scopes;
|
|
}
|
|
|
|
/**
|
|
* Resolves the scopes to be used for an API key based on license status.
|
|
* If the API Key Scopes feature is not licensed, returns all available scopes for the user's role.
|
|
* Otherwise, returns the requested scopes.
|
|
*/
|
|
private resolveScopesForUser(user: AuthenticatedRequest['user'], requestedScopes: ApiKeyScope[]) {
|
|
return this.license.isLicensed(LICENSE_FEATURES.API_KEY_SCOPES)
|
|
? requestedScopes
|
|
: getApiKeyScopesForRole(user);
|
|
}
|
|
}
|