mirror of
https://github.com/Unleash/unleash.git
synced 2025-03-04 00:18:40 +01:00
Create endpoint that validates tokens for edge (#2039)
* Create new endpoint * Change edge url * Fix snapshot
This commit is contained in:
parent
0db2c08382
commit
ad546a054f
@ -111,6 +111,8 @@ import { proxyFeatureSchema } from './spec/proxy-feature-schema';
|
||||
import { proxyClientSchema } from './spec/proxy-client-schema';
|
||||
import { proxyMetricsSchema } from './spec/proxy-metrics-schema';
|
||||
import { setUiConfigSchema } from './spec/set-ui-config-schema';
|
||||
import { edgeTokenSchema } from './spec/edge-token-schema';
|
||||
import { validateEdgeTokensSchema } from './spec/validate-edge-tokens-schema';
|
||||
|
||||
// All schemas in `openapi/spec` should be listed here.
|
||||
export const schemas = {
|
||||
@ -221,6 +223,8 @@ export const schemas = {
|
||||
proxyFeaturesSchema,
|
||||
proxyFeatureSchema,
|
||||
proxyMetricsSchema,
|
||||
edgeTokenSchema,
|
||||
validateEdgeTokensSchema,
|
||||
};
|
||||
|
||||
// Schemas must have an $id property on the form "#/components/schemas/mySchema".
|
||||
|
27
src/lib/openapi/spec/edge-token-schema.ts
Normal file
27
src/lib/openapi/spec/edge-token-schema.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { FromSchema } from 'json-schema-to-ts';
|
||||
import { ApiTokenType } from '../../types/models/api-token';
|
||||
|
||||
export const edgeTokenSchema = {
|
||||
$id: '#/components/schemas/edgeTokenSchema',
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
required: ['token', 'projects', 'type'],
|
||||
properties: {
|
||||
projects: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
enum: Object.values(ApiTokenType),
|
||||
},
|
||||
token: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
components: {},
|
||||
} as const;
|
||||
|
||||
export type EdgeTokenSchema = FromSchema<typeof edgeTokenSchema>;
|
27
src/lib/openapi/spec/validate-edge-tokens-schema.ts
Normal file
27
src/lib/openapi/spec/validate-edge-tokens-schema.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { FromSchema } from 'json-schema-to-ts';
|
||||
import { edgeTokenSchema } from './edge-token-schema';
|
||||
|
||||
export const validateEdgeTokensSchema = {
|
||||
$id: '#/components/schemas/validateEdgeTokensSchema',
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
required: ['tokens'],
|
||||
properties: {
|
||||
tokens: {
|
||||
type: 'array',
|
||||
anyOf: [
|
||||
{ items: { $ref: '#/components/schemas/edgeTokenSchema' } },
|
||||
{ items: { type: 'string' } },
|
||||
],
|
||||
},
|
||||
},
|
||||
components: {
|
||||
schemas: {
|
||||
edgeTokenSchema,
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export type ValidateEdgeTokensSchema = FromSchema<
|
||||
typeof validateEdgeTokensSchema
|
||||
>;
|
@ -77,6 +77,7 @@ const OPENAPI_TAGS = [
|
||||
description:
|
||||
'Experimental endpoints that may change or disappear at any time.',
|
||||
},
|
||||
{ name: 'Edge', description: 'Endpoints related to Unleash on the Edge.' },
|
||||
] as const;
|
||||
|
||||
// make the export mutable, so it can be used in a schema
|
||||
|
69
src/lib/routes/edge-api/index.ts
Normal file
69
src/lib/routes/edge-api/index.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { Response } from 'express';
|
||||
import Controller from '../controller';
|
||||
import { IUnleashConfig, IUnleashServices } from '../../types';
|
||||
import { Logger } from '../../logger';
|
||||
import { NONE } from '../../types/permissions';
|
||||
import { createResponseSchema } from '../../openapi/util/create-response-schema';
|
||||
import { RequestBody } from '../unleash-types';
|
||||
import { createRequestSchema } from '../../openapi/util/create-request-schema';
|
||||
import {
|
||||
validateEdgeTokensSchema,
|
||||
ValidateEdgeTokensSchema,
|
||||
} from '../../openapi/spec/validate-edge-tokens-schema';
|
||||
import EdgeService from '../../services/edge-service';
|
||||
import { OpenApiService } from '../../services/openapi-service';
|
||||
|
||||
export default class EdgeController extends Controller {
|
||||
private readonly logger: Logger;
|
||||
|
||||
private edgeService: EdgeService;
|
||||
|
||||
private openApiService: OpenApiService;
|
||||
|
||||
constructor(
|
||||
config: IUnleashConfig,
|
||||
{
|
||||
edgeService,
|
||||
openApiService,
|
||||
}: Pick<IUnleashServices, 'edgeService' | 'openApiService'>,
|
||||
) {
|
||||
super(config);
|
||||
this.logger = config.getLogger('edge-api/index.ts');
|
||||
this.edgeService = edgeService;
|
||||
this.openApiService = openApiService;
|
||||
|
||||
this.route({
|
||||
method: 'post',
|
||||
path: '/validate',
|
||||
handler: this.getValidTokens,
|
||||
permission: NONE,
|
||||
middleware: [
|
||||
this.openApiService.validPath({
|
||||
tags: ['Edge'],
|
||||
operationId: 'getValidTokens',
|
||||
requestBody: createRequestSchema(
|
||||
'validateEdgeTokensSchema',
|
||||
),
|
||||
responses: {
|
||||
200: createResponseSchema('validateEdgeTokensSchema'),
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
async getValidTokens(
|
||||
req: RequestBody<ValidateEdgeTokensSchema>,
|
||||
res: Response<ValidateEdgeTokensSchema>,
|
||||
): Promise<void> {
|
||||
const tokens = await this.edgeService.getValidTokens(
|
||||
req.body.tokens as string[],
|
||||
);
|
||||
this.openApiService.respondWithValidation<ValidateEdgeTokensSchema>(
|
||||
200,
|
||||
res,
|
||||
validateEdgeTokensSchema.$id,
|
||||
tokens,
|
||||
);
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ const Controller = require('./controller');
|
||||
import { HealthCheckController } from './health-check';
|
||||
import ProxyController from './proxy-api';
|
||||
import { conditionalMiddleware } from '../middleware/conditional-middleware';
|
||||
import EdgeController from './edge-api';
|
||||
|
||||
class IndexRouter extends Controller {
|
||||
constructor(config: IUnleashConfig, services: IUnleashServices) {
|
||||
@ -37,6 +38,8 @@ class IndexRouter extends Controller {
|
||||
new ProxyController(config, services).router,
|
||||
),
|
||||
);
|
||||
|
||||
this.use('/edge', new EdgeController(config, services).router);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,3 +11,7 @@ export interface IAuthRequest<
|
||||
logout: () => void;
|
||||
session: any;
|
||||
}
|
||||
|
||||
export interface RequestBody<T> extends Express.Request {
|
||||
body: T;
|
||||
}
|
||||
|
40
src/lib/services/edge-service.ts
Normal file
40
src/lib/services/edge-service.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { IUnleashStores, IUnleashConfig } from '../types';
|
||||
import { Logger } from '../logger';
|
||||
import { IApiTokenStore } from '../types/stores/api-token-store';
|
||||
import { EdgeTokenSchema } from '../openapi/spec/edge-token-schema';
|
||||
import { constantTimeCompare } from '../util/constantTimeCompare';
|
||||
import { ValidateEdgeTokensSchema } from '../openapi/spec/validate-edge-tokens-schema';
|
||||
|
||||
export default class EdgeService {
|
||||
private logger: Logger;
|
||||
|
||||
private apiTokenStore: IApiTokenStore;
|
||||
|
||||
constructor(
|
||||
{ apiTokenStore }: Pick<IUnleashStores, 'apiTokenStore'>,
|
||||
{ getLogger }: Pick<IUnleashConfig, 'getLogger'>,
|
||||
) {
|
||||
this.logger = getLogger('lib/services/edge-service.ts');
|
||||
this.apiTokenStore = apiTokenStore;
|
||||
}
|
||||
|
||||
async getValidTokens(tokens: string[]): Promise<ValidateEdgeTokensSchema> {
|
||||
const activeTokens = await this.apiTokenStore.getAllActive();
|
||||
const edgeTokens = tokens.reduce((result: EdgeTokenSchema[], token) => {
|
||||
const dbToken = activeTokens.find((activeToken) =>
|
||||
constantTimeCompare(activeToken.secret, token),
|
||||
);
|
||||
if (dbToken) {
|
||||
result.push({
|
||||
token: token,
|
||||
type: dbToken.type,
|
||||
projects: dbToken.projects,
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}, []);
|
||||
return { tokens: edgeTokens };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = EdgeService;
|
@ -34,6 +34,7 @@ import { ClientSpecService } from './client-spec-service';
|
||||
import { PlaygroundService } from './playground-service';
|
||||
import { GroupService } from './group-service';
|
||||
import { ProxyService } from './proxy-service';
|
||||
import EdgeService from './edge-service';
|
||||
export const createServices = (
|
||||
stores: IUnleashStores,
|
||||
config: IUnleashConfig,
|
||||
@ -98,6 +99,8 @@ export const createServices = (
|
||||
segmentService,
|
||||
});
|
||||
|
||||
const edgeService = new EdgeService(stores, config);
|
||||
|
||||
return {
|
||||
accessService,
|
||||
addonService,
|
||||
@ -132,6 +135,7 @@ export const createServices = (
|
||||
playgroundService,
|
||||
groupService,
|
||||
proxyService,
|
||||
edgeService,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -30,6 +30,7 @@ import { ClientSpecService } from '../services/client-spec-service';
|
||||
import { PlaygroundService } from 'lib/services/playground-service';
|
||||
import { GroupService } from '../services/group-service';
|
||||
import { ProxyService } from '../services/proxy-service';
|
||||
import EdgeService from '../services/edge-service';
|
||||
|
||||
export interface IUnleashServices {
|
||||
accessService: AccessService;
|
||||
@ -65,4 +66,5 @@ export interface IUnleashServices {
|
||||
clientSpecService: ClientSpecService;
|
||||
playgroundService: PlaygroundService;
|
||||
proxyService: ProxyService;
|
||||
edgeService: EdgeService;
|
||||
}
|
||||
|
@ -758,6 +758,34 @@ Object {
|
||||
},
|
||||
],
|
||||
},
|
||||
"edgeTokenSchema": Object {
|
||||
"additionalProperties": false,
|
||||
"properties": Object {
|
||||
"projects": Object {
|
||||
"items": Object {
|
||||
"type": "string",
|
||||
},
|
||||
"type": "array",
|
||||
},
|
||||
"token": Object {
|
||||
"type": "string",
|
||||
},
|
||||
"type": Object {
|
||||
"enum": Array [
|
||||
"client",
|
||||
"admin",
|
||||
"frontend",
|
||||
],
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
"required": Array [
|
||||
"token",
|
||||
"projects",
|
||||
"type",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
"emailSchema": Object {
|
||||
"additionalProperties": false,
|
||||
"properties": Object {
|
||||
@ -3133,6 +3161,30 @@ Object {
|
||||
},
|
||||
"type": "array",
|
||||
},
|
||||
"validateEdgeTokensSchema": Object {
|
||||
"additionalProperties": false,
|
||||
"properties": Object {
|
||||
"tokens": Object {
|
||||
"anyOf": Array [
|
||||
Object {
|
||||
"items": Object {
|
||||
"$ref": "#/components/schemas/edgeTokenSchema",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"items": Object {
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
],
|
||||
"type": "array",
|
||||
},
|
||||
},
|
||||
"required": Array [
|
||||
"tokens",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
"validatePasswordSchema": Object {
|
||||
"additionalProperties": false,
|
||||
"properties": Object {
|
||||
@ -6837,6 +6889,37 @@ If the provided project does not exist, the list of events will be empty.",
|
||||
],
|
||||
},
|
||||
},
|
||||
"/edge/validate": Object {
|
||||
"post": Object {
|
||||
"operationId": "getValidTokens",
|
||||
"requestBody": Object {
|
||||
"content": Object {
|
||||
"application/json": Object {
|
||||
"schema": Object {
|
||||
"$ref": "#/components/schemas/validateEdgeTokensSchema",
|
||||
},
|
||||
},
|
||||
},
|
||||
"description": "validateEdgeTokensSchema",
|
||||
"required": true,
|
||||
},
|
||||
"responses": Object {
|
||||
"200": Object {
|
||||
"content": Object {
|
||||
"application/json": Object {
|
||||
"schema": Object {
|
||||
"$ref": "#/components/schemas/validateEdgeTokensSchema",
|
||||
},
|
||||
},
|
||||
},
|
||||
"description": "validateEdgeTokensSchema",
|
||||
},
|
||||
},
|
||||
"tags": Array [
|
||||
"Edge",
|
||||
],
|
||||
},
|
||||
},
|
||||
"/health": Object {
|
||||
"get": Object {
|
||||
"operationId": "getHealth",
|
||||
@ -6907,6 +6990,10 @@ If the provided project does not exist, the list of events will be empty.",
|
||||
"description": "Create, update, and delete [context fields](https://docs.getunleash.io/user_guide/unleash_context) that Unleash is aware of.",
|
||||
"name": "Context",
|
||||
},
|
||||
Object {
|
||||
"description": "Endpoints related to Unleash on the Edge.",
|
||||
"name": "Edge",
|
||||
},
|
||||
Object {
|
||||
"description": "Create, update, delete, enable or disable [environments](https://docs.getunleash.io/user_guide/environments) for this Unleash instance.",
|
||||
"name": "Environments",
|
||||
|
Loading…
Reference in New Issue
Block a user