aws-service-stack 0.18.447 → 0.18.450
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 +79 -7
- package/dist/controller/base-controller.d.ts +2 -1
- package/dist/controller/base-controller.d.ts.map +1 -1
- package/dist/controller/base-controller.js +64 -15
- package/dist/controller/base-controller.js.map +1 -1
- package/dist/controller/controller-api.d.ts +13 -2
- package/dist/controller/controller-api.d.ts.map +1 -1
- package/dist/controller/controller-api.js +77 -10
- package/dist/controller/controller-api.js.map +1 -1
- package/dist/controller/controller-request.d.ts +3 -0
- package/dist/controller/controller-request.d.ts.map +1 -1
- package/dist/controller/controller-request.js +5 -0
- package/dist/controller/controller-request.js.map +1 -1
- package/dist/controller/controller-role.d.ts +2 -1
- package/dist/controller/controller-role.d.ts.map +1 -1
- package/dist/controller/controller-role.js +12 -3
- package/dist/controller/controller-role.js.map +1 -1
- package/dist/exception/exception-handler.d.ts.map +1 -1
- package/dist/exception/exception-handler.js +17 -2
- package/dist/exception/exception-handler.js.map +1 -1
- package/dist/model/base.config.d.ts +4 -1
- package/dist/model/base.config.d.ts.map +1 -1
- package/dist/model/base.config.js +1 -0
- package/dist/model/base.config.js.map +1 -1
- package/dist/model/base.model.d.ts +3 -0
- package/dist/model/base.model.d.ts.map +1 -1
- package/dist/model/base.model.js.map +1 -1
- package/dist/model/caller.model.d.ts +22 -0
- package/dist/model/caller.model.d.ts.map +1 -0
- package/dist/model/caller.model.js +12 -0
- package/dist/model/caller.model.js.map +1 -0
- package/dist/model/index.d.ts +1 -0
- package/dist/model/index.d.ts.map +1 -1
- package/dist/model/index.js +1 -0
- package/dist/model/index.js.map +1 -1
- package/dist/model/validation.model.d.ts +15 -1
- package/dist/model/validation.model.d.ts.map +1 -1
- package/dist/model/validation.model.js +3 -1
- package/dist/model/validation.model.js.map +1 -1
- package/dist/repositories/base-es.repo.d.ts.map +1 -1
- package/dist/repositories/base-es.repo.js +4 -0
- package/dist/repositories/base-es.repo.js.map +1 -1
- package/dist/utils/auth/caller.d.ts +9 -0
- package/dist/utils/auth/caller.d.ts.map +1 -0
- package/dist/utils/auth/caller.js +108 -0
- package/dist/utils/auth/caller.js.map +1 -0
- package/dist/utils/auth/policy-view.d.ts +42 -0
- package/dist/utils/auth/policy-view.d.ts.map +1 -0
- package/dist/utils/auth/policy-view.js +170 -0
- package/dist/utils/auth/policy-view.js.map +1 -0
- package/dist/utils/http/api-event.d.ts +23 -0
- package/dist/utils/http/api-event.d.ts.map +1 -0
- package/dist/utils/http/api-event.js +84 -0
- package/dist/utils/http/api-event.js.map +1 -0
- package/dist/utils/http/http.util.d.ts +12 -2
- package/dist/utils/http/http.util.d.ts.map +1 -1
- package/dist/utils/http/http.util.js +50 -24
- package/dist/utils/http/http.util.js.map +1 -1
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/opensearch/opensearch.mapping.d.ts +35 -0
- package/dist/utils/opensearch/opensearch.mapping.d.ts.map +1 -0
- package/dist/utils/opensearch/opensearch.mapping.js +95 -0
- package/dist/utils/opensearch/opensearch.mapping.js.map +1 -0
- package/dist/utils/opensearch/opensearch.parser.aggs.d.ts +2 -1
- package/dist/utils/opensearch/opensearch.parser.aggs.d.ts.map +1 -1
- package/dist/utils/opensearch/opensearch.parser.aggs.js +38 -4
- package/dist/utils/opensearch/opensearch.parser.aggs.js.map +1 -1
- package/dist/utils/opensearch/opensearch.parser.d.ts +1 -1
- package/dist/utils/reflection.util.d.ts +4 -0
- package/dist/utils/reflection.util.d.ts.map +1 -1
- package/dist/utils/reflection.util.js +17 -0
- package/dist/utils/reflection.util.js.map +1 -1
- package/package.json +76 -19
package/README.md
CHANGED
|
@@ -46,15 +46,21 @@ npm install aws-service-stack
|
|
|
46
46
|
|
|
47
47
|
### Peer Dependencies
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
Backend services must install the peer dependencies below. They are marked optional in
|
|
50
|
+
`peerDependenciesMeta`, so a project that lists the package without importing it at runtime
|
|
51
|
+
does not get unmet-peer warnings. Importing the package without them fails at runtime, not at install time.
|
|
50
52
|
|
|
51
53
|
```bash
|
|
52
|
-
npm install
|
|
53
|
-
@aws-sdk/client-
|
|
54
|
-
@aws-sdk/client-cognito-identity-provider
|
|
55
|
-
@aws-sdk/client-
|
|
56
|
-
@aws-sdk/
|
|
57
|
-
@
|
|
54
|
+
npm install \
|
|
55
|
+
@aws-sdk/client-apigatewaymanagementapi \
|
|
56
|
+
@aws-sdk/client-cognito-identity-provider \
|
|
57
|
+
@aws-sdk/client-dynamodb \
|
|
58
|
+
@aws-sdk/client-secrets-manager \
|
|
59
|
+
@aws-sdk/credential-provider-node \
|
|
60
|
+
@aws-sdk/lib-dynamodb \
|
|
61
|
+
@aws-sdk/util-dynamodb \
|
|
62
|
+
@opensearch-project/opensearch \
|
|
63
|
+
axios dayjs typedi@0.10.0 yup zod
|
|
58
64
|
```
|
|
59
65
|
|
|
60
66
|
## 🏁 Quick Start
|
|
@@ -570,6 +576,72 @@ await roleController.assignRole("us-east-1_PoolId", "john@example.com", "Manager
|
|
|
570
576
|
- Concurrent requests for the same key are deduplicated (single in-flight fetch)
|
|
571
577
|
- Cache is automatically invalidated on create, update, and delete operations
|
|
572
578
|
|
|
579
|
+
## 🪪 Caller kinds and policy views (HTTP API + Cognito JWT)
|
|
580
|
+
|
|
581
|
+
Caller mode verifies the `Authorization` JWT itself (REST and HTTP API events alike) and gives every
|
|
582
|
+
request a verified **caller kind**: `guest` (no token), `user`, `retailer`, `supplier` or `admin`.
|
|
583
|
+
Without `CALLER_POOLS` nothing changes: the REST authorizer claims and the legacy access chain are used
|
|
584
|
+
exactly as before.
|
|
585
|
+
|
|
586
|
+
### `CALLER_POOLS`
|
|
587
|
+
|
|
588
|
+
Set it on the entity config (`CALLER_POOLS`) or as the env variable `CALLER_POOLS` (JSON). The config wins.
|
|
589
|
+
|
|
590
|
+
```ts
|
|
591
|
+
CALLER_POOLS: [
|
|
592
|
+
{ userPoolId: "ap-southeast-1_User", kind: CallerKind.USER },
|
|
593
|
+
{ userPoolId: "ap-southeast-1_Supplier", kind: CallerKind.SUPPLIER, clientIds: ["abc123"] },
|
|
594
|
+
{ userPoolId: "ap-southeast-1_Admin", kind: CallerKind.ADMIN },
|
|
595
|
+
]
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
```bash
|
|
599
|
+
CALLER_POOLS='[{"userPoolId":"ap-southeast-1_Supplier","kind":"supplier"}]'
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
- Each entry needs a string `userPoolId` and a `kind` of `user|retailer|supplier|admin`; `clientIds` is
|
|
603
|
+
optional (absent = any app client). Invalid JSON or entries are a config error (HTTP 500).
|
|
604
|
+
- The token's issuer selects the pool. A token from the admin pool is `admin` only with a group from
|
|
605
|
+
`ADMIN_GROUP_NAME`, otherwise `user`.
|
|
606
|
+
- Invalid or expired token: 401. JWKS not reachable: 503.
|
|
607
|
+
|
|
608
|
+
### `kinds` and `view` on an endpoint policy
|
|
609
|
+
|
|
610
|
+
```ts
|
|
611
|
+
{
|
|
612
|
+
method: HttpMethod.GET,
|
|
613
|
+
path: "/products",
|
|
614
|
+
kinds: [CallerKind.GUEST, CallerKind.SUPPLIER, CallerKind.ADMIN],
|
|
615
|
+
view: {
|
|
616
|
+
guest: { filter: { status: ["active", "inactive"] }, response: { include: ["id", "name"] } },
|
|
617
|
+
supplier: { filter: { supplierId: claim("custom:profileId") } },
|
|
618
|
+
},
|
|
619
|
+
}
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
- `kinds` lists the caller kinds allowed on the endpoint (403 otherwise). In caller mode a policy with a
|
|
623
|
+
`view` but without `kinds` is a config error (500).
|
|
624
|
+
- `view[kind].filter` forces filter keys: a scalar means equality, an array means IN, `claim("…")` takes
|
|
625
|
+
the value from the verified token. Client keys, range/operator/index selectors and owner aliases
|
|
626
|
+
(`profileId`, `ownerParentId`, `ownerId`, `OWNER_ID_FIELD_NAME`, `OWNER_PARENT_ID_FIELD_NAME`) that
|
|
627
|
+
could replace a forced key are dropped. By-id GET of an item outside the view is 404, PATCH/PUT/DELETE
|
|
628
|
+
403; a POST/PUT/PATCH body value for a forced key must match it.
|
|
629
|
+
- An allowed kind **without a view** gets the client filter unchanged (no forced keys).
|
|
630
|
+
- `view[kind].response` replaces `response` for that kind.
|
|
631
|
+
- **`claim()` attributes must be read-only for app clients** (Cognito: not in the app client's write
|
|
632
|
+
attributes). A claim value containing `*` or `,` or starting with `!` is rejected (403), because
|
|
633
|
+
DynamoDB and OpenSearch would read it as an operator.
|
|
634
|
+
|
|
635
|
+
### Things to know
|
|
636
|
+
|
|
637
|
+
- The guards apply only to the **built-in routes** (`<base>`, `/search`, `/search/query`,
|
|
638
|
+
`/search/query/total-count`, `/scan`, `/{id}`). A custom endpoint (`processCrudRequest`) must honour
|
|
639
|
+
`req.filter` and `req.forcedFilter` itself.
|
|
640
|
+
- `PERMISSION_MAP.kinds` (role-table access) defaults to `[CallerKind.ADMIN]` in caller mode.
|
|
641
|
+
- HTTP API (v2) repeated query parameters other than `searchBy` become a comma list, i.e. an IN filter.
|
|
642
|
+
- `ControllerRequest.resolveRequest` only dispatches REST vs HTTP API events; it does **no caller
|
|
643
|
+
verification**.
|
|
644
|
+
|
|
573
645
|
## 🤝 Contributing
|
|
574
646
|
|
|
575
647
|
1. Fork the repository
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { APIResponse, BaseService, HttpMethod, HttpRequest, RequestType } from "../index";
|
|
2
2
|
import { APIGatewayProxyEvent, APIGatewayProxyWebsocketEventV2, CreateAuthChallengeTriggerEvent, DefineAuthChallengeTriggerEvent, DynamoDBStreamEvent, PostConfirmationTriggerEvent, PreSignUpTriggerEvent, ScheduledEvent, SQSEvent, VerifyAuthChallengeResponseTriggerEvent } from "aws-lambda";
|
|
3
|
+
import { type ApiEvent } from "../utils/http/api-event";
|
|
3
4
|
import { EntityConfig } from "../model/index.js";
|
|
4
5
|
/**
|
|
5
6
|
* @deprecated Use `ControllerApi, ControllerSocket, ControllerStream` instead.
|
|
@@ -25,7 +26,7 @@ export declare abstract class BaseController<T extends BaseService<any, any>> {
|
|
|
25
26
|
protected config: EntityConfig;
|
|
26
27
|
protected path: string;
|
|
27
28
|
protected constructor(baseService: T, config: EntityConfig);
|
|
28
|
-
resolveCrudRequest(event:
|
|
29
|
+
resolveCrudRequest(event: ApiEvent): Promise<APIResponse>;
|
|
29
30
|
resolveSQSEvent(sqsEvent: SQSEvent): Promise<void>;
|
|
30
31
|
resolveStreamEvent(event: DynamoDBStreamEvent): Promise<void>;
|
|
31
32
|
resolveScheduledEvent(event: ScheduledEvent): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-controller.d.ts","sourceRoot":"","sources":["../../src/controller/base-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,WAAW,EACX,WAAW,EAOX,UAAU,EACV,WAAW,EAKX,WAAW,EAGZ,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,oBAAoB,EACpB,+BAA+B,EAC/B,+BAA+B,EAC/B,+BAA+B,EAC/B,mBAAmB,EACnB,4BAA4B,EAC5B,qBAAqB,EACrB,cAAc,EACd,QAAQ,EACR,uCAAuC,EACxC,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"base-controller.d.ts","sourceRoot":"","sources":["../../src/controller/base-controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.BaseController = void 0;
|
|
4
4
|
const index_1 = require("../index");
|
|
5
5
|
const exception_1 = require("../exception");
|
|
6
|
+
const caller_model_1 = require("../model/caller.model");
|
|
7
|
+
const caller_1 = require("../utils/auth/caller");
|
|
8
|
+
const policy_view_1 = require("../utils/auth/policy-view");
|
|
9
|
+
const api_event_1 = require("../utils/http/api-event");
|
|
6
10
|
const string_util_1 = require("../utils/string.util");
|
|
7
11
|
/**
|
|
8
12
|
* @deprecated Use `ControllerApi, ControllerSocket, ControllerStream` instead.
|
|
@@ -41,16 +45,43 @@ class BaseController {
|
|
|
41
45
|
}
|
|
42
46
|
async resolveCrudRequest(event) {
|
|
43
47
|
try {
|
|
44
|
-
this.
|
|
48
|
+
const pools = this.config.CALLER_POOLS ?? (0, caller_1.parseCallerPoolsEnv)(process.env.CALLER_POOLS);
|
|
49
|
+
const caller = pools?.length
|
|
50
|
+
? await (0, caller_1.resolveCaller)((0, api_event_1.normalizeApiEvent)(event).headers.authorization, pools, this.config.ADMIN_GROUP_NAME ?? [])
|
|
51
|
+
: undefined;
|
|
52
|
+
this.bootstrapRequest(event, caller);
|
|
45
53
|
const policy = (0, index_1.findMatchedPolicy)(this.methode, this.path, this.config.ENDPOINT_POLICY);
|
|
46
|
-
|
|
54
|
+
if (caller && !policy)
|
|
55
|
+
throw new exception_1.ErrorHttp(index_1.HTTP.NOT_FOUND, "No matching policy found for this endpoint");
|
|
56
|
+
if (caller)
|
|
57
|
+
(0, policy_view_1.assertViewHasKinds)(policy);
|
|
58
|
+
let responseFields = policy?.response;
|
|
59
|
+
const viewPath = !!(caller && policy?.kinds);
|
|
60
|
+
if (viewPath) {
|
|
61
|
+
const filter = (0, policy_view_1.stripForcedSelectors)(policy, caller, this.request.filter ?? {}, this.config);
|
|
62
|
+
const view = (0, policy_view_1.applyPolicyView)(policy, caller, filter);
|
|
63
|
+
this.request.filter = view.filter;
|
|
64
|
+
this.request.responseFields = view.response;
|
|
65
|
+
responseFields = view.response;
|
|
66
|
+
const forced = (0, policy_view_1.resolveForcedFilter)(policy, caller);
|
|
67
|
+
if (Object.keys(forced).length) {
|
|
68
|
+
this.request.forcedFilter = forced;
|
|
69
|
+
this.request.body = (0, policy_view_1.guardForcedBody)(this.methode, this.request.body, forced);
|
|
70
|
+
this.requestBody = this.request.body;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
this.checkPermission(policy?.access);
|
|
75
|
+
}
|
|
47
76
|
this.validateRequest(policy?.validator);
|
|
48
|
-
|
|
77
|
+
// The view's forced keys own the filter; the legacy owner filter must not overwrite them
|
|
78
|
+
if (!viewPath)
|
|
79
|
+
this.setUserFilter();
|
|
49
80
|
const response = await this.handleCrudByMethod(event);
|
|
50
|
-
if (!
|
|
81
|
+
if (!responseFields) {
|
|
51
82
|
return (0, index_1.createApiResponse)(200, response);
|
|
52
83
|
}
|
|
53
|
-
const filteredResponse = this.filterResponse(response,
|
|
84
|
+
const filteredResponse = this.filterResponse(response, responseFields);
|
|
54
85
|
return (0, index_1.createApiResponse)(200, filteredResponse);
|
|
55
86
|
}
|
|
56
87
|
catch (err) {
|
|
@@ -205,12 +236,25 @@ class BaseController {
|
|
|
205
236
|
return isMethodGet && isExpectedPath;
|
|
206
237
|
}
|
|
207
238
|
async handleCrudByMethod(event) {
|
|
239
|
+
const forced = this.request?.forcedFilter;
|
|
240
|
+
if (forced && this.entityId && (this.isUpdateRequest() || this.isDeleteRequest() || this.methode === "PUT")) {
|
|
241
|
+
const item = await this.service.findById(this.entityId);
|
|
242
|
+
if (!item)
|
|
243
|
+
throw new exception_1.ErrorHttp(index_1.HTTP.NOT_FOUND, `Resource with ID ${this.entityId} not found`);
|
|
244
|
+
if (!(0, policy_view_1.matchesForcedFilter)(item, forced))
|
|
245
|
+
throw new exception_1.ErrorHttp(index_1.HTTP.FORBIDDEN, "Access denied");
|
|
246
|
+
}
|
|
208
247
|
if (this.isUpdateRequest())
|
|
209
248
|
return this.handleUpdate();
|
|
210
249
|
if (this.isDeleteRequest())
|
|
211
250
|
return this.handleDelete();
|
|
212
|
-
if (this.isFetchRequest())
|
|
213
|
-
|
|
251
|
+
if (this.isFetchRequest()) {
|
|
252
|
+
const item = await this.handleFetch();
|
|
253
|
+
if (forced && !(0, policy_view_1.matchesForcedFilter)(item, forced)) {
|
|
254
|
+
throw new exception_1.ErrorHttp(index_1.HTTP.NOT_FOUND, `Resource with ID ${this.entityId} not found`);
|
|
255
|
+
}
|
|
256
|
+
return item;
|
|
257
|
+
}
|
|
214
258
|
if (this.methode === "PUT")
|
|
215
259
|
return this.handleReplace();
|
|
216
260
|
if (this.methode === "POST")
|
|
@@ -262,17 +306,19 @@ class BaseController {
|
|
|
262
306
|
const ownerIdFieldName = this.config.OWNER_ID_FIELD_NAME || "ownerId";
|
|
263
307
|
this.request.filter[ownerIdFieldName] = this.profileId;
|
|
264
308
|
}
|
|
265
|
-
bootstrapRequest(event) {
|
|
309
|
+
bootstrapRequest(event, caller) {
|
|
266
310
|
log.debug("event: " + JSON.stringify(event, null, 2));
|
|
311
|
+
const isRest = !(0, api_event_1.isHttpApiEvent)(event);
|
|
312
|
+
// HTTP API events are exposed as-is; subclasses typed for REST must check the event version
|
|
267
313
|
this.event = event;
|
|
268
|
-
this.resource = event.resource || undefined;
|
|
269
|
-
this.
|
|
270
|
-
this.
|
|
314
|
+
this.resource = isRest ? event.resource || undefined : undefined;
|
|
315
|
+
this.request = (0, index_1.parseHttpRequest)(event, this.config, caller);
|
|
316
|
+
this.methode = this.request.methode;
|
|
317
|
+
this.path = isRest ? event?.requestContext?.resourcePath : this.request.routePath;
|
|
271
318
|
this.resourcePath = `${this.methode} ${this.path}`;
|
|
272
|
-
this.request = (0, index_1.parseHttpRequest)(event, this.config);
|
|
273
319
|
this.requestBody = this.request.body;
|
|
274
320
|
this.entityId = event.pathParameters?.id || undefined;
|
|
275
|
-
this.parserUserData(event.requestContext?.authorizer?.claims);
|
|
321
|
+
this.parserUserData(caller ? caller.claims : event.requestContext?.authorizer?.claims, caller);
|
|
276
322
|
}
|
|
277
323
|
parseEntity() {
|
|
278
324
|
if (!this.requestBody)
|
|
@@ -290,7 +336,7 @@ class BaseController {
|
|
|
290
336
|
throw new exception_1.ErrorHttp(index_1.HTTP.UNPROCESSABLE_ENTITY, "Validation Error", formattedErrors);
|
|
291
337
|
}
|
|
292
338
|
}
|
|
293
|
-
parserUserData(claims) {
|
|
339
|
+
parserUserData(claims, caller) {
|
|
294
340
|
// request user data
|
|
295
341
|
this.groups = (0, string_util_1.toArray)(claims?.["cognito:groups"]);
|
|
296
342
|
this.username = claims?.["cognito:username"] || "";
|
|
@@ -298,12 +344,15 @@ class BaseController {
|
|
|
298
344
|
this.profileId = claims?.["custom:profileId"] || this.username;
|
|
299
345
|
const adminGroups = new Set((0, string_util_1.normalizeLower)((0, string_util_1.toArray)(this.adminGroupNames)));
|
|
300
346
|
const groups = (0, string_util_1.normalizeLower)((0, string_util_1.toArray)(this.groups));
|
|
301
|
-
|
|
347
|
+
// With verified callers only kind ADMIN is admin (a supplier token with an admin group is not)
|
|
348
|
+
this.isAdmin = caller ? caller.kind === caller_model_1.CallerKind.ADMIN : groups.some((g) => adminGroups.has(g));
|
|
302
349
|
if (this.isAdmin) {
|
|
303
350
|
this.profileId = this.request.body?.ownerId || "";
|
|
304
351
|
delete this.request.body?.ownerId;
|
|
305
352
|
this.requestType = index_1.RequestType.ADMIN;
|
|
306
353
|
}
|
|
354
|
+
else if (caller)
|
|
355
|
+
this.requestType = caller.kind === caller_model_1.CallerKind.GUEST ? index_1.RequestType.GUEST : index_1.RequestType.USER;
|
|
307
356
|
else if (this.profileId || this.userId)
|
|
308
357
|
this.requestType = index_1.RequestType.USER;
|
|
309
358
|
else
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-controller.js","sourceRoot":"","sources":["../../src/controller/base-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Access,\n APIResponse,\n BaseService,\n createApiResponse,\n EndpointPolicy,\n findMatchedPolicy,\n formatErrors,\n getTableName,\n HTTP,\n HttpMethod,\n HttpRequest,\n parseEventToAction,\n parseHttpRequest,\n parseImage,\n removeFields,\n RequestType,\n ResponseFields,\n validateWithSchema,\n} from \"../index\";\nimport {\n APIGatewayProxyEvent,\n APIGatewayProxyWebsocketEventV2,\n CreateAuthChallengeTriggerEvent,\n DefineAuthChallengeTriggerEvent,\n DynamoDBStreamEvent,\n PostConfirmationTriggerEvent,\n PreSignUpTriggerEvent,\n ScheduledEvent,\n SQSEvent,\n VerifyAuthChallengeResponseTriggerEvent,\n} from \"aws-lambda\";\nimport { ErrorHttp, refineHttpError } from \"../exception\";\nimport { EntityConfig } from \"@chinggis/types\";\nimport { normalizeLower, toArray, trimSpecialChar } from \"../utils/string.util\";\n\n/**\n * @deprecated Use `ControllerApi, ControllerSocket, ControllerStream` instead.\n */\nexport abstract class BaseController<T extends BaseService<any, any>> {\n protected resourcePath: string;\n protected userId: string;\n protected isAdmin: boolean;\n protected request: HttpRequest;\n protected readonly service: T;\n protected adminGroupNames: string[];\n protected requestBody: any;\n protected triggerEvent: any;\n protected eventAttr: any;\n protected event: APIGatewayProxyEvent;\n protected resource: string;\n protected entityId: string;\n protected methode: HttpMethod;\n protected groups: string[] = [];\n protected username: string;\n protected profileId: string;\n protected requestType: RequestType;\n protected config: EntityConfig;\n protected path: string;\n\n protected constructor(baseService: T, config: EntityConfig) {\n this.service = baseService;\n\n // Store config for use in subclasses\n if (!config) return;\n\n this.config = config;\n // Set adminGroupName from config if available\n if (config.ADMIN_GROUP_NAME) {\n this.adminGroupNames = config.ADMIN_GROUP_NAME;\n }\n\n this.service.setConfig(config);\n }\n\n async resolveCrudRequest(event: APIGatewayProxyEvent): Promise<APIResponse> {\n try {\n this.bootstrapRequest(event);\n\n const policy: EndpointPolicy | undefined = findMatchedPolicy(\n this.methode,\n this.path,\n this.config.ENDPOINT_POLICY,\n );\n\n this.checkPermission(policy?.access);\n this.validateRequest(policy?.validator);\n this.setUserFilter();\n\n const response: any = await this.handleCrudByMethod(event);\n\n if (!policy?.response) {\n return createApiResponse(200, response);\n }\n\n const filteredResponse = this.filterResponse(response, policy.response);\n\n return createApiResponse(200, filteredResponse);\n } catch (err) {\n const error = refineHttpError(err);\n log.info(err);\n if (error.statusCode >= 500) log.error(error);\n else if (error.statusCode >= 400) log.warn(error);\n return createApiResponse(error.statusCode, error.content);\n }\n }\n\n async resolveSQSEvent(sqsEvent: SQSEvent): Promise<void> {\n try {\n await this.processSQSEvent(sqsEvent);\n } catch (error) {\n console.error(\"Error handling SQS event:\", error);\n }\n }\n\n async resolveStreamEvent(event: DynamoDBStreamEvent): Promise<void> {\n try {\n for (const record of event.Records) {\n const oldItem = parseImage(record.dynamodb.OldImage) as T;\n const newItem = parseImage(record.dynamodb.NewImage) as T;\n\n await this.service.processChanges(\n oldItem,\n newItem,\n parseEventToAction(record.eventName),\n getTableName(record.eventSourceARN),\n );\n }\n await this.processStreamEvent(event);\n } catch (error) {\n console.error(\"Error handling request event:\", error);\n }\n }\n\n async resolveScheduledEvent(event: ScheduledEvent): Promise<void> {\n try {\n await this.processScheduledEvent(event);\n } catch (error) {\n console.error(\"Error handling request event:\", error);\n }\n }\n\n async resolveWebSocketEvent(event: APIGatewayProxyWebsocketEventV2): Promise<void> {\n try {\n return await this.processWebSocketEvent(event);\n } catch (error) {\n console.error(\"Error handling request event:\", error);\n }\n }\n\n async resolveTriggerEvent(\n event:\n | CreateAuthChallengeTriggerEvent\n | DefineAuthChallengeTriggerEvent\n | VerifyAuthChallengeResponseTriggerEvent\n | PostConfirmationTriggerEvent\n | PreSignUpTriggerEvent,\n ): Promise<void> {\n try {\n this.triggerEvent = event;\n this.eventAttr = this.triggerEvent.userAttributes;\n return await this.processTriggerEvent(event);\n } catch (error) {\n console.error(\"Error handling request event:\", error);\n }\n }\n\n setConfig(config: EntityConfig): void {\n this.config = config;\n }\n\n protected async handleList(): Promise<any> {\n if (this.methode === \"GET\" && trimSpecialChar(this.path) === trimSpecialChar(this.config.BASE_PATH)) {\n return await this.service.find(this.request.filter || {});\n }\n\n if (this.methode === \"GET\" && trimSpecialChar(this.path) === trimSpecialChar(this.config.BASE_PATH) + \"/search\") {\n return await this.service.search(this.request.filter || {});\n }\n\n if (this.methode === \"GET\" && trimSpecialChar(this.path) === trimSpecialChar(this.config.BASE_PATH) + \"/scan\") {\n return await this.service.scan(this.request.filter || {});\n }\n }\n\n protected async handleUpdate(): Promise<any> {\n if (!this.entityId) throw new ErrorHttp(HTTP.BAD_REQUEST, \"Cannot PATCH resource without id field\");\n\n const entity = this.parseEntity();\n\n if (Object.keys(entity).length === 0) {\n throw new ErrorHttp(HTTP.BAD_REQUEST, \"No fields to update\");\n }\n\n // id change is forbidden\n if (\"id\" in entity) {\n throw new ErrorHttp(HTTP.BAD_REQUEST, \"Cannot modify the id field\");\n }\n\n entity.id = this.entityId;\n return this.service.update(entity, this.profileId);\n }\n\n protected async handleDelete(): Promise<boolean> {\n if (!this.entityId) throw new ErrorHttp(HTTP.BAD_REQUEST, \"Cannot delete resource without id field\");\n\n return this.service.remove(this.entityId, this.profileId);\n }\n\n protected async handleFetch(): Promise<any> {\n if (!this.entityId) throw new ErrorHttp(HTTP.BAD_REQUEST, \"Cannot fetch resource without id field\");\n\n const result = await this.service.findById(this.entityId, this.profileId);\n\n if (result) return result;\n\n throw new ErrorHttp(HTTP.NOT_FOUND, `Resource with ID ${this.entityId} not found`);\n }\n\n protected async handleReplace() {\n if (!this.entityId) throw new ErrorHttp(HTTP.BAD_REQUEST, \"Cannot PUT resource without id field\");\n\n const entity = this.parseEntity();\n\n if (!Object.keys(entity).length) {\n throw new ErrorHttp(HTTP.BAD_REQUEST, \"No entity provided for PUT update\");\n }\n\n if (!this.entityId) {\n throw new ErrorHttp(HTTP.BAD_REQUEST, \"Cannot PUT resource without id field\");\n }\n\n entity.id = this.entityId;\n\n return this.service.update(entity, this.profileId);\n }\n\n protected async handlePostCreate() {\n const entity = this.parseEntity();\n if (!Object.keys(entity).length) {\n throw new ErrorHttp(HTTP.BAD_REQUEST, \"No entity payload provided\");\n }\n\n if (!this.isAdmin) entity.profileId = this.profileId;\n else if (!entity.profileId) {\n throw new ErrorHttp(HTTP.BAD_REQUEST, \"No profileId provided\");\n }\n\n return await this.service.save(entity, this.profileId);\n }\n\n protected abstract processCrudRequest(event: APIGatewayProxyEvent): Promise<any>;\n\n /**\n * service дээр processChanges methode ажилсны дараа хийгдэх үйлдлүүд байна\n * @param event - DynamoDBStreamEvent\n * @returns Promise<void>\n * */\n protected abstract processStreamEvent(event: DynamoDBStreamEvent): Promise<void>;\n\n protected abstract processScheduledEvent(event: ScheduledEvent): Promise<void>;\n\n protected abstract processWebSocketEvent(event: APIGatewayProxyWebsocketEventV2): Promise<void>;\n\n protected processTriggerEvent?(\n event:\n | CreateAuthChallengeTriggerEvent\n | DefineAuthChallengeTriggerEvent\n | VerifyAuthChallengeResponseTriggerEvent\n | PostConfirmationTriggerEvent\n | PreSignUpTriggerEvent,\n ): Promise<void> {\n throw new Error(`Method not implemented. event: ${JSON.stringify(event, null, 2)}`);\n }\n\n protected abstract processSQSEvent(sqsEvent: SQSEvent): Promise<any>;\n\n protected isListRequest(): boolean {\n const basePath = trimSpecialChar(this.config.BASE_PATH);\n\n const allowedPaths = [basePath, `${basePath}/search`, `${basePath}/scan`];\n\n const isMethodGet = this.methode === \"GET\";\n const isAllowedPath = allowedPaths.includes(trimSpecialChar(this.path));\n\n return isMethodGet && isAllowedPath;\n }\n\n protected isUpdateRequest(): boolean {\n const expectedPath = `${trimSpecialChar(this.config.BASE_PATH)}/{id}`;\n const isMethodPatch = this.methode === \"PATCH\";\n const isExpectedPath = trimSpecialChar(this.path) === expectedPath;\n\n return isMethodPatch && isExpectedPath;\n }\n\n protected isDeleteRequest(): boolean {\n const expectedPath = `${trimSpecialChar(this.config.BASE_PATH)}/{id}`;\n const isMethodDelete = this.methode === \"DELETE\";\n const isExpectedPath = trimSpecialChar(this.path) === expectedPath;\n\n return isMethodDelete && isExpectedPath;\n }\n\n protected isFetchRequest(): boolean {\n const expectedPath = `${trimSpecialChar(this.config.BASE_PATH)}/{id}`;\n const isMethodGet = this.methode === \"GET\";\n const isExpectedPath = trimSpecialChar(this.path) === expectedPath;\n\n return isMethodGet && isExpectedPath;\n }\n\n private async handleCrudByMethod(event: APIGatewayProxyEvent): Promise<any> {\n if (this.isUpdateRequest()) return this.handleUpdate();\n if (this.isDeleteRequest()) return this.handleDelete();\n if (this.isFetchRequest()) return this.handleFetch();\n if (this.methode === \"PUT\") return this.handleReplace();\n if (this.methode === \"POST\") return this.handlePostCreate();\n if (this.isListRequest()) return this.handleList();\n return this.processCrudRequest(event); // Custom Endpoints\n }\n\n private filterResponse(response: any, responsePolicy: ResponseFields): any {\n if (Array.isArray(response)) {\n return removeFields(response, responsePolicy.include, responsePolicy.exclude);\n }\n\n if (response?.items && Array.isArray(response.items)) {\n response.items = removeFields(response.items, responsePolicy.include, responsePolicy.exclude);\n return response;\n }\n\n return removeFields([response], responsePolicy.include, responsePolicy.exclude)[0];\n }\n\n /**\n * Map RequestType to Access for permission checking\n */\n private getUserAccessLevel(): Access {\n switch (this.requestType) {\n case RequestType.ADMIN:\n return Access.ADMIN;\n case RequestType.USER:\n return Access.USER;\n case RequestType.GUEST:\n return Access.PUBLIC;\n case RequestType.SYSTEM:\n return Access.SYSTEM;\n default:\n return Access.PUBLIC;\n }\n }\n\n /** Check if the user has permission for the current operation */\n private checkPermission(allowedAccess: Access[]) {\n const currentAccessLevel = this.getUserAccessLevel();\n\n // This means USER can access OWNER-level permissions, but the service will verify actual ownership\n const hasPermission =\n allowedAccess.includes(currentAccessLevel) ||\n (this.requestType === RequestType.USER && allowedAccess.includes(Access.OWNER));\n\n if (hasPermission) return;\n\n throw new ErrorHttp(\n HTTP.UNAUTHORIZED,\n `Access denied. Required: ${allowedAccess.join(\", \")}, Current: ${currentAccessLevel}`,\n );\n }\n\n private setUserFilter() {\n if (this.isAdmin && !this.profileId) return;\n const ownerIdFieldName = this.config.OWNER_ID_FIELD_NAME || \"ownerId\";\n this.request.filter[ownerIdFieldName] = this.profileId;\n }\n\n private bootstrapRequest(event: APIGatewayProxyEvent) {\n log.debug(\"event: \" + JSON.stringify(event, null, 2));\n\n this.event = event;\n this.resource = event.resource || undefined;\n\n this.methode = event.httpMethod as HttpMethod;\n this.path = event?.requestContext?.resourcePath;\n this.resourcePath = `${this.methode} ${this.path}`;\n\n this.request = parseHttpRequest(event, this.config);\n this.requestBody = this.request.body;\n this.entityId = event.pathParameters?.id || undefined;\n\n this.parserUserData(event.requestContext?.authorizer?.claims);\n }\n\n private parseEntity(): Record<string, unknown> {\n if (!this.requestBody) return {};\n return typeof this.requestBody === \"string\" ? JSON.parse(this.requestBody) : this.requestBody;\n }\n\n private validateRequest(schema: any) {\n if (!schema) return;\n\n try {\n validateWithSchema(schema, this.requestBody);\n } catch (error) {\n const formattedErrors = formatErrors(error);\n throw new ErrorHttp(HTTP.UNPROCESSABLE_ENTITY, \"Validation Error\", formattedErrors);\n }\n }\n\n private parserUserData(claims: any) {\n // request user data\n this.groups = toArray(claims?.[\"cognito:groups\"]);\n this.username = claims?.[\"cognito:username\"] || \"\";\n this.userId = claims?.sub || \"\";\n this.profileId = claims?.[\"custom:profileId\"] || this.username;\n\n const adminGroups = new Set(normalizeLower(toArray(this.adminGroupNames)));\n const groups = normalizeLower(toArray(this.groups));\n this.isAdmin = groups.some((g) => adminGroups.has(g));\n\n if (this.isAdmin) {\n this.profileId = this.request.body?.ownerId || \"\";\n delete this.request.body?.ownerId;\n this.requestType = RequestType.ADMIN;\n } else if (this.profileId || this.userId) this.requestType = RequestType.USER;\n else this.requestType = RequestType.GUEST;\n\n log.debug(\"groups: \" + JSON.stringify(this.groups, null, 2));\n log.debug(`claims:${JSON.stringify(claims, null, 2)}`);\n log.debug(\n `groups:${this.groups}, isAdmin:${this.isAdmin}, userId:${this.userId}, profileId:${this.profileId}, username:${this.username}, requestType:${this.requestType}`,\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"base-controller.js","sourceRoot":"","sources":["../../src/controller/base-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Access,\n APIResponse,\n BaseService,\n createApiResponse,\n EndpointPolicy,\n findMatchedPolicy,\n formatErrors,\n getTableName,\n HTTP,\n HttpMethod,\n HttpRequest,\n parseEventToAction,\n parseHttpRequest,\n parseImage,\n removeFields,\n RequestType,\n ResponseFields,\n validateWithSchema,\n} from \"../index\";\nimport {\n APIGatewayProxyEvent,\n APIGatewayProxyWebsocketEventV2,\n CreateAuthChallengeTriggerEvent,\n DefineAuthChallengeTriggerEvent,\n DynamoDBStreamEvent,\n PostConfirmationTriggerEvent,\n PreSignUpTriggerEvent,\n ScheduledEvent,\n SQSEvent,\n VerifyAuthChallengeResponseTriggerEvent,\n} from \"aws-lambda\";\nimport { ErrorHttp, refineHttpError } from \"../exception\";\nimport { type Caller, CallerKind } from \"../model/caller.model\";\nimport { parseCallerPoolsEnv, resolveCaller } from \"../utils/auth/caller\";\nimport {\n applyPolicyView,\n assertViewHasKinds,\n guardForcedBody,\n matchesForcedFilter,\n resolveForcedFilter,\n stripForcedSelectors,\n} from \"../utils/auth/policy-view\";\nimport { type ApiEvent, isHttpApiEvent, normalizeApiEvent } from \"../utils/http/api-event\";\nimport { EntityConfig } from \"@chinggis/types\";\nimport { normalizeLower, toArray, trimSpecialChar } from \"../utils/string.util\";\n\n/**\n * @deprecated Use `ControllerApi, ControllerSocket, ControllerStream` instead.\n */\nexport abstract class BaseController<T extends BaseService<any, any>> {\n protected resourcePath: string;\n protected userId: string;\n protected isAdmin: boolean;\n protected request: HttpRequest;\n protected readonly service: T;\n protected adminGroupNames: string[];\n protected requestBody: any;\n protected triggerEvent: any;\n protected eventAttr: any;\n protected event: APIGatewayProxyEvent;\n protected resource: string;\n protected entityId: string;\n protected methode: HttpMethod;\n protected groups: string[] = [];\n protected username: string;\n protected profileId: string;\n protected requestType: RequestType;\n protected config: EntityConfig;\n protected path: string;\n\n protected constructor(baseService: T, config: EntityConfig) {\n this.service = baseService;\n\n // Store config for use in subclasses\n if (!config) return;\n\n this.config = config;\n // Set adminGroupName from config if available\n if (config.ADMIN_GROUP_NAME) {\n this.adminGroupNames = config.ADMIN_GROUP_NAME;\n }\n\n this.service.setConfig(config);\n }\n\n async resolveCrudRequest(event: ApiEvent): Promise<APIResponse> {\n try {\n const pools = this.config.CALLER_POOLS ?? parseCallerPoolsEnv(process.env.CALLER_POOLS);\n const caller = pools?.length\n ? await resolveCaller(normalizeApiEvent(event).headers.authorization, pools, this.config.ADMIN_GROUP_NAME ?? [])\n : undefined;\n\n this.bootstrapRequest(event, caller);\n\n const policy: EndpointPolicy | undefined = findMatchedPolicy(\n this.methode,\n this.path,\n this.config.ENDPOINT_POLICY,\n );\n\n if (caller && !policy) throw new ErrorHttp(HTTP.NOT_FOUND, \"No matching policy found for this endpoint\");\n if (caller) assertViewHasKinds(policy);\n\n let responseFields = policy?.response;\n const viewPath = !!(caller && policy?.kinds);\n if (viewPath) {\n const filter = stripForcedSelectors(policy, caller, this.request.filter ?? {}, this.config);\n const view = applyPolicyView(policy, caller, filter);\n this.request.filter = view.filter;\n this.request.responseFields = view.response;\n responseFields = view.response;\n const forced = resolveForcedFilter(policy, caller);\n if (Object.keys(forced).length) {\n this.request.forcedFilter = forced;\n this.request.body = guardForcedBody(this.methode, this.request.body, forced);\n this.requestBody = this.request.body;\n }\n } else {\n this.checkPermission(policy?.access);\n }\n this.validateRequest(policy?.validator);\n // The view's forced keys own the filter; the legacy owner filter must not overwrite them\n if (!viewPath) this.setUserFilter();\n\n const response: any = await this.handleCrudByMethod(event as APIGatewayProxyEvent);\n\n if (!responseFields) {\n return createApiResponse(200, response);\n }\n\n const filteredResponse = this.filterResponse(response, responseFields);\n\n return createApiResponse(200, filteredResponse);\n } catch (err) {\n const error = refineHttpError(err);\n log.info(err);\n if (error.statusCode >= 500) log.error(error);\n else if (error.statusCode >= 400) log.warn(error);\n return createApiResponse(error.statusCode, error.content);\n }\n }\n\n async resolveSQSEvent(sqsEvent: SQSEvent): Promise<void> {\n try {\n await this.processSQSEvent(sqsEvent);\n } catch (error) {\n console.error(\"Error handling SQS event:\", error);\n }\n }\n\n async resolveStreamEvent(event: DynamoDBStreamEvent): Promise<void> {\n try {\n for (const record of event.Records) {\n const oldItem = parseImage(record.dynamodb.OldImage) as T;\n const newItem = parseImage(record.dynamodb.NewImage) as T;\n\n await this.service.processChanges(\n oldItem,\n newItem,\n parseEventToAction(record.eventName),\n getTableName(record.eventSourceARN),\n );\n }\n await this.processStreamEvent(event);\n } catch (error) {\n console.error(\"Error handling request event:\", error);\n }\n }\n\n async resolveScheduledEvent(event: ScheduledEvent): Promise<void> {\n try {\n await this.processScheduledEvent(event);\n } catch (error) {\n console.error(\"Error handling request event:\", error);\n }\n }\n\n async resolveWebSocketEvent(event: APIGatewayProxyWebsocketEventV2): Promise<void> {\n try {\n return await this.processWebSocketEvent(event);\n } catch (error) {\n console.error(\"Error handling request event:\", error);\n }\n }\n\n async resolveTriggerEvent(\n event:\n | CreateAuthChallengeTriggerEvent\n | DefineAuthChallengeTriggerEvent\n | VerifyAuthChallengeResponseTriggerEvent\n | PostConfirmationTriggerEvent\n | PreSignUpTriggerEvent,\n ): Promise<void> {\n try {\n this.triggerEvent = event;\n this.eventAttr = this.triggerEvent.userAttributes;\n return await this.processTriggerEvent(event);\n } catch (error) {\n console.error(\"Error handling request event:\", error);\n }\n }\n\n setConfig(config: EntityConfig): void {\n this.config = config;\n }\n\n protected async handleList(): Promise<any> {\n if (this.methode === \"GET\" && trimSpecialChar(this.path) === trimSpecialChar(this.config.BASE_PATH)) {\n return await this.service.find(this.request.filter || {});\n }\n\n if (this.methode === \"GET\" && trimSpecialChar(this.path) === trimSpecialChar(this.config.BASE_PATH) + \"/search\") {\n return await this.service.search(this.request.filter || {});\n }\n\n if (this.methode === \"GET\" && trimSpecialChar(this.path) === trimSpecialChar(this.config.BASE_PATH) + \"/scan\") {\n return await this.service.scan(this.request.filter || {});\n }\n }\n\n protected async handleUpdate(): Promise<any> {\n if (!this.entityId) throw new ErrorHttp(HTTP.BAD_REQUEST, \"Cannot PATCH resource without id field\");\n\n const entity = this.parseEntity();\n\n if (Object.keys(entity).length === 0) {\n throw new ErrorHttp(HTTP.BAD_REQUEST, \"No fields to update\");\n }\n\n // id change is forbidden\n if (\"id\" in entity) {\n throw new ErrorHttp(HTTP.BAD_REQUEST, \"Cannot modify the id field\");\n }\n\n entity.id = this.entityId;\n return this.service.update(entity, this.profileId);\n }\n\n protected async handleDelete(): Promise<boolean> {\n if (!this.entityId) throw new ErrorHttp(HTTP.BAD_REQUEST, \"Cannot delete resource without id field\");\n\n return this.service.remove(this.entityId, this.profileId);\n }\n\n protected async handleFetch(): Promise<any> {\n if (!this.entityId) throw new ErrorHttp(HTTP.BAD_REQUEST, \"Cannot fetch resource without id field\");\n\n const result = await this.service.findById(this.entityId, this.profileId);\n\n if (result) return result;\n\n throw new ErrorHttp(HTTP.NOT_FOUND, `Resource with ID ${this.entityId} not found`);\n }\n\n protected async handleReplace() {\n if (!this.entityId) throw new ErrorHttp(HTTP.BAD_REQUEST, \"Cannot PUT resource without id field\");\n\n const entity = this.parseEntity();\n\n if (!Object.keys(entity).length) {\n throw new ErrorHttp(HTTP.BAD_REQUEST, \"No entity provided for PUT update\");\n }\n\n if (!this.entityId) {\n throw new ErrorHttp(HTTP.BAD_REQUEST, \"Cannot PUT resource without id field\");\n }\n\n entity.id = this.entityId;\n\n return this.service.update(entity, this.profileId);\n }\n\n protected async handlePostCreate() {\n const entity = this.parseEntity();\n if (!Object.keys(entity).length) {\n throw new ErrorHttp(HTTP.BAD_REQUEST, \"No entity payload provided\");\n }\n\n if (!this.isAdmin) entity.profileId = this.profileId;\n else if (!entity.profileId) {\n throw new ErrorHttp(HTTP.BAD_REQUEST, \"No profileId provided\");\n }\n\n return await this.service.save(entity, this.profileId);\n }\n\n protected abstract processCrudRequest(event: APIGatewayProxyEvent): Promise<any>;\n\n /**\n * service дээр processChanges methode ажилсны дараа хийгдэх үйлдлүүд байна\n * @param event - DynamoDBStreamEvent\n * @returns Promise<void>\n * */\n protected abstract processStreamEvent(event: DynamoDBStreamEvent): Promise<void>;\n\n protected abstract processScheduledEvent(event: ScheduledEvent): Promise<void>;\n\n protected abstract processWebSocketEvent(event: APIGatewayProxyWebsocketEventV2): Promise<void>;\n\n protected processTriggerEvent?(\n event:\n | CreateAuthChallengeTriggerEvent\n | DefineAuthChallengeTriggerEvent\n | VerifyAuthChallengeResponseTriggerEvent\n | PostConfirmationTriggerEvent\n | PreSignUpTriggerEvent,\n ): Promise<void> {\n throw new Error(`Method not implemented. event: ${JSON.stringify(event, null, 2)}`);\n }\n\n protected abstract processSQSEvent(sqsEvent: SQSEvent): Promise<any>;\n\n protected isListRequest(): boolean {\n const basePath = trimSpecialChar(this.config.BASE_PATH);\n\n const allowedPaths = [basePath, `${basePath}/search`, `${basePath}/scan`];\n\n const isMethodGet = this.methode === \"GET\";\n const isAllowedPath = allowedPaths.includes(trimSpecialChar(this.path));\n\n return isMethodGet && isAllowedPath;\n }\n\n protected isUpdateRequest(): boolean {\n const expectedPath = `${trimSpecialChar(this.config.BASE_PATH)}/{id}`;\n const isMethodPatch = this.methode === \"PATCH\";\n const isExpectedPath = trimSpecialChar(this.path) === expectedPath;\n\n return isMethodPatch && isExpectedPath;\n }\n\n protected isDeleteRequest(): boolean {\n const expectedPath = `${trimSpecialChar(this.config.BASE_PATH)}/{id}`;\n const isMethodDelete = this.methode === \"DELETE\";\n const isExpectedPath = trimSpecialChar(this.path) === expectedPath;\n\n return isMethodDelete && isExpectedPath;\n }\n\n protected isFetchRequest(): boolean {\n const expectedPath = `${trimSpecialChar(this.config.BASE_PATH)}/{id}`;\n const isMethodGet = this.methode === \"GET\";\n const isExpectedPath = trimSpecialChar(this.path) === expectedPath;\n\n return isMethodGet && isExpectedPath;\n }\n\n private async handleCrudByMethod(event: APIGatewayProxyEvent): Promise<any> {\n const forced = this.request?.forcedFilter;\n if (forced && this.entityId && (this.isUpdateRequest() || this.isDeleteRequest() || this.methode === \"PUT\")) {\n const item = await this.service.findById(this.entityId);\n if (!item) throw new ErrorHttp(HTTP.NOT_FOUND, `Resource with ID ${this.entityId} not found`);\n if (!matchesForcedFilter(item, forced)) throw new ErrorHttp(HTTP.FORBIDDEN, \"Access denied\");\n }\n if (this.isUpdateRequest()) return this.handleUpdate();\n if (this.isDeleteRequest()) return this.handleDelete();\n if (this.isFetchRequest()) {\n const item = await this.handleFetch();\n if (forced && !matchesForcedFilter(item, forced)) {\n throw new ErrorHttp(HTTP.NOT_FOUND, `Resource with ID ${this.entityId} not found`);\n }\n return item;\n }\n if (this.methode === \"PUT\") return this.handleReplace();\n if (this.methode === \"POST\") return this.handlePostCreate();\n if (this.isListRequest()) return this.handleList();\n return this.processCrudRequest(event); // Custom Endpoints\n }\n\n private filterResponse(response: any, responsePolicy: ResponseFields): any {\n if (Array.isArray(response)) {\n return removeFields(response, responsePolicy.include, responsePolicy.exclude);\n }\n\n if (response?.items && Array.isArray(response.items)) {\n response.items = removeFields(response.items, responsePolicy.include, responsePolicy.exclude);\n return response;\n }\n\n return removeFields([response], responsePolicy.include, responsePolicy.exclude)[0];\n }\n\n /**\n * Map RequestType to Access for permission checking\n */\n private getUserAccessLevel(): Access {\n switch (this.requestType) {\n case RequestType.ADMIN:\n return Access.ADMIN;\n case RequestType.USER:\n return Access.USER;\n case RequestType.GUEST:\n return Access.PUBLIC;\n case RequestType.SYSTEM:\n return Access.SYSTEM;\n default:\n return Access.PUBLIC;\n }\n }\n\n /** Check if the user has permission for the current operation */\n private checkPermission(allowedAccess: Access[]) {\n const currentAccessLevel = this.getUserAccessLevel();\n\n // This means USER can access OWNER-level permissions, but the service will verify actual ownership\n const hasPermission =\n allowedAccess.includes(currentAccessLevel) ||\n (this.requestType === RequestType.USER && allowedAccess.includes(Access.OWNER));\n\n if (hasPermission) return;\n\n throw new ErrorHttp(\n HTTP.UNAUTHORIZED,\n `Access denied. Required: ${allowedAccess.join(\", \")}, Current: ${currentAccessLevel}`,\n );\n }\n\n private setUserFilter() {\n if (this.isAdmin && !this.profileId) return;\n const ownerIdFieldName = this.config.OWNER_ID_FIELD_NAME || \"ownerId\";\n this.request.filter[ownerIdFieldName] = this.profileId;\n }\n\n private bootstrapRequest(event: ApiEvent, caller?: Caller) {\n log.debug(\"event: \" + JSON.stringify(event, null, 2));\n\n const isRest = !isHttpApiEvent(event);\n // HTTP API events are exposed as-is; subclasses typed for REST must check the event version\n this.event = event as APIGatewayProxyEvent;\n this.resource = isRest ? (event as APIGatewayProxyEvent).resource || undefined : undefined;\n\n this.request = parseHttpRequest(event, this.config, caller);\n this.methode = this.request.methode;\n this.path = isRest ? (event as APIGatewayProxyEvent)?.requestContext?.resourcePath : this.request.routePath;\n this.resourcePath = `${this.methode} ${this.path}`;\n\n this.requestBody = this.request.body;\n this.entityId = event.pathParameters?.id || undefined;\n\n this.parserUserData(\n caller ? caller.claims : (event as APIGatewayProxyEvent).requestContext?.authorizer?.claims,\n caller,\n );\n }\n\n private parseEntity(): Record<string, unknown> {\n if (!this.requestBody) return {};\n return typeof this.requestBody === \"string\" ? JSON.parse(this.requestBody) : this.requestBody;\n }\n\n private validateRequest(schema: any) {\n if (!schema) return;\n\n try {\n validateWithSchema(schema, this.requestBody);\n } catch (error) {\n const formattedErrors = formatErrors(error);\n throw new ErrorHttp(HTTP.UNPROCESSABLE_ENTITY, \"Validation Error\", formattedErrors);\n }\n }\n\n private parserUserData(claims: any, caller?: Caller) {\n // request user data\n this.groups = toArray(claims?.[\"cognito:groups\"]);\n this.username = claims?.[\"cognito:username\"] || \"\";\n this.userId = claims?.sub || \"\";\n this.profileId = claims?.[\"custom:profileId\"] || this.username;\n\n const adminGroups = new Set(normalizeLower(toArray(this.adminGroupNames)));\n const groups = normalizeLower(toArray(this.groups));\n // With verified callers only kind ADMIN is admin (a supplier token with an admin group is not)\n this.isAdmin = caller ? caller.kind === CallerKind.ADMIN : groups.some((g) => adminGroups.has(g));\n\n if (this.isAdmin) {\n this.profileId = this.request.body?.ownerId || \"\";\n delete this.request.body?.ownerId;\n this.requestType = RequestType.ADMIN;\n } else if (caller) this.requestType = caller.kind === CallerKind.GUEST ? RequestType.GUEST : RequestType.USER;\n else if (this.profileId || this.userId) this.requestType = RequestType.USER;\n else this.requestType = RequestType.GUEST;\n\n log.debug(\"groups: \" + JSON.stringify(this.groups, null, 2));\n log.debug(`claims:${JSON.stringify(claims, null, 2)}`);\n log.debug(\n `groups:${this.groups}, isAdmin:${this.isAdmin}, userId:${this.userId}, profileId:${this.profileId}, username:${this.username}, requestType:${this.requestType}`,\n );\n }\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { APIResponse, BaseEntity, HttpMethod, HttpRequest, List } from "../index";
|
|
2
|
-
import {
|
|
2
|
+
import type { Caller } from "../model/caller.model";
|
|
3
|
+
import { type ApiEvent } from "../utils/http/api-event";
|
|
3
4
|
import { CognitoUser, EntityConfig } from "../model/index.js";
|
|
4
5
|
import { CrudService } from "../service";
|
|
5
6
|
export declare abstract class ControllerApi<R extends BaseEntity, T extends CrudService<R>> {
|
|
@@ -8,8 +9,18 @@ export declare abstract class ControllerApi<R extends BaseEntity, T extends Crud
|
|
|
8
9
|
protected adminGroupNames: string[];
|
|
9
10
|
private roleController;
|
|
10
11
|
protected constructor(baseService: T, config: EntityConfig);
|
|
11
|
-
resolveCrudRequest(event:
|
|
12
|
+
resolveCrudRequest(event: ApiEvent): Promise<APIResponse>;
|
|
12
13
|
setConfig(config: EntityConfig): void;
|
|
14
|
+
/** Verified caller when CALLER_POOLS (config or env) are set; undefined = legacy REST authorizer claims */
|
|
15
|
+
protected resolveRequestCaller(event: ApiEvent): Promise<Caller | undefined>;
|
|
16
|
+
/** Kind check + forced view filter; client index/range selectors and owner aliases on forced keys are dropped */
|
|
17
|
+
private applyCallerPolicy;
|
|
18
|
+
/** `GET <base>/search/query` and `GET <base>/search/query/total-count` (OpenSearch query-string routes) */
|
|
19
|
+
private isSearchQueryPath;
|
|
20
|
+
/** By-id mutations under a forced view: the stored item must exist (404) and match the forced filter (403) */
|
|
21
|
+
private assertForcedItem;
|
|
22
|
+
/** By-id fetch under a forced view: an item outside the view is reported as not found */
|
|
23
|
+
private fetchInView;
|
|
13
24
|
processCrudRequestPre(req: HttpRequest): Promise<HttpRequest>;
|
|
14
25
|
processCrudRequestPost(request: HttpRequest, response: R | List<R>): Promise<R | List<R>>;
|
|
15
26
|
/** Return constructor-defined resource name */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller-api.d.ts","sourceRoot":"","sources":["../../src/controller/controller-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,WAAW,EACX,UAAU,EAIV,UAAU,EACV,WAAW,EACX,IAAI,EAML,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"controller-api.d.ts","sourceRoot":"","sources":["../../src/controller/controller-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ControllerApi = void 0;
|
|
4
4
|
const index_1 = require("../index");
|
|
5
|
+
const caller_1 = require("../utils/auth/caller");
|
|
6
|
+
const policy_view_1 = require("../utils/auth/policy-view");
|
|
7
|
+
const api_event_1 = require("../utils/http/api-event");
|
|
5
8
|
const exception_1 = require("../exception");
|
|
6
9
|
const string_util_1 = require("../utils/string.util");
|
|
7
10
|
const controller_role_1 = require("./controller-role");
|
|
@@ -25,8 +28,18 @@ class ControllerApi {
|
|
|
25
28
|
}
|
|
26
29
|
async resolveCrudRequest(event) {
|
|
27
30
|
try {
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
const caller = await this.resolveRequestCaller(event);
|
|
32
|
+
let req = (0, index_1.parseHttpRequest)(event, this.config, caller);
|
|
33
|
+
if (caller && !req.policy)
|
|
34
|
+
throw new exception_1.ErrorHttp(index_1.HTTP.NOT_FOUND, "No matching policy found for this endpoint");
|
|
35
|
+
if (caller)
|
|
36
|
+
(0, policy_view_1.assertViewHasKinds)(req.policy);
|
|
37
|
+
if (caller && req.policy.kinds) {
|
|
38
|
+
if (req.identity)
|
|
39
|
+
req.identity.isScope = false;
|
|
40
|
+
this.applyCallerPolicy(req, caller);
|
|
41
|
+
}
|
|
42
|
+
else if (req.policy.access?.length) {
|
|
30
43
|
if (req.identity)
|
|
31
44
|
req.identity.isScope = false;
|
|
32
45
|
this.checkPermission(req.policy.access, req);
|
|
@@ -35,7 +48,7 @@ class ControllerApi {
|
|
|
35
48
|
if (req.identity)
|
|
36
49
|
req.identity.isScope = true;
|
|
37
50
|
const resource = this.getResource();
|
|
38
|
-
await this.roleController.checkAccess(req, resource, this.config.PERMISSION_MAP.scopeMap, this.adminGroupNames, (id) => this.service.findById(id));
|
|
51
|
+
await this.roleController.checkAccess(req, resource, this.config.PERMISSION_MAP.scopeMap, this.adminGroupNames, (id) => this.service.findById(id), this.config.PERMISSION_MAP.kinds);
|
|
39
52
|
}
|
|
40
53
|
else {
|
|
41
54
|
throw new exception_1.ErrorHttp(index_1.HTTP.FORBIDDEN, "Access denied");
|
|
@@ -52,9 +65,10 @@ class ControllerApi {
|
|
|
52
65
|
response = await this.processCrudRequestPost(req, response);
|
|
53
66
|
else
|
|
54
67
|
response = await this.processCrudRequest(req); // Custom Endpoints
|
|
55
|
-
|
|
68
|
+
const responseFields = req.responseFields ?? req.policy.response;
|
|
69
|
+
if (!responseFields)
|
|
56
70
|
return (0, index_1.createApiResponse)(200, response);
|
|
57
|
-
const filteredResponse = this.filterResponse(response,
|
|
71
|
+
const filteredResponse = this.filterResponse(response, responseFields);
|
|
58
72
|
return (0, index_1.createApiResponse)(200, filteredResponse);
|
|
59
73
|
}
|
|
60
74
|
catch (err) {
|
|
@@ -69,6 +83,53 @@ class ControllerApi {
|
|
|
69
83
|
setConfig(config) {
|
|
70
84
|
this.config = config;
|
|
71
85
|
}
|
|
86
|
+
/** Verified caller when CALLER_POOLS (config or env) are set; undefined = legacy REST authorizer claims */
|
|
87
|
+
async resolveRequestCaller(event) {
|
|
88
|
+
const pools = this.config.CALLER_POOLS ?? (0, caller_1.parseCallerPoolsEnv)(process.env.CALLER_POOLS);
|
|
89
|
+
if (!pools?.length)
|
|
90
|
+
return undefined;
|
|
91
|
+
const { headers } = (0, api_event_1.normalizeApiEvent)(event);
|
|
92
|
+
return (0, caller_1.resolveCaller)(headers.authorization, pools, this.config.ADMIN_GROUP_NAME ?? []);
|
|
93
|
+
}
|
|
94
|
+
/** Kind check + forced view filter; client index/range selectors and owner aliases on forced keys are dropped */
|
|
95
|
+
applyCallerPolicy(req, caller) {
|
|
96
|
+
const filter = (0, policy_view_1.stripForcedSelectors)(req.policy, caller, req.filter ?? {}, this.config);
|
|
97
|
+
const view = (0, policy_view_1.applyPolicyView)(req.policy, caller, filter);
|
|
98
|
+
req.filter = view.filter;
|
|
99
|
+
req.responseFields = view.response;
|
|
100
|
+
const forced = (0, policy_view_1.resolveForcedFilter)(req.policy, caller);
|
|
101
|
+
if (Object.keys(forced).length) {
|
|
102
|
+
req.forcedFilter = forced;
|
|
103
|
+
req.body = (0, policy_view_1.guardForcedBody)(req.methode, req.body, forced);
|
|
104
|
+
// OpenSearch search/query* only reads `field__op` keys: the forced keys must be expressed as such
|
|
105
|
+
if (this.isSearchQueryPath(req.routePath))
|
|
106
|
+
req.filter = (0, policy_view_1.applyForcedSearchQuery)(req.filter, forced);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/** `GET <base>/search/query` and `GET <base>/search/query/total-count` (OpenSearch query-string routes) */
|
|
110
|
+
isSearchQueryPath(path) {
|
|
111
|
+
const base = (0, string_util_1.trimSpecialChar)(this.config.BASE_PATH);
|
|
112
|
+
const normalized = (0, string_util_1.trimSpecialChar)(path ?? "");
|
|
113
|
+
return normalized === `${base}/search/query` || normalized === `${base}/search/query/total-count`;
|
|
114
|
+
}
|
|
115
|
+
/** By-id mutations under a forced view: the stored item must exist (404) and match the forced filter (403) */
|
|
116
|
+
async assertForcedItem(req) {
|
|
117
|
+
if (!req.forcedFilter || !req.entityId)
|
|
118
|
+
return;
|
|
119
|
+
const item = await this.service.findById(req.entityId);
|
|
120
|
+
if (!item)
|
|
121
|
+
throw new exception_1.ErrorHttp(index_1.HTTP.NOT_FOUND, `[CORE] Resource with ID ${req.entityId} not found`);
|
|
122
|
+
if (!(0, policy_view_1.matchesForcedFilter)(item, req.forcedFilter))
|
|
123
|
+
throw new exception_1.ErrorHttp(index_1.HTTP.FORBIDDEN, "Access denied");
|
|
124
|
+
}
|
|
125
|
+
/** By-id fetch under a forced view: an item outside the view is reported as not found */
|
|
126
|
+
async fetchInView(req) {
|
|
127
|
+
const item = await this.handleFetch(req.entityId, req.identity);
|
|
128
|
+
if (req.forcedFilter && !(0, policy_view_1.matchesForcedFilter)(item, req.forcedFilter)) {
|
|
129
|
+
throw new exception_1.ErrorHttp(index_1.HTTP.NOT_FOUND, `[CORE] Resource with ID ${req.entityId} not found`);
|
|
130
|
+
}
|
|
131
|
+
return item;
|
|
132
|
+
}
|
|
72
133
|
async processCrudRequestPre(req) {
|
|
73
134
|
return req;
|
|
74
135
|
}
|
|
@@ -223,18 +284,24 @@ class ControllerApi {
|
|
|
223
284
|
return isMethodGet && isExpectedPath;
|
|
224
285
|
}
|
|
225
286
|
async handleCrudByMethod(req) {
|
|
226
|
-
const path = req.
|
|
287
|
+
const path = req.routePath;
|
|
227
288
|
const entity = this.parseEntity(req.body);
|
|
228
289
|
if (this.isPermissionRequest(path))
|
|
229
290
|
return this.handlePermission(req, path);
|
|
230
|
-
if (this.isUpdateRequest(req.methode, path))
|
|
291
|
+
if (this.isUpdateRequest(req.methode, path)) {
|
|
292
|
+
await this.assertForcedItem(req);
|
|
231
293
|
return this.handleUpdate(req.entityId, entity, req.identity);
|
|
232
|
-
|
|
294
|
+
}
|
|
295
|
+
if (this.isDeleteRequest(req.methode, path)) {
|
|
296
|
+
await this.assertForcedItem(req);
|
|
233
297
|
return this.handleDelete(req.entityId, req.identity);
|
|
298
|
+
}
|
|
234
299
|
if (this.isFetchRequest(req.methode, path))
|
|
235
|
-
return this.
|
|
236
|
-
if (this.isPutRequest(req.methode, path))
|
|
300
|
+
return this.fetchInView(req);
|
|
301
|
+
if (this.isPutRequest(req.methode, path)) {
|
|
302
|
+
await this.assertForcedItem(req);
|
|
237
303
|
return this.handleReplace(req.entityId, entity, req.identity);
|
|
304
|
+
}
|
|
238
305
|
if (this.isPostRequest(req.methode, path))
|
|
239
306
|
return this.handlePostCreate(entity, req.identity);
|
|
240
307
|
if (this.isListRequest(req.methode, path))
|