@gravity-ui/gateway 4.7.2 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -1
- package/build/components/grpc.d.ts +2 -2
- package/build/components/grpc.js +5 -4
- package/build/components/rest.d.ts +2 -2
- package/build/components/rest.js +7 -7
- package/build/index.js +7 -4
- package/build/models/common.d.ts +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -455,17 +455,41 @@ const config = {
|
|
|
455
455
|
};
|
|
456
456
|
```
|
|
457
457
|
|
|
458
|
-
You can
|
|
458
|
+
You can define authentication at three levels:
|
|
459
|
+
|
|
|
460
|
+
|
|
461
|
+
1. **Gateway level** (global) - as shown above
|
|
462
|
+
2. **Service level** - by adding authentication methods to the service definition
|
|
463
|
+
3. **Action level** (most specific) - by adding authentication methods to individual actions
|
|
464
|
+
|
|
|
465
|
+
The authentication methods are checked in the following order: action > service > gateway.
|
|
466
|
+
|
|
|
467
|
+
**Service-level authentication:**
|
|
468
|
+
|
|
|
459
469
|
|
|
460
470
|
```javascript
|
|
461
471
|
const schema = {
|
|
462
472
|
userService: {
|
|
463
473
|
serviceName: 'users',
|
|
464
474
|
endpoints: {...},
|
|
475
|
+
// Service-level authentication
|
|
476
|
+
getAuthHeaders: (params) => ({
|
|
477
|
+
'X-User-Service-Auth': params.token,
|
|
478
|
+
}),
|
|
479
|
+
getAuthArgs: (req, res) => ({
|
|
480
|
+
token: req.authorization.token,
|
|
481
|
+
serviceSpecificData: req.headers['x-service-data'],
|
|
482
|
+
}),
|
|
465
483
|
actions: {
|
|
466
484
|
getProfile: {
|
|
467
485
|
path: () => '/profile',
|
|
468
486
|
method: 'GET',
|
|
487
|
+
// Uses service-level authentication
|
|
488
|
+
},
|
|
489
|
+
updateProfile: {
|
|
490
|
+
path: () => '/profile',
|
|
491
|
+
method: 'PUT',
|
|
492
|
+
// Action-level authentication (overrides service-level)
|
|
469
493
|
getAuthHeaders: (params) => ({
|
|
470
494
|
'X-Special-Auth': params.token,
|
|
471
495
|
}),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as grpc from '@grpc/grpc-js';
|
|
2
2
|
import * as protobufjs from 'protobufjs';
|
|
3
3
|
import type * as descriptor from 'protobufjs/ext/descriptor';
|
|
4
|
-
import { ApiActionConfig, ApiServiceGrpcActionConfig, EndpointsConfig, GatewayApiOptions } from '../models/common';
|
|
4
|
+
import { ApiActionConfig, ApiServiceGrpcActionConfig, BaseSchema, EndpointsConfig, GatewayApiOptions } from '../models/common';
|
|
5
5
|
import { GatewayContext } from '../models/context';
|
|
6
6
|
import { AppErrorConstructor } from '../models/error';
|
|
7
7
|
declare module 'protobufjs' {
|
|
@@ -20,5 +20,5 @@ export interface GrpcContext {
|
|
|
20
20
|
}
|
|
21
21
|
export declare function createRoot(includeGrpcPaths?: string[]): protobufjs.Root;
|
|
22
22
|
export declare function getCredentialsMap(caCertificatePath?: string | null): CredentialsMap;
|
|
23
|
-
export default function createGrpcAction<Context extends GatewayContext>({ root, credentials }: GrpcContext, endpoints: EndpointsConfig | undefined, config: ApiServiceGrpcActionConfig<Context, any, any>, serviceKey: string, actionName: string, options: GatewayApiOptions<Context>, ErrorConstructor: AppErrorConstructor): (actionConfig: ApiActionConfig<Context, any, any>) => Promise<import("../models/common").GatewayActionClientStreamResponse<any> | import("../models/common").GatewayActionServerStreamResponse<any> | import("../models/common").GatewayActionDuplexStreamResponse<any> | import("../models/common").GatewayActionUnaryResponse<any>>;
|
|
23
|
+
export default function createGrpcAction<Context extends GatewayContext>({ root, credentials }: GrpcContext, endpoints: EndpointsConfig | undefined, config: ApiServiceGrpcActionConfig<Context, any, any>, serviceKey: string, actionName: string, options: GatewayApiOptions<Context>, ErrorConstructor: AppErrorConstructor, serviceSchema?: Pick<BaseSchema[string], 'getAuthHeaders'>): (actionConfig: ApiActionConfig<Context, any, any>) => Promise<import("../models/common").GatewayActionClientStreamResponse<any> | import("../models/common").GatewayActionServerStreamResponse<any> | import("../models/common").GatewayActionDuplexStreamResponse<any> | import("../models/common").GatewayActionUnaryResponse<any>>;
|
|
24
24
|
export {};
|
package/build/components/grpc.js
CHANGED
|
@@ -86,8 +86,8 @@ function decodeResponse(response, packageRoot, ctx, encodedFields = [], ErrorCon
|
|
|
86
86
|
}
|
|
87
87
|
});
|
|
88
88
|
}
|
|
89
|
-
function createMetadata({ options, actionConfig, config, params, serviceName, proxyHeadersCaller, ctx, }) {
|
|
90
|
-
var _a;
|
|
89
|
+
function createMetadata({ options, actionConfig, config, params, serviceName, proxyHeadersCaller, ctx, serviceSchema, }) {
|
|
90
|
+
var _a, _b;
|
|
91
91
|
const { headers, requestId, authArgs } = actionConfig;
|
|
92
92
|
const proxyHeaders = [...constants_1.DEFAULT_PROXY_HEADERS];
|
|
93
93
|
let metadata = {
|
|
@@ -111,7 +111,7 @@ function createMetadata({ options, actionConfig, config, params, serviceName, pr
|
|
|
111
111
|
metadata[headerName] = headers[headerName];
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
|
-
const authHeaders = ((_a = config.getAuthHeaders) !== null && _a !== void 0 ? _a : options.getAuthHeaders)({
|
|
114
|
+
const authHeaders = ((_b = (_a = config.getAuthHeaders) !== null && _a !== void 0 ? _a : serviceSchema === null || serviceSchema === void 0 ? void 0 : serviceSchema.getAuthHeaders) !== null && _b !== void 0 ? _b : options.getAuthHeaders)({
|
|
115
115
|
actionType: 'grpc',
|
|
116
116
|
serviceName,
|
|
117
117
|
requestHeaders: headers,
|
|
@@ -333,7 +333,7 @@ function createServiceOptions(timeout) {
|
|
|
333
333
|
deadline: Date.now() + timeout,
|
|
334
334
|
};
|
|
335
335
|
}
|
|
336
|
-
function createGrpcAction({ root, credentials }, endpoints, config, serviceKey, actionName, options, ErrorConstructor) {
|
|
336
|
+
function createGrpcAction({ root, credentials }, endpoints, config, serviceKey, actionName, options, ErrorConstructor, serviceSchema) {
|
|
337
337
|
const serviceName = (options === null || options === void 0 ? void 0 : options.serviceName) || serviceKey;
|
|
338
338
|
let getService;
|
|
339
339
|
let recreateService;
|
|
@@ -520,6 +520,7 @@ function createGrpcAction({ root, credentials }, endpoints, config, serviceKey,
|
|
|
520
520
|
serviceName,
|
|
521
521
|
proxyHeadersCaller,
|
|
522
522
|
ctx,
|
|
523
|
+
serviceSchema,
|
|
523
524
|
});
|
|
524
525
|
if (!service[action]) {
|
|
525
526
|
reject(new parse_error_1.GrpcError('Not found action', {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ApiActionConfig, ApiServiceRestActionConfig, EndpointsConfig, GatewayApiOptions, Headers } from '../models/common';
|
|
1
|
+
import { ApiActionConfig, ApiServiceRestActionConfig, BaseSchema, EndpointsConfig, GatewayApiOptions, Headers } from '../models/common';
|
|
2
2
|
import { GatewayContext } from '../models/context';
|
|
3
3
|
import { AppErrorConstructor } from '../models/error';
|
|
4
|
-
export default function createRestAction<Context extends GatewayContext>(endpoints: EndpointsConfig | undefined, config: ApiServiceRestActionConfig<Context, any, any>, serviceKey: string, actionName: string, options: GatewayApiOptions<Context>, ErrorConstructor: AppErrorConstructor): (actionConfig: ApiActionConfig<Context, any>) => Promise<{
|
|
4
|
+
export default function createRestAction<Context extends GatewayContext>(endpoints: EndpointsConfig | undefined, config: ApiServiceRestActionConfig<Context, any, any>, serviceKey: string, actionName: string, options: GatewayApiOptions<Context>, ErrorConstructor: AppErrorConstructor, serviceSchema?: Pick<BaseSchema[string], 'getAuthHeaders'>): (actionConfig: ApiActionConfig<Context, any>) => Promise<{
|
|
5
5
|
responseData: unknown;
|
|
6
6
|
responseHeaders?: Headers | undefined;
|
|
7
7
|
debugHeaders: Headers;
|
package/build/components/rest.js
CHANGED
|
@@ -33,13 +33,13 @@ function getConfigSerializerFunction(config) {
|
|
|
33
33
|
}
|
|
34
34
|
return undefined;
|
|
35
35
|
}
|
|
36
|
-
function createRestAction(endpoints, config, serviceKey, actionName, options, ErrorConstructor) {
|
|
36
|
+
function createRestAction(endpoints, config, serviceKey, actionName, options, ErrorConstructor, serviceSchema) {
|
|
37
37
|
var _a, _b, _c, _d;
|
|
38
38
|
const timeout = (_c = (_a = config === null || config === void 0 ? void 0 : config.timeout) !== null && _a !== void 0 ? _a : (_b = options === null || options === void 0 ? void 0 : options.axiosConfig) === null || _b === void 0 ? void 0 : _b.timeout) !== null && _c !== void 0 ? _c : options === null || options === void 0 ? void 0 : options.timeout;
|
|
39
39
|
const defaultAxiosClient = (0, axios_1.getAxiosClient)(timeout, config === null || config === void 0 ? void 0 : config.retries, (_d = config === null || config === void 0 ? void 0 : config.axiosRetryCondition) !== null && _d !== void 0 ? _d : options === null || options === void 0 ? void 0 : options.axiosRetryCondition, options === null || options === void 0 ? void 0 : options.axiosConfig, options === null || options === void 0 ? void 0 : options.axiosInterceptors);
|
|
40
40
|
/* eslint-disable complexity */
|
|
41
41
|
return async function action(actionConfig) {
|
|
42
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
42
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
43
43
|
const { args, requestId, headers: requestHeaders, ctx: parentCtx, authArgs, userId, abortSignal, } = actionConfig;
|
|
44
44
|
const debugHeaders = {};
|
|
45
45
|
const lang = requestHeaders[constants_1.DEFAULT_LANG_HEADER] || constants_1.Lang.Ru; // header might be empty string
|
|
@@ -142,7 +142,7 @@ function createRestAction(endpoints, config, serviceKey, actionName, options, Er
|
|
|
142
142
|
if (idempotency) {
|
|
143
143
|
actionHeaders['idempotency-key'] = requestHeaders['idempotency-key'] || (0, uuid_1.v4)();
|
|
144
144
|
}
|
|
145
|
-
const authHeaders = ((_b = config.getAuthHeaders) !== null && _b !== void 0 ? _b : options.getAuthHeaders)({
|
|
145
|
+
const authHeaders = ((_c = (_b = config.getAuthHeaders) !== null && _b !== void 0 ? _b : serviceSchema === null || serviceSchema === void 0 ? void 0 : serviceSchema.getAuthHeaders) !== null && _c !== void 0 ? _c : options.getAuthHeaders)({
|
|
146
146
|
actionType: 'rest',
|
|
147
147
|
serviceName,
|
|
148
148
|
requestHeaders,
|
|
@@ -202,7 +202,7 @@ function createRestAction(endpoints, config, serviceKey, actionName, options, Er
|
|
|
202
202
|
}
|
|
203
203
|
const startRequestTime = Date.now();
|
|
204
204
|
let axiosClient = defaultAxiosClient;
|
|
205
|
-
const customActionTimeout = (
|
|
205
|
+
const customActionTimeout = (_f = (_e = (_d = actionConfig.timeout) !== null && _d !== void 0 ? _d : config.timeout) !== null && _e !== void 0 ? _e : endpointAxiosConfig === null || endpointAxiosConfig === void 0 ? void 0 : endpointAxiosConfig.timeout) !== null && _f !== void 0 ? _f : timeout;
|
|
206
206
|
if (actionConfig.timeout || endpointAxiosConfig) {
|
|
207
207
|
const customActionAxiosConfig = Object.assign(Object.assign({}, ((options === null || options === void 0 ? void 0 : options.axiosConfig) || {})), (endpointAxiosConfig || {}));
|
|
208
208
|
axiosClient = (0, axios_1.getAxiosClient)(customActionTimeout, config === null || config === void 0 ? void 0 : config.retries, options.axiosRetryCondition, customActionAxiosConfig, options === null || options === void 0 ? void 0 : options.axiosInterceptors);
|
|
@@ -216,7 +216,7 @@ function createRestAction(endpoints, config, serviceKey, actionName, options, Er
|
|
|
216
216
|
requestId,
|
|
217
217
|
requestMethod: config.method,
|
|
218
218
|
requestUrl: actionURL,
|
|
219
|
-
traceId: ((
|
|
219
|
+
traceId: ((_g = ctx.getTraceId) === null || _g === void 0 ? void 0 : _g.call(ctx)) || '',
|
|
220
220
|
userId: userId || '',
|
|
221
221
|
};
|
|
222
222
|
const requestConfig = {
|
|
@@ -243,7 +243,7 @@ function createRestAction(endpoints, config, serviceKey, actionName, options, Er
|
|
|
243
243
|
const responseHeaders = {};
|
|
244
244
|
const endRequestTime = Date.now();
|
|
245
245
|
requestData.requestTime = endRequestTime - startRequestTime;
|
|
246
|
-
const actualResponseContentType = (
|
|
246
|
+
const actualResponseContentType = (_h = response.headers) === null || _h === void 0 ? void 0 : _h['Content-Type'];
|
|
247
247
|
const expectedResponseContentType = config.expectedResponseContentType || options.expectedResponseContentType;
|
|
248
248
|
if (actualResponseContentType && expectedResponseContentType) {
|
|
249
249
|
let isInvalidResponseContentType;
|
|
@@ -340,7 +340,7 @@ function createRestAction(endpoints, config, serviceKey, actionName, options, Er
|
|
|
340
340
|
}
|
|
341
341
|
const responseStatus = lodash_1.default.get(parsedError, 'status') || lodash_1.default.get(error, 'status', 500);
|
|
342
342
|
if (options === null || options === void 0 ? void 0 : options.sendStats) {
|
|
343
|
-
options.sendStats(Object.assign(Object.assign({}, requestData), { responseSize: getRestResponseSize((
|
|
343
|
+
options.sendStats(Object.assign(Object.assign({}, requestData), { responseSize: getRestResponseSize((_j = error === null || error === void 0 ? void 0 : error.response) === null || _j === void 0 ? void 0 : _j.data, ctx, ErrorConstructor), restStatus: responseStatus, userId }), (0, redact_sensitive_headers_1.redactSensitiveHeaders)(parentCtx, headers), parentCtx, { debugHeaders: (0, common_1.sanitizeDebugHeaders)(debugHeaders) });
|
|
344
344
|
}
|
|
345
345
|
else {
|
|
346
346
|
ctx.stats(Object.assign(Object.assign({}, requestData), { responseStatus }));
|
package/build/index.js
CHANGED
|
@@ -85,7 +85,7 @@ function createApiAction(schema, config, serviceKey, actionName, api, grpcContex
|
|
|
85
85
|
validationSchema: config.validationSchema,
|
|
86
86
|
encodePathArgs: config.encodePathArgs,
|
|
87
87
|
getAuthHeaders: config.getAuthHeaders,
|
|
88
|
-
}, config.ErrorConstructor);
|
|
88
|
+
}, config.ErrorConstructor, serviceSchema);
|
|
89
89
|
}
|
|
90
90
|
const grpcRecreateService = (_a = config.grpcRecreateService) !== null && _a !== void 0 ? _a : true;
|
|
91
91
|
return (0, grpc_1.default)(grpcContext, endpointsConfig, action, serviceKey, actionName, {
|
|
@@ -98,7 +98,7 @@ function createApiAction(schema, config, serviceKey, actionName, api, grpcContex
|
|
|
98
98
|
grpcOptions: config.grpcOptions,
|
|
99
99
|
grpcRecreateService,
|
|
100
100
|
getAuthHeaders: config.getAuthHeaders,
|
|
101
|
-
}, config.ErrorConstructor);
|
|
101
|
+
}, config.ErrorConstructor, serviceSchema);
|
|
102
102
|
}
|
|
103
103
|
function generateGatewayApi(schema, config, grpcContext, baseApi) {
|
|
104
104
|
const { installation, env } = config;
|
|
@@ -117,7 +117,7 @@ function generateGatewayApi(schema, config, grpcContext, baseApi) {
|
|
|
117
117
|
function generateGatewayApiController(schemasByScope, Api, config, controllerActions) {
|
|
118
118
|
// eslint-disable-next-line complexity
|
|
119
119
|
return async function gateway(req, res) {
|
|
120
|
-
var _a, _b, _c;
|
|
120
|
+
var _a, _b, _c, _d;
|
|
121
121
|
const { userId } = res.locals || {};
|
|
122
122
|
const { service, action, scope = 'root' } = req.params;
|
|
123
123
|
const withDebugHeaders = typeof config.withDebugHeaders === 'function'
|
|
@@ -192,12 +192,15 @@ function generateGatewayApiController(schemasByScope, Api, config, controllerAct
|
|
|
192
192
|
throw { error, debugHeaders: {} };
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
|
+
const serviceSchema = (_d = schemasByScope[scope]) === null || _d === void 0 ? void 0 : _d[service];
|
|
195
196
|
const { responseData, responseHeaders, debugHeaders } = await apiAction({
|
|
196
197
|
requestId: req.id,
|
|
197
198
|
headers: req.headers,
|
|
198
199
|
ctx: req.ctx,
|
|
199
200
|
args,
|
|
200
|
-
authArgs:
|
|
201
|
+
authArgs: (serviceSchema === null || serviceSchema === void 0 ? void 0 : serviceSchema.getAuthArgs)
|
|
202
|
+
? serviceSchema.getAuthArgs(req, res)
|
|
203
|
+
: config.getAuthArgs(req, res),
|
|
201
204
|
userId,
|
|
202
205
|
abortSignal: abortController.signal,
|
|
203
206
|
});
|
package/build/models/common.d.ts
CHANGED
|
@@ -199,6 +199,8 @@ export interface BaseSchema {
|
|
|
199
199
|
actions: Record<string, ApiServiceActionConfig<any, any, any, any, any, any>>;
|
|
200
200
|
serviceName?: string;
|
|
201
201
|
endpoints?: Record<string, Record<string, EndpointsConfig>>;
|
|
202
|
+
getAuthHeaders?: GetAuthHeaders;
|
|
203
|
+
getAuthArgs?: (req: Request, res: Response) => Record<string, unknown> | undefined;
|
|
202
204
|
};
|
|
203
205
|
}
|
|
204
206
|
export interface SchemasByScope {
|