@forklaunch/core 0.1.1 → 0.1.2
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/.prettierignore +2 -0
- package/.prettierrc +6 -0
- package/dist/cache/index.d.ts +3 -0
- package/dist/cache/index.js +20 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/interfaces/ttlCache.interface.d.ts +1 -1
- package/dist/cache/redisTtlCache.d.ts +3 -2
- package/dist/cache/redisTtlCache.js +2 -2
- package/dist/cache/redisTtlCache.js.map +1 -1
- package/dist/cache/types/{ttlCacheRecord.js → ttlCacheRecord.types.js} +1 -1
- package/dist/cache/types/ttlCacheRecord.types.js.map +1 -0
- package/dist/controllers/index.d.ts +1 -0
- package/dist/controllers/index.js +18 -0
- package/dist/controllers/index.js.map +1 -0
- package/dist/database/index.d.ts +1 -0
- package/dist/database/index.js +18 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/mikro/models/entities/base.entity.js +1 -1
- package/dist/entityMapper/index.d.ts +2 -0
- package/dist/entityMapper/index.js +19 -0
- package/dist/entityMapper/index.js.map +1 -0
- package/dist/entityMapper/interfaces/entityMapper.interface.d.ts +3 -3
- package/dist/entityMapper/models/baseEntityMapper.model.d.ts +23 -23
- package/dist/entityMapper/models/baseEntityMapper.model.js +15 -15
- package/dist/entityMapper/models/baseEntityMapper.model.js.map +1 -1
- package/dist/entityMapper/models/requestEntityMapper.model.d.ts +17 -23
- package/dist/entityMapper/models/requestEntityMapper.model.js +13 -19
- package/dist/entityMapper/models/requestEntityMapper.model.js.map +1 -1
- package/dist/entityMapper/models/responseEntityMapper.model.d.ts +15 -16
- package/dist/entityMapper/models/responseEntityMapper.model.js +8 -8
- package/dist/entityMapper/models/responseEntityMapper.model.js.map +1 -1
- package/dist/entityMapper/types/entityMapper.types.d.ts +3 -22
- package/dist/http/index.d.ts +2 -0
- package/dist/http/index.js +19 -0
- package/dist/http/index.js.map +1 -0
- package/dist/http/middlewares/index.d.ts +2 -0
- package/dist/http/middlewares/index.js +19 -0
- package/dist/http/middlewares/index.js.map +1 -0
- package/dist/http/middlewares/request.middleware.d.ts +11 -11
- package/dist/http/middlewares/request.middleware.js +23 -21
- package/dist/http/middlewares/request.middleware.js.map +1 -1
- package/dist/http/middlewares/response.middleware.d.ts +3 -3
- package/dist/http/middlewares/response.middleware.js +7 -3
- package/dist/http/middlewares/response.middleware.js.map +1 -1
- package/dist/http/types/api.types.d.ts +16 -12
- package/dist/http/types/index.d.ts +2 -0
- package/dist/http/types/index.js +19 -0
- package/dist/http/types/index.js.map +1 -0
- package/dist/http/types/primitive.types.d.ts +14 -13
- package/dist/index.d.ts +6 -1
- package/dist/index.js +20 -5
- package/dist/index.js.map +1 -1
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +18 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/interfaces/baseService.d.ts +1 -1
- package/dist/tests/{dto.test.js → entityMapper.test.js} +10 -32
- package/dist/tests/entityMapper.test.js.map +1 -0
- package/dist/tests/http.middleware.test.d.ts +1 -0
- package/dist/tests/http.middleware.test.js +79 -0
- package/dist/tests/http.middleware.test.js.map +1 -0
- package/dist/tests/redisTtlCache.test.js +32 -15
- package/dist/tests/redisTtlCache.test.js.map +1 -1
- package/entityMapper/index.ts +2 -0
- package/entityMapper/interfaces/entityMapper.interface.ts +11 -11
- package/entityMapper/models/baseEntityMapper.model.ts +90 -73
- package/entityMapper/models/requestEntityMapper.model.ts +96 -75
- package/entityMapper/models/responseEntityMapper.model.ts +83 -62
- package/entityMapper/types/entityMapper.types.ts +6 -23
- package/http/index.ts +2 -0
- package/http/middlewares/index.ts +2 -0
- package/http/middlewares/request.middleware.ts +103 -55
- package/http/middlewares/response.middleware.ts +56 -31
- package/http/types/api.types.ts +43 -25
- package/http/types/index.ts +2 -0
- package/http/types/primitive.types.ts +65 -44
- package/index.ts +6 -5
- package/jest.config.ts +2 -2
- package/package.json +13 -4
- package/tests/entityMapper.test.ts +219 -0
- package/tests/http.middleware.test.ts +99 -0
- package/tests/redisTtlCache.test.ts +49 -29
- package/dist/cache/types/ttlCacheRecord.js.map +0 -1
- package/dist/tests/dto.test.js.map +0 -1
- package/tests/dto.test.ts +0 -235
- /package/dist/cache/types/{ttlCacheRecord.d.ts → ttlCacheRecord.types.d.ts} +0 -0
- /package/dist/tests/{dto.test.d.ts → entityMapper.test.d.ts} +0 -0
@@ -1,8 +1,7 @@
|
|
1
|
-
import {
|
2
|
-
import { BaseEntity } from
|
3
|
-
import { EntityMapperConstructor } from
|
4
|
-
import {
|
5
|
-
import { BaseEntityMapper, construct } from "./baseEntityMapper.model";
|
1
|
+
import { AnySchemaValidator } from '@forklaunch/validator';
|
2
|
+
import { BaseEntity } from '../../database/mikro/models/entities/base.entity';
|
3
|
+
import { EntityMapperConstructor } from '../interfaces/entityMapper.interface';
|
4
|
+
import { BaseEntityMapper, construct } from './baseEntityMapper.model';
|
6
5
|
|
7
6
|
/**
|
8
7
|
* Abstract class representing a response entityMapper.
|
@@ -11,67 +10,89 @@ import { BaseEntityMapper, construct } from "./baseEntityMapper.model";
|
|
11
10
|
* @template SV - A type that extends SchemaValidator.
|
12
11
|
* @extends {BaseEntityMapper<SV>}
|
13
12
|
*/
|
14
|
-
export abstract class ResponseEntityMapper<
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
13
|
+
export abstract class ResponseEntityMapper<
|
14
|
+
Entity extends BaseEntity,
|
15
|
+
SV extends AnySchemaValidator
|
16
|
+
> extends BaseEntityMapper<SV> {
|
17
|
+
/**
|
18
|
+
* The entity type.
|
19
|
+
* @type {Entity}
|
20
|
+
* @protected
|
21
|
+
*/
|
22
|
+
_Entity!: Entity;
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
24
|
+
/**
|
25
|
+
* Populates entityMapper with DTO from an entity.
|
26
|
+
*
|
27
|
+
* @abstract
|
28
|
+
* @param {Entity} entity - The entity to convert.
|
29
|
+
* @returns {this} - The instance of the ResponseEntityMapper.
|
30
|
+
*/
|
31
|
+
abstract fromEntity(entity: Entity, ...additionalArgs: unknown[]): this;
|
30
32
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
33
|
+
/**
|
34
|
+
* Converts the underlying DTO to a JSON object.
|
35
|
+
*
|
36
|
+
* @param {...unknown[]} additionalArgs - Additional arguments.
|
37
|
+
* @returns {this['_dto']} - The JSON object.
|
38
|
+
*/
|
39
|
+
toJson(): this['_dto'] {
|
40
|
+
if (
|
41
|
+
!this.schemaValidator.validate(
|
42
|
+
this.schemaValidator.schemify(this.schema),
|
43
|
+
this.dto
|
44
|
+
)
|
45
|
+
) {
|
46
|
+
throw new Error('Invalid DTO');
|
42
47
|
}
|
48
|
+
return this.dto;
|
49
|
+
}
|
43
50
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
51
|
+
/**
|
52
|
+
* Serializes an entity to a JSON object.
|
53
|
+
*
|
54
|
+
* @param {Entity} entity - The entity to serialize.
|
55
|
+
* @returns {this['_dto']} - The JSON object.
|
56
|
+
*/
|
57
|
+
serializeEntityToJson(entity: Entity): this['_dto'] {
|
58
|
+
return this.fromEntity(entity).toJson();
|
59
|
+
}
|
53
60
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
61
|
+
/**
|
62
|
+
* Populates entityMapper with DTO from an entity.
|
63
|
+
*
|
64
|
+
* @template T - A type that extends ResponseEntityMapper.
|
65
|
+
* @param {EntityMapperConstructor<T>} this - The constructor of the T.
|
66
|
+
* @param {T['_Entity']} entity - The entity to convert.
|
67
|
+
* @returns {T} - An instance of the T.
|
68
|
+
*/
|
69
|
+
static fromEntity<
|
70
|
+
T extends ResponseEntityMapper<BaseEntity, SV>,
|
71
|
+
SV extends AnySchemaValidator
|
72
|
+
>(
|
73
|
+
this: EntityMapperConstructor<T, SV>,
|
74
|
+
schemaValidator: SV,
|
75
|
+
entity: T['_Entity']
|
76
|
+
): T {
|
77
|
+
return construct(this, schemaValidator).fromEntity(entity);
|
78
|
+
}
|
65
79
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
80
|
+
/**
|
81
|
+
* Serializes an entity to a JSON object.
|
82
|
+
*
|
83
|
+
* @template T - A type that extends ResponseEntityMapper.
|
84
|
+
* @param {EntityMapperConstructor<T>} this - The constructor of the T.
|
85
|
+
* @param {T['_Entity']} entity - The entity to serialize.
|
86
|
+
* @returns {T['_dto']} - The JSON object.
|
87
|
+
*/
|
88
|
+
static serializeEntityToJson<
|
89
|
+
T extends ResponseEntityMapper<BaseEntity, SV>,
|
90
|
+
SV extends AnySchemaValidator
|
91
|
+
>(
|
92
|
+
this: EntityMapperConstructor<T, SV>,
|
93
|
+
schemaValidator: SV,
|
94
|
+
entity: T['_Entity']
|
95
|
+
): T['_dto'] {
|
96
|
+
return construct(this, schemaValidator).serializeEntityToJson(entity);
|
97
|
+
}
|
77
98
|
}
|
@@ -1,29 +1,12 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
3
|
-
import { UnboxedObjectSchema } from "@forklaunch/validator/types";
|
4
|
-
import { BaseEntityMapper } from "../models/baseEntityMapper.model";
|
1
|
+
import { AnySchemaValidator } from '@forklaunch/validator';
|
2
|
+
import { UnboxedObjectSchema } from '@forklaunch/validator/types';
|
5
3
|
|
6
4
|
/**
|
7
5
|
* Type representing a schema validator object for an entity mapper.
|
8
|
-
*
|
6
|
+
*
|
9
7
|
* @template SV - A type that extends SchemaValidator.
|
10
8
|
* @typedef {ValidSchemaObject<SV> | UnboxedObjectSchema<SchemaCatchall<SV>> & {}} EntityMapperSchemaValidatorObject
|
11
9
|
*/
|
12
|
-
export type EntityMapperSchemaValidatorObject<SV extends
|
13
|
-
|
14
|
-
|
15
|
-
* Type representing the static schema of an entity mapper.
|
16
|
-
*
|
17
|
-
* @template T - A type that extends BaseEntityMapper with a schema property.
|
18
|
-
* @typedef {Schema<T['schema'], T['_SV']> & {}} EntityMapperStaticSchema
|
19
|
-
*/
|
20
|
-
export type EntityMapperStaticSchema<T extends BaseEntityMapper<any> & { schema: any }> = Schema<T['schema'], T['_SV']>;
|
21
|
-
|
22
|
-
/**
|
23
|
-
* Type representing the schema of an entity mapper.
|
24
|
-
*
|
25
|
-
* @template T - A type that extends ValidSchemaObject or UnboxedObjectSchema with SchemaCatchall.
|
26
|
-
* @template SV - A type that extends SchemaValidator.
|
27
|
-
* @typedef {Schema<T, SV> & {}} EntityMapperSchema
|
28
|
-
*/
|
29
|
-
export type EntityMapperSchema<T extends ValidSchemaObject<SV> | UnboxedObjectSchema<SchemaCatchall<SV>>, SV extends SchemaValidator> = Schema<T, SV>;
|
10
|
+
export type EntityMapperSchemaValidatorObject<SV extends AnySchemaValidator> =
|
11
|
+
| SV['_ValidSchemaObject']
|
12
|
+
| UnboxedObjectSchema<SV>;
|
package/http/index.ts
ADDED
@@ -1,17 +1,26 @@
|
|
1
|
-
import { SchemaValidator } from
|
2
|
-
import * as jose from
|
3
|
-
import { v4 } from
|
4
|
-
import {
|
5
|
-
|
1
|
+
import { AnySchemaValidator, SchemaValidator } from '@forklaunch/validator';
|
2
|
+
import * as jose from 'jose';
|
3
|
+
import { v4 } from 'uuid';
|
4
|
+
import {
|
5
|
+
ForklaunchNextFunction,
|
6
|
+
ForklaunchRequest,
|
7
|
+
ForklaunchResponse
|
8
|
+
} from '../types/api.types';
|
9
|
+
import {
|
10
|
+
AuthMethod,
|
11
|
+
HttpContractDetails,
|
12
|
+
PathParamHttpContractDetails,
|
13
|
+
StringOnlyObject
|
14
|
+
} from '../types/primitive.types';
|
6
15
|
|
7
16
|
export function createRequestContext<
|
8
|
-
SV extends
|
17
|
+
SV extends AnySchemaValidator,
|
9
18
|
Request extends ForklaunchRequest<SV>,
|
10
19
|
Response extends ForklaunchResponse,
|
11
20
|
NextFunction extends ForklaunchNextFunction
|
12
21
|
>(schemaValidator: SV) {
|
13
22
|
return (req: Request, res: Response, next?: NextFunction) => {
|
14
|
-
req.schemaValidator = schemaValidator;
|
23
|
+
req.schemaValidator = schemaValidator as SchemaValidator;
|
15
24
|
|
16
25
|
let correlationId = v4();
|
17
26
|
|
@@ -23,16 +32,16 @@ export function createRequestContext<
|
|
23
32
|
|
24
33
|
req.context = {
|
25
34
|
correlationId: correlationId
|
26
|
-
}
|
35
|
+
};
|
27
36
|
|
28
37
|
if (next) {
|
29
38
|
next();
|
30
39
|
}
|
31
|
-
}
|
40
|
+
};
|
32
41
|
}
|
33
42
|
|
34
43
|
export function enrichRequestDetails<
|
35
|
-
SV extends
|
44
|
+
SV extends AnySchemaValidator,
|
36
45
|
Request extends ForklaunchRequest<SV>,
|
37
46
|
Response extends ForklaunchResponse,
|
38
47
|
NextFunction extends ForklaunchNextFunction
|
@@ -43,10 +52,14 @@ export function enrichRequestDetails<
|
|
43
52
|
if (next) {
|
44
53
|
next();
|
45
54
|
}
|
46
|
-
}
|
55
|
+
};
|
47
56
|
}
|
48
57
|
|
49
|
-
export function preHandlerParse<SV extends
|
58
|
+
export function preHandlerParse<SV extends AnySchemaValidator>(
|
59
|
+
schemaValidator: SchemaValidator,
|
60
|
+
object: unknown,
|
61
|
+
schemaInput?: StringOnlyObject<SV>
|
62
|
+
) {
|
50
63
|
if (!schemaInput) {
|
51
64
|
return;
|
52
65
|
}
|
@@ -58,35 +71,42 @@ export function preHandlerParse<SV extends SchemaValidator>(schemaValidator: SV,
|
|
58
71
|
}
|
59
72
|
|
60
73
|
export function parseRequestParams<
|
61
|
-
SV extends
|
74
|
+
SV extends AnySchemaValidator,
|
62
75
|
Request extends ForklaunchRequest<SV>,
|
63
|
-
Response extends ForklaunchResponse,
|
76
|
+
Response extends ForklaunchResponse,
|
64
77
|
NextFunction extends ForklaunchNextFunction
|
65
78
|
>(req: Request, res: Response, next?: NextFunction) {
|
66
79
|
const params = req.contractDetails.params;
|
67
80
|
if (preHandlerParse(req.schemaValidator, req.params, params) === 400) {
|
68
|
-
res.status(400).send(
|
81
|
+
res.status(400).send('Invalid request parameters.');
|
69
82
|
if (next) {
|
70
|
-
next(new Error(
|
83
|
+
next(new Error('Invalid request parameters.'));
|
71
84
|
}
|
72
|
-
}
|
85
|
+
}
|
73
86
|
if (next) {
|
74
87
|
next();
|
75
88
|
}
|
76
89
|
}
|
77
90
|
|
78
91
|
export function parseRequestBody<
|
79
|
-
SV extends
|
92
|
+
SV extends AnySchemaValidator,
|
80
93
|
Request extends ForklaunchRequest<SV>,
|
81
|
-
Response extends ForklaunchResponse,
|
94
|
+
Response extends ForklaunchResponse,
|
82
95
|
NextFunction extends ForklaunchNextFunction
|
83
96
|
>(req: Request, res: Response, next?: NextFunction) {
|
84
97
|
if (req.headers['content-type'] === 'application/json') {
|
85
|
-
const body = (req.schemaValidator,
|
86
|
-
|
87
|
-
|
98
|
+
const body = (req.schemaValidator,
|
99
|
+
req.contractDetails as HttpContractDetails<SV>).body;
|
100
|
+
if (
|
101
|
+
preHandlerParse(
|
102
|
+
req.schemaValidator,
|
103
|
+
req.body,
|
104
|
+
body as StringOnlyObject<SV>
|
105
|
+
) === 400
|
106
|
+
) {
|
107
|
+
res.status(400).send('Invalid request body.');
|
88
108
|
if (next) {
|
89
|
-
next(new Error(
|
109
|
+
next(new Error('Invalid request body.'));
|
90
110
|
}
|
91
111
|
}
|
92
112
|
}
|
@@ -96,16 +116,16 @@ export function parseRequestBody<
|
|
96
116
|
}
|
97
117
|
|
98
118
|
export function parseRequestHeaders<
|
99
|
-
SV extends
|
119
|
+
SV extends AnySchemaValidator,
|
100
120
|
Request extends ForklaunchRequest<SV>,
|
101
|
-
Response extends ForklaunchResponse,
|
121
|
+
Response extends ForklaunchResponse,
|
102
122
|
NextFunction extends ForklaunchNextFunction
|
103
|
-
>
|
123
|
+
>(req: Request, res: Response, next?: NextFunction) {
|
104
124
|
const headers = req.contractDetails.requestHeaders;
|
105
125
|
if (preHandlerParse(req.schemaValidator, req.headers, headers) === 400) {
|
106
|
-
res.status(400).send(
|
126
|
+
res.status(400).send('Invalid request headers.');
|
107
127
|
if (next) {
|
108
|
-
next(new Error(
|
128
|
+
next(new Error('Invalid request headers.'));
|
109
129
|
}
|
110
130
|
}
|
111
131
|
if (next) {
|
@@ -114,16 +134,16 @@ export function parseRequestHeaders<
|
|
114
134
|
}
|
115
135
|
|
116
136
|
export function parseRequestQuery<
|
117
|
-
SV extends
|
137
|
+
SV extends AnySchemaValidator,
|
118
138
|
Request extends ForklaunchRequest<SV>,
|
119
|
-
Response extends ForklaunchResponse,
|
139
|
+
Response extends ForklaunchResponse,
|
120
140
|
NextFunction extends ForklaunchNextFunction
|
121
141
|
>(req: Request, res: Response, next?: NextFunction) {
|
122
142
|
const query = req.contractDetails.query;
|
123
143
|
if (preHandlerParse(req.schemaValidator, req.query, query) === 400) {
|
124
|
-
res.status(400).send(
|
144
|
+
res.status(400).send('Invalid request query.');
|
125
145
|
if (next) {
|
126
|
-
next(new Error(
|
146
|
+
next(new Error('Invalid request query.'));
|
127
147
|
}
|
128
148
|
}
|
129
149
|
if (next) {
|
@@ -131,44 +151,61 @@ export function parseRequestQuery<
|
|
131
151
|
}
|
132
152
|
}
|
133
153
|
|
134
|
-
async function checkAuthorizationToken(
|
154
|
+
async function checkAuthorizationToken(
|
155
|
+
authorizationMethod?: AuthMethod,
|
156
|
+
authorizationString?: string
|
157
|
+
): Promise<[401 | 403, string] | string | undefined> {
|
135
158
|
if (!authorizationString) {
|
136
|
-
return [401,
|
159
|
+
return [401, 'No Authorization token provided.'];
|
137
160
|
}
|
138
161
|
switch (authorizationMethod) {
|
139
162
|
case 'jwt': {
|
140
163
|
if (!authorizationString.startsWith('Bearer ')) {
|
141
|
-
return [401,
|
164
|
+
return [401, 'Invalid Authorization token format.'];
|
142
165
|
}
|
143
166
|
try {
|
144
|
-
const decodedJwt = await jose.jwtVerify(
|
167
|
+
const decodedJwt = await jose.jwtVerify(
|
168
|
+
authorizationString.split(' ')[1],
|
169
|
+
new TextEncoder().encode(
|
170
|
+
process.env.JWT_SECRET || 'your-256-bit-secret'
|
171
|
+
)
|
172
|
+
);
|
145
173
|
return decodedJwt.payload.iss;
|
146
|
-
} catch(error) {
|
174
|
+
} catch (error) {
|
147
175
|
console.error(error);
|
148
|
-
return [403,
|
176
|
+
return [403, 'Invalid Authorization token.'];
|
149
177
|
}
|
150
178
|
}
|
151
179
|
default:
|
152
|
-
return [401,
|
180
|
+
return [401, 'Invalid Authorization method.'];
|
153
181
|
}
|
154
182
|
}
|
155
183
|
|
156
|
-
function mapRoles(
|
184
|
+
function mapRoles(
|
185
|
+
authorizationType?: AuthMethod,
|
186
|
+
authorizationToken?: string
|
187
|
+
): string[] {
|
157
188
|
return [];
|
158
189
|
}
|
159
|
-
function mapPermissions(
|
190
|
+
function mapPermissions(
|
191
|
+
authorizationType?: AuthMethod,
|
192
|
+
authorizationToken?: string
|
193
|
+
): string[] {
|
160
194
|
return [];
|
161
195
|
}
|
162
196
|
|
163
197
|
export async function parseRequestAuth<
|
164
|
-
SV extends
|
198
|
+
SV extends AnySchemaValidator,
|
165
199
|
Request extends ForklaunchRequest<SV>,
|
166
|
-
Response extends ForklaunchResponse,
|
200
|
+
Response extends ForklaunchResponse,
|
167
201
|
NextFunction extends ForklaunchNextFunction
|
168
202
|
>(req: Request, res: Response, next?: NextFunction) {
|
169
203
|
const auth = req.contractDetails.auth;
|
170
204
|
if (auth) {
|
171
|
-
const errorAndMessage = await checkAuthorizationToken(
|
205
|
+
const errorAndMessage = await checkAuthorizationToken(
|
206
|
+
auth.method,
|
207
|
+
req.headers.authorization
|
208
|
+
);
|
172
209
|
if (Array.isArray(errorAndMessage)) {
|
173
210
|
res.status(errorAndMessage[0]).send(errorAndMessage[1]);
|
174
211
|
if (next) {
|
@@ -177,33 +214,44 @@ export async function parseRequestAuth<
|
|
177
214
|
}
|
178
215
|
|
179
216
|
// TODO: Implement role and permission checking
|
180
|
-
const permissionSlugs
|
217
|
+
const permissionSlugs = mapPermissions(
|
218
|
+
auth.method,
|
219
|
+
req.headers.authorization
|
220
|
+
);
|
181
221
|
const roles = mapRoles(auth.method, req.headers.authorization);
|
182
222
|
|
183
|
-
const permissionErrorMessage =
|
184
|
-
|
223
|
+
const permissionErrorMessage =
|
224
|
+
'User does not have sufficient permissions to perform action.';
|
225
|
+
const roleErrorMessage =
|
226
|
+
'User does not have correct role to perform action.';
|
185
227
|
|
186
228
|
// this is wrong, we need to check if any of the user's permissions are in the allowed permissions, while checking that any of the permissions is not in the forbidden slugs
|
187
229
|
// currently this is checking if any of the user's permissions are NOT in the allowed permissions
|
188
|
-
permissionSlugs.forEach(permissionSlug => {
|
189
|
-
if (
|
230
|
+
permissionSlugs.forEach((permissionSlug) => {
|
231
|
+
if (
|
232
|
+
!req.contractDetails.auth?.allowedSlugs?.has(permissionSlug) ||
|
233
|
+
req.contractDetails.auth?.forbiddenSlugs?.has(permissionSlug)
|
234
|
+
) {
|
190
235
|
res.status(403).send(permissionErrorMessage);
|
191
236
|
if (next) {
|
192
237
|
next(new Error(permissionErrorMessage));
|
193
238
|
}
|
194
|
-
}
|
239
|
+
}
|
195
240
|
});
|
196
|
-
roles.forEach(role => {
|
197
|
-
if (
|
241
|
+
roles.forEach((role) => {
|
242
|
+
if (
|
243
|
+
!req.contractDetails.auth?.allowedRoles?.has(role) ||
|
244
|
+
req.contractDetails.auth?.forbiddenRoles?.has(role)
|
245
|
+
) {
|
198
246
|
res.status(403).send(roleErrorMessage);
|
199
247
|
if (next) {
|
200
248
|
next(new Error(roleErrorMessage));
|
201
249
|
}
|
202
|
-
}
|
250
|
+
}
|
203
251
|
});
|
204
252
|
}
|
205
|
-
|
253
|
+
|
206
254
|
// if (next) {
|
207
255
|
// next();
|
208
256
|
// }
|
209
|
-
}
|
257
|
+
}
|
@@ -1,38 +1,63 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
3
|
-
|
1
|
+
import { AnySchemaValidator } from '@forklaunch/validator';
|
2
|
+
import {
|
3
|
+
ForklaunchNextFunction,
|
4
|
+
ForklaunchRequest,
|
5
|
+
ForklaunchResponse
|
6
|
+
} from '../types/api.types';
|
7
|
+
import { HttpContractDetails } from '../types/primitive.types';
|
4
8
|
|
5
|
-
function checkAnyValidation<SV extends
|
6
|
-
|
9
|
+
function checkAnyValidation<SV extends AnySchemaValidator>(
|
10
|
+
contractDetails: HttpContractDetails<SV>
|
11
|
+
) {
|
12
|
+
return (
|
13
|
+
contractDetails.body ||
|
14
|
+
contractDetails.params ||
|
15
|
+
contractDetails.requestHeaders ||
|
16
|
+
contractDetails.query
|
17
|
+
);
|
7
18
|
}
|
8
19
|
|
9
20
|
export function parseResponse<
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
>
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
(checkAnyValidation(req.contractDetails) && res.statusCode === 400) ||
|
22
|
-
(req.contractDetails.auth && (res.statusCode === 401 || res.statusCode === 403))
|
23
|
-
) {
|
24
|
-
return;
|
25
|
-
}
|
26
|
-
if (Object.prototype.hasOwnProperty.call(!req.contractDetails.responses, res.statusCode)) {
|
27
|
-
if (next) {
|
28
|
-
next(new Error(`Response code ${res.statusCode} not defined in contract.`));
|
29
|
-
};
|
30
|
-
}
|
31
|
-
|
32
|
-
const schema = req.schemaValidator.schemify(req.contractDetails.responses[res.statusCode]);
|
33
|
-
req.schemaValidator.validate(schema, res.bodyData);
|
21
|
+
SV extends AnySchemaValidator,
|
22
|
+
Request extends ForklaunchRequest<SV>,
|
23
|
+
Response extends ForklaunchResponse,
|
24
|
+
NextFunction extends ForklaunchNextFunction
|
25
|
+
>(req: Request, res: Response, next?: NextFunction) {
|
26
|
+
if (req.contractDetails.responseHeaders) {
|
27
|
+
const schema = req.schemaValidator.schemify(
|
28
|
+
req.contractDetails.responseHeaders
|
29
|
+
);
|
30
|
+
req.schemaValidator.validate(schema, res.getHeaders());
|
31
|
+
}
|
34
32
|
|
33
|
+
if (
|
34
|
+
res.statusCode === 500 ||
|
35
|
+
(checkAnyValidation(req.contractDetails) && res.statusCode === 400) ||
|
36
|
+
(req.contractDetails.auth &&
|
37
|
+
(res.statusCode === 401 || res.statusCode === 403))
|
38
|
+
) {
|
39
|
+
req.schemaValidator.validate(req.schemaValidator.string, res.bodyData);
|
40
|
+
return;
|
41
|
+
}
|
42
|
+
if (
|
43
|
+
Object.prototype.hasOwnProperty.call(
|
44
|
+
!req.contractDetails.responses,
|
45
|
+
res.statusCode
|
46
|
+
)
|
47
|
+
) {
|
35
48
|
if (next) {
|
36
|
-
|
49
|
+
next(
|
50
|
+
new Error(`Response code ${res.statusCode} not defined in contract.`)
|
51
|
+
);
|
37
52
|
}
|
38
|
-
}
|
53
|
+
}
|
54
|
+
|
55
|
+
const schema = req.schemaValidator.schemify(
|
56
|
+
req.contractDetails.responses[res.statusCode]
|
57
|
+
);
|
58
|
+
req.schemaValidator.validate(schema, res.bodyData);
|
59
|
+
|
60
|
+
if (next) {
|
61
|
+
next();
|
62
|
+
}
|
63
|
+
}
|