lemon-core 5.0.4 → 5.0.6
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 +168 -136
- package/bin/lemon-fields-types.mjs +12 -0
- package/bin/lib/fields-types.mjs +629 -0
- package/dist/common/test-helper.js +6 -3
- package/dist/common/test-helper.js.map +1 -1
- package/dist/cores/aws/aws-sns-service.d.ts +6 -0
- package/dist/cores/aws/aws-sns-service.js +22 -3
- package/dist/cores/aws/aws-sns-service.js.map +1 -1
- package/dist/cores/aws/aws-sqs-service.js +5 -0
- package/dist/cores/aws/aws-sqs-service.js.map +1 -1
- package/dist/cores/config/config-service.js +3 -1
- package/dist/cores/config/config-service.js.map +1 -1
- package/dist/cores/lambda/lambda-alb-handler.js +5 -0
- package/dist/cores/lambda/lambda-alb-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-handler.js +4 -1
- package/dist/cores/lambda/lambda-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-notification-handler.js +4 -1
- package/dist/cores/lambda/lambda-notification-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-sns-handler.d.ts +7 -1
- package/dist/cores/lambda/lambda-sns-handler.js +26 -3
- package/dist/cores/lambda/lambda-sns-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-sqs-handler.d.ts +7 -1
- package/dist/cores/lambda/lambda-sqs-handler.js +26 -3
- package/dist/cores/lambda/lambda-sqs-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-web-handler.js +63 -15
- package/dist/cores/lambda/lambda-web-handler.js.map +1 -1
- package/dist/cores/protocol/aws-lambda-helper.d.ts +13 -0
- package/dist/cores/protocol/aws-lambda-helper.js +64 -41
- package/dist/cores/protocol/aws-lambda-helper.js.map +1 -1
- package/dist/cores/protocol/local-transport.d.ts +135 -0
- package/dist/cores/protocol/local-transport.js +392 -0
- package/dist/cores/protocol/local-transport.js.map +1 -0
- package/dist/cores/protocol/protocol-relay.d.ts +123 -0
- package/dist/cores/protocol/protocol-relay.js +339 -0
- package/dist/cores/protocol/protocol-relay.js.map +1 -0
- package/dist/cores/protocol/protocol-service.d.ts +11 -4
- package/dist/cores/protocol/protocol-service.js +140 -36
- package/dist/cores/protocol/protocol-service.js.map +1 -1
- package/dist/cores/protocol/protocol-sign.d.ts +22 -0
- package/dist/cores/protocol/protocol-sign.js +30 -3
- package/dist/cores/protocol/protocol-sign.js.map +1 -1
- package/dist/engine/engine.js +35 -15
- package/dist/engine/engine.js.map +1 -1
- package/dist/esm/index.mjs +2 -0
- package/dist/extended/cores/abstract-controllers.d.ts +18 -4
- package/dist/extended/cores/abstract-controllers.js +59 -19
- package/dist/extended/cores/abstract-controllers.js.map +1 -1
- package/dist/extended/cores/abstract-services.d.ts +54 -4
- package/dist/extended/cores/abstract-services.js +159 -14
- package/dist/extended/cores/abstract-services.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/log-mask.d.ts +19 -0
- package/dist/lib/log-mask.js +55 -0
- package/dist/lib/log-mask.js.map +1 -0
- package/dist/lib/safe-json.d.ts +23 -0
- package/dist/lib/safe-json.js +78 -0
- package/dist/lib/safe-json.js.map +1 -0
- package/package.json +14 -4
|
@@ -30,18 +30,37 @@ declare const $LUT: {
|
|
|
30
30
|
* type: `CanDoActionType`
|
|
31
31
|
*/
|
|
32
32
|
export type CanDoActionType = keyof typeof $LUT.CanDoAction;
|
|
33
|
+
/**
|
|
34
|
+
* type: `AccessScope`
|
|
35
|
+
* - v5 B13: which rows one action may touch, against the caller's session (SPEC § 14.1).
|
|
36
|
+
* - `owner`: same `sid` and same non-empty `uid`. `group`: same `sid` and same non-empty `gid`.
|
|
37
|
+
* - `site`: same non-empty `sid`. `any`: every role holder.
|
|
38
|
+
*/
|
|
39
|
+
export type AccessScope = 'owner' | 'group' | 'site' | 'any';
|
|
40
|
+
/**
|
|
41
|
+
* type: `AccessPolicy`
|
|
42
|
+
* - v5 B13: the scope of each CRUD action.
|
|
43
|
+
*/
|
|
44
|
+
export type AccessPolicy = Record<CanDoActionType, AccessScope>;
|
|
45
|
+
/**
|
|
46
|
+
* v5 B13: the core default policy - list in the caller's site, the other four on own rows only.
|
|
47
|
+
* - override per type with `MyManagerProxy.accessPolicy()`, per controller with `options.policy`.
|
|
48
|
+
*/
|
|
49
|
+
export declare const DEFAULT_ACCESS_POLICY: Readonly<AccessPolicy>;
|
|
33
50
|
/**
|
|
34
51
|
* Optional parameters for `canDo()`
|
|
35
52
|
*/
|
|
36
53
|
export interface CanDoOptions {
|
|
37
54
|
/** error scope to print */
|
|
38
55
|
errScope?: string;
|
|
39
|
-
/** flag to throw error if not allowed (default
|
|
56
|
+
/** flag to throw error if not allowed (default true) */
|
|
40
57
|
throwable?: boolean;
|
|
41
|
-
/** flag to use session (default
|
|
58
|
+
/** flag to use session (default env `USE_SESSION`) */
|
|
42
59
|
useSession?: boolean;
|
|
43
60
|
/** current context to override */
|
|
44
61
|
context?: NextContext;
|
|
62
|
+
/** (optional) v5 B13: scopes to override the manager-proxy policy (used only with the session on) */
|
|
63
|
+
policy?: Partial<AccessPolicy>;
|
|
45
64
|
}
|
|
46
65
|
/**
|
|
47
66
|
* type: `ScanLastParams`
|
|
@@ -445,6 +464,8 @@ export declare class MyManagerProxy<MyModel extends CoreModel<ModelType>, MyMana
|
|
|
445
464
|
limit?: number;
|
|
446
465
|
/** (optional) error scope to use */
|
|
447
466
|
errScope?: string;
|
|
467
|
+
/** (optional) v5 B13: list scope to pin (default: the effective policy `list`, session on only) */
|
|
468
|
+
scope?: AccessScope;
|
|
448
469
|
}): {
|
|
449
470
|
$page: PaginateParam;
|
|
450
471
|
$param: SearchParam<MyModel>;
|
|
@@ -485,16 +506,45 @@ export declare class MyManagerProxy<MyModel extends CoreModel<ModelType>, MyMana
|
|
|
485
506
|
* @param validate (optional) flag to validate (default is true)
|
|
486
507
|
*/
|
|
487
508
|
makeModel<T extends MyModel>(model: T, validate?: boolean): Promise<T>;
|
|
509
|
+
/**
|
|
510
|
+
* v5 B13: the default policy of this model type (override per type).
|
|
511
|
+
* - merged as `{ ...DEFAULT_ACCESS_POLICY, ...accessPolicy(), ...options.policy }`.
|
|
512
|
+
*
|
|
513
|
+
* @returns the scope per action
|
|
514
|
+
*/
|
|
515
|
+
accessPolicy(): AccessPolicy;
|
|
516
|
+
/**
|
|
517
|
+
* v5 B13: the effective policy - core default, then `accessPolicy()`, then `policy` (undefined values skipped).
|
|
518
|
+
*
|
|
519
|
+
* @param policy (optional) scopes from the caller (ex: controller `options.policy`)
|
|
520
|
+
* @returns the merged policy
|
|
521
|
+
*/
|
|
522
|
+
effectivePolicy(policy?: Partial<AccessPolicy>): AccessPolicy;
|
|
488
523
|
/**
|
|
489
524
|
* Check if the current user can perform the specified action on the given model.
|
|
490
|
-
* - override this method to implement custom logic.
|
|
525
|
+
* - override this method to implement custom logic (an override runs before this default).
|
|
526
|
+
* - v5 B13: with the session on, the effective `AccessPolicy` decides (SPEC § 14.2); with it off, § 6.4 as before.
|
|
491
527
|
*
|
|
492
528
|
* @param action The action to check.
|
|
493
|
-
* @param model The model to check against.
|
|
529
|
+
* @param model The model to check against. (`undefined` for `list` = the caller check only)
|
|
494
530
|
* @param options Additional options for the check.
|
|
495
531
|
* @returns True if the action is allowed, false otherwise.
|
|
496
532
|
*/
|
|
497
533
|
canDo<T extends MyModel>(action: CanDoActionType, model?: T, options?: CanDoOptions): boolean;
|
|
534
|
+
/**
|
|
535
|
+
* the `canDo()` rules with the session off (v5 § 6.4, unchanged by B13).
|
|
536
|
+
* - `list`/`read`/`create`: same `sid` or a `sid`-less row; `update`/`delete`: same `sid` and `uid`.
|
|
537
|
+
*
|
|
538
|
+
* @param _act the validated action
|
|
539
|
+
* @param model the model to check against
|
|
540
|
+
* @param options { errScope, throwable, context }
|
|
541
|
+
* @returns True if the action is allowed, false otherwise.
|
|
542
|
+
*/
|
|
543
|
+
protected canDoWithoutSession<T extends MyModel>(_act: CanDoActionType, model: T, options: {
|
|
544
|
+
errScope: string;
|
|
545
|
+
throwable: boolean;
|
|
546
|
+
context?: NextContext;
|
|
547
|
+
}): boolean;
|
|
498
548
|
/**
|
|
499
549
|
* read multiple nodes.
|
|
500
550
|
* @param ids list of object-ids
|
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.$ES6Routed = exports.$OS2 = exports._OS2 = exports.OS2Instance = exports.OS2FGACManager = exports.OS2Service = exports.MyManagerProxy = exports.MyCoreProxy = exports.MyCoreManager = exports.MyCoreService = exports.sourceToItem = void 0;
|
|
36
|
+
exports.$ES6Routed = exports.$OS2 = exports._OS2 = exports.OS2Instance = exports.OS2FGACManager = exports.OS2Service = exports.MyManagerProxy = exports.MyCoreProxy = exports.MyCoreManager = exports.MyCoreService = exports.DEFAULT_ACCESS_POLICY = exports.sourceToItem = void 0;
|
|
37
37
|
/**
|
|
38
38
|
* `abstract-services.ts`
|
|
39
39
|
* - common services used in `/cores`
|
|
@@ -75,6 +75,7 @@ exports.$ES6Routed = exports.$OS2 = exports._OS2 = exports.OS2Instance = exports
|
|
|
75
75
|
* @date 2026-04-09 optimized `types` to fix `ModelType` cast error.
|
|
76
76
|
* @date 2026-10-27 v5 B2-b: OpenSearch client, lazy `$OS2` (= `$ES6Routed`), one service set per instance.
|
|
77
77
|
* @date 2026-10-28 v5 B4: `CORE_FIELDS = fieldsOf(CoreModel)`; manager `fields` may be a model class.
|
|
78
|
+
* @date 2026-10-30 v5 B13: default data-access policy (`AccessPolicy`, `canDo` scopes, `list` pin by scope).
|
|
78
79
|
*
|
|
79
80
|
* @copyright (C) 2022 LemonCloud Co Ltd. - All Rights Reserved.
|
|
80
81
|
* @origin `@lemoncloud/lemon-templates-api/cores`
|
|
@@ -116,6 +117,17 @@ const $LUT = {
|
|
|
116
117
|
delete: 'delete',
|
|
117
118
|
},
|
|
118
119
|
};
|
|
120
|
+
/**
|
|
121
|
+
* v5 B13: the core default policy - list in the caller's site, the other four on own rows only.
|
|
122
|
+
* - override per type with `MyManagerProxy.accessPolicy()`, per controller with `options.policy`.
|
|
123
|
+
*/
|
|
124
|
+
exports.DEFAULT_ACCESS_POLICY = Object.freeze({
|
|
125
|
+
list: 'site',
|
|
126
|
+
read: 'owner',
|
|
127
|
+
create: 'owner',
|
|
128
|
+
update: 'owner',
|
|
129
|
+
delete: 'owner',
|
|
130
|
+
});
|
|
119
131
|
/**
|
|
120
132
|
* class: `MyCoreService`
|
|
121
133
|
* - CoreService의 공통 부분을 채워넣는다.
|
|
@@ -1027,17 +1039,24 @@ class MyCoreProxy extends abstract_service_1.AbstractProxy {
|
|
|
1027
1039
|
const useSession = options?.useSession ?? false;
|
|
1028
1040
|
const throwable = options?.throwable ?? false;
|
|
1029
1041
|
const base = model ?? {};
|
|
1042
|
+
//* v5 B13: copy a non-empty `gid` only (an absent group adds no `gid` key).
|
|
1043
|
+
const _gid = (gid) => {
|
|
1044
|
+
if (base['gid'] === undefined && typeof gid === 'string' && gid)
|
|
1045
|
+
base['gid'] = gid;
|
|
1046
|
+
};
|
|
1030
1047
|
// STEP.0 populate with current parent.
|
|
1031
1048
|
if (options?.parent) {
|
|
1032
1049
|
const parent = options.parent;
|
|
1033
1050
|
base['sid'] = base['sid'] ?? parent?.sid;
|
|
1034
1051
|
base['uid'] = base['uid'] ?? parent?.uid;
|
|
1052
|
+
_gid(parent?.gid); //* v5 B13: `gid` from the parent too.
|
|
1035
1053
|
}
|
|
1036
1054
|
// STEP.1 use session if applicable
|
|
1037
1055
|
if (useSession) {
|
|
1038
1056
|
const parent = this.getCurrentSession({ throwable });
|
|
1039
1057
|
base['sid'] = base['sid'] ?? parent?.sid;
|
|
1040
1058
|
base['uid'] = base['uid'] ?? parent?.uid;
|
|
1059
|
+
_gid(parent?.gid); //* v5 B13: stamp the session `gid` (SPEC § 14.3 create).
|
|
1041
1060
|
}
|
|
1042
1061
|
return base;
|
|
1043
1062
|
}
|
|
@@ -1103,10 +1122,11 @@ class MyManagerProxy extends abstract_service_1.ManagerProxy {
|
|
|
1103
1122
|
const throwable = options?.throwable ?? true;
|
|
1104
1123
|
const errScope = options?.errScope ?? `packSearchParam(${type})`;
|
|
1105
1124
|
const isLocal = engine_1.$U.isLocalMode(); //* v5: drop the `sid` pin only in local mode (B5 § 6.3).
|
|
1106
|
-
|
|
1125
|
+
//* v5 B13: admin is decided before the session, so a session-less admin (IAM SigV4) lists without 403.
|
|
1126
|
+
const isAdmin = useSession && !isLocal ? this.proxy.hasAdminRole('admin') : false;
|
|
1127
|
+
const session = useSession ? this.proxy.getCurrentSession({ throwable: throwable && !isAdmin }) : null;
|
|
1107
1128
|
const _has = (name) => param && (typeof param[name] === 'string' || typeof param[name] === 'number');
|
|
1108
1129
|
const _val = (name) => (param ? commons_1.$T.S2(param[name]) : undefined);
|
|
1109
|
-
const _hasAdm = () => this.proxy.hasAdminRole('admin');
|
|
1110
1130
|
// parse params
|
|
1111
1131
|
const sort = _has('sort') ? commons_1.$T.S2(param?.sort, '') : undefined;
|
|
1112
1132
|
const $page = (0, commons_1.parsePaginateParam)({ ...param, sort }, { limit: options?.limit ?? 10, page: 0 });
|
|
@@ -1126,17 +1146,55 @@ class MyManagerProxy extends abstract_service_1.ManagerProxy {
|
|
|
1126
1146
|
return M;
|
|
1127
1147
|
}, {});
|
|
1128
1148
|
// use w/ `identity-token` (known as session)
|
|
1129
|
-
if (useSession && !isLocal) {
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
$param['sid'] = session?.sid;
|
|
1135
|
-
}
|
|
1149
|
+
if (useSession && !isLocal && isAdmin) {
|
|
1150
|
+
//* admin: `?sid=` (or `0` = own site), else the session site (unchanged).
|
|
1151
|
+
//* v5 B13: a session-less admin (empty `sid`) gets `null` = no site filter, not the `sid`-less rows.
|
|
1152
|
+
const ownSid = session?.sid || null;
|
|
1153
|
+
$param['sid'] = _has('sid') ? (_val('sid') === '0' ? ownSid : _val('sid')) : ownSid;
|
|
1136
1154
|
//* use the current session's uid.
|
|
1137
1155
|
if (_has('uid'))
|
|
1138
1156
|
$param['uid'] = _val('uid') === '0' ? session?.uid : _val('uid');
|
|
1139
1157
|
}
|
|
1158
|
+
else if (useSession && !isLocal) {
|
|
1159
|
+
//* v5 B13: pin per the list scope (SPEC § 14.3 list).
|
|
1160
|
+
const scope = options?.scope ?? this.effectivePolicy().list;
|
|
1161
|
+
const S = { sid: commons_1.$T.S2(session?.sid), uid: commons_1.$T.S2(session?.uid), gid: commons_1.$T.S2(session?.gid) };
|
|
1162
|
+
const _deny = (name) => new Error(`403 NOT ALLOWED - list[${scope}] needs session .${name} @${errScope}`);
|
|
1163
|
+
if (scope === 'any') {
|
|
1164
|
+
//* `any`: no pin, `?sid=` and `?uid=` as given (`0` = the session value).
|
|
1165
|
+
if (_has('sid'))
|
|
1166
|
+
$param['sid'] = _val('sid') === '0' ? session?.sid : _val('sid');
|
|
1167
|
+
if (_has('uid'))
|
|
1168
|
+
$param['uid'] = _val('uid') === '0' ? session?.uid : _val('uid');
|
|
1169
|
+
}
|
|
1170
|
+
else if (scope === 'site' || scope === 'owner' || scope === 'group') {
|
|
1171
|
+
//* every pinned scope needs the session site; an empty one lists nothing (was: no filter).
|
|
1172
|
+
if (!S.sid)
|
|
1173
|
+
throw _deny('sid');
|
|
1174
|
+
$param['sid'] = S.sid;
|
|
1175
|
+
if (scope === 'owner') {
|
|
1176
|
+
//* `owner`: own rows only, `?uid=` is overridden.
|
|
1177
|
+
if (!S.uid)
|
|
1178
|
+
throw _deny('uid');
|
|
1179
|
+
$param['uid'] = S.uid;
|
|
1180
|
+
}
|
|
1181
|
+
else {
|
|
1182
|
+
//* `site`/`group`: `?uid=` stays a narrowing filter (`0` = own uid).
|
|
1183
|
+
if (_has('uid'))
|
|
1184
|
+
$param['uid'] = _val('uid') === '0' ? session?.uid : _val('uid');
|
|
1185
|
+
if (scope === 'group') {
|
|
1186
|
+
//* `group`: the caller's group only.
|
|
1187
|
+
if (!S.gid)
|
|
1188
|
+
throw _deny('gid');
|
|
1189
|
+
$param['gid'] = S.gid;
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
else {
|
|
1194
|
+
//* an unknown scope never lists.
|
|
1195
|
+
throw new Error(`403 NOT ALLOWED - list[${scope ?? ''}] is invalid @${errScope}`);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1140
1198
|
else {
|
|
1141
1199
|
if (_has('sid'))
|
|
1142
1200
|
$param['sid'] = _val('sid');
|
|
@@ -1210,12 +1268,37 @@ class MyManagerProxy extends abstract_service_1.ManagerProxy {
|
|
|
1210
1268
|
const $res = hasId ? this.override($org, $def3) : $org;
|
|
1211
1269
|
return $res; //! return the model with id.
|
|
1212
1270
|
}
|
|
1271
|
+
/**
|
|
1272
|
+
* v5 B13: the default policy of this model type (override per type).
|
|
1273
|
+
* - merged as `{ ...DEFAULT_ACCESS_POLICY, ...accessPolicy(), ...options.policy }`.
|
|
1274
|
+
*
|
|
1275
|
+
* @returns the scope per action
|
|
1276
|
+
*/
|
|
1277
|
+
accessPolicy() {
|
|
1278
|
+
return { ...exports.DEFAULT_ACCESS_POLICY };
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* v5 B13: the effective policy - core default, then `accessPolicy()`, then `policy` (undefined values skipped).
|
|
1282
|
+
*
|
|
1283
|
+
* @param policy (optional) scopes from the caller (ex: controller `options.policy`)
|
|
1284
|
+
* @returns the merged policy
|
|
1285
|
+
*/
|
|
1286
|
+
effectivePolicy(policy) {
|
|
1287
|
+
//* keep only the defined scopes, so `{ read: undefined }` does not erase a default.
|
|
1288
|
+
const _defined = (P) => Object.entries(P ?? {}).reduce((M, [k, v]) => {
|
|
1289
|
+
if (v !== undefined && v !== null)
|
|
1290
|
+
M[k] = v;
|
|
1291
|
+
return M;
|
|
1292
|
+
}, {});
|
|
1293
|
+
return { ...exports.DEFAULT_ACCESS_POLICY, ..._defined(this.accessPolicy()), ..._defined(policy) };
|
|
1294
|
+
}
|
|
1213
1295
|
/**
|
|
1214
1296
|
* Check if the current user can perform the specified action on the given model.
|
|
1215
|
-
* - override this method to implement custom logic.
|
|
1297
|
+
* - override this method to implement custom logic (an override runs before this default).
|
|
1298
|
+
* - v5 B13: with the session on, the effective `AccessPolicy` decides (SPEC § 14.2); with it off, § 6.4 as before.
|
|
1216
1299
|
*
|
|
1217
1300
|
* @param action The action to check.
|
|
1218
|
-
* @param model The model to check against.
|
|
1301
|
+
* @param model The model to check against. (`undefined` for `list` = the caller check only)
|
|
1219
1302
|
* @param options Additional options for the check.
|
|
1220
1303
|
* @returns True if the action is allowed, false otherwise.
|
|
1221
1304
|
*/
|
|
@@ -1228,10 +1311,72 @@ class MyManagerProxy extends abstract_service_1.ManagerProxy {
|
|
|
1228
1311
|
const _act = commons_1.$T.asLut(action, $LUT.CanDoAction, { throwable: false, default: null });
|
|
1229
1312
|
if (!_act || typeof _act !== 'string')
|
|
1230
1313
|
throw new Error(`400 INVALID - action[${action ?? ''}] is invalid @${errScope}`);
|
|
1314
|
+
//* v5 B13: session off → the § 6.4 rules, unchanged (SPEC § 14.3 "세션 꺼짐").
|
|
1315
|
+
if (!useSession)
|
|
1316
|
+
return this.canDoWithoutSession(_act, model, { errScope, throwable, context });
|
|
1317
|
+
//* v5 B13: one way to refuse (throw 403 or return false).
|
|
1318
|
+
const _deny = () => {
|
|
1319
|
+
if (throwable)
|
|
1320
|
+
throw new Error(`403 NOT ALLOWED - action[${_act}] is invalid @${errScope}`);
|
|
1321
|
+
return false;
|
|
1322
|
+
};
|
|
1323
|
+
const hasModel = model !== undefined && model !== null;
|
|
1324
|
+
const M = { sid: commons_1.$T.S2(model?.sid), uid: commons_1.$T.S2(model?.uid), gid: commons_1.$T.S2(model?.gid) };
|
|
1325
|
+
const legacy = engine_1.$U.sidLegacyAccess();
|
|
1326
|
+
//* v5 B13 (1): `deny` refuses update/delete of a `sid`-less record before the admin pass (B5 § 6.4, kept).
|
|
1327
|
+
if (hasModel && !M.sid && (_act === 'update' || _act === 'delete') && legacy === 'deny')
|
|
1328
|
+
return _deny();
|
|
1329
|
+
//* v5 B13 (2): admin before the session fetch - IAM SigV4 and `roles: ['admin']` claims pass (SPEC § 14.3).
|
|
1330
|
+
if (this.proxy.hasAdminRole(null, { errScope, context }))
|
|
1331
|
+
return true;
|
|
1332
|
+
//* v5 B13 (3): the session is required (throwable → the current `403 IDENTITY-TOKEN` messages).
|
|
1333
|
+
const $sess = this.proxy.getCurrentSession({ throwable, useSession, context });
|
|
1334
|
+
if (!$sess)
|
|
1335
|
+
return _deny();
|
|
1336
|
+
//* v5 B13 (4): caller state - a role holder with a site and a user (T-20, T-21, T-22).
|
|
1337
|
+
const S = { sid: commons_1.$T.S2($sess?.sid), uid: commons_1.$T.S2($sess?.uid), gid: commons_1.$T.S2($sess?.gid) };
|
|
1338
|
+
const hasRole = $sess?.roles?.length > 0 ? true : false; // guest if empty.
|
|
1339
|
+
if (!hasRole || !S.uid || !S.sid)
|
|
1340
|
+
return _deny();
|
|
1341
|
+
//* v5 B13 (6): `list` without a model = the caller check only; the rows are pinned by `packSearchParam()`.
|
|
1342
|
+
if (_act === 'list' && !hasModel)
|
|
1343
|
+
return true;
|
|
1344
|
+
//* v5 B13 (5): the scope of this action against the row.
|
|
1345
|
+
const scope = this.effectivePolicy(options?.policy)[_act];
|
|
1346
|
+
if (scope === 'any')
|
|
1347
|
+
return true;
|
|
1348
|
+
//* a `sid`-less row → `SID_LEGACY_ACCESS` (`open` = v4, else admin only) (T-25, T-26, T-27).
|
|
1349
|
+
if (!M.sid)
|
|
1350
|
+
return legacy === 'open' ? true : _deny();
|
|
1351
|
+
switch (scope) {
|
|
1352
|
+
case 'owner':
|
|
1353
|
+
//* same site and same non-empty user (an empty `uid` never matches, T-24).
|
|
1354
|
+
return S.sid === M.sid && S.uid === M.uid && !!S.uid ? true : _deny();
|
|
1355
|
+
case 'group':
|
|
1356
|
+
//* same site and same non-empty group.
|
|
1357
|
+
return S.sid === M.sid && S.gid === M.gid && !!S.gid ? true : _deny();
|
|
1358
|
+
case 'site':
|
|
1359
|
+
//* same non-empty site.
|
|
1360
|
+
return S.sid === M.sid && !!S.sid ? true : _deny();
|
|
1361
|
+
default:
|
|
1362
|
+
//* an unknown scope never allows.
|
|
1363
|
+
return _deny();
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
/**
|
|
1367
|
+
* the `canDo()` rules with the session off (v5 § 6.4, unchanged by B13).
|
|
1368
|
+
* - `list`/`read`/`create`: same `sid` or a `sid`-less row; `update`/`delete`: same `sid` and `uid`.
|
|
1369
|
+
*
|
|
1370
|
+
* @param _act the validated action
|
|
1371
|
+
* @param model the model to check against
|
|
1372
|
+
* @param options { errScope, throwable, context }
|
|
1373
|
+
* @returns True if the action is allowed, false otherwise.
|
|
1374
|
+
*/
|
|
1375
|
+
canDoWithoutSession(_act, model, options) {
|
|
1376
|
+
const { errScope, throwable, context } = options;
|
|
1377
|
+
const useSession = false;
|
|
1231
1378
|
// no session but required.
|
|
1232
1379
|
const $sess = this.proxy.getCurrentSession({ throwable, useSession, context });
|
|
1233
|
-
if (useSession && !$sess)
|
|
1234
|
-
return false;
|
|
1235
1380
|
// session & model information.
|
|
1236
1381
|
const S = { sid: commons_1.$T.S2($sess?.sid), uid: commons_1.$T.S2($sess?.uid) };
|
|
1237
1382
|
const M = { sid: commons_1.$T.S2(model?.sid), uid: commons_1.$T.S2(model?.uid) };
|