@futdevpro/fsm-dynamo 1.20.67 → 1.20.68
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/build/_collections/utils/operation-authz.util.d.ts.map +1 -1
- package/build/_collections/utils/operation-authz.util.js +14 -7
- package/build/_collections/utils/operation-authz.util.js.map +1 -1
- package/build/_models/interfaces/operation-authz-result.interface.d.ts +7 -0
- package/build/_models/interfaces/operation-authz-result.interface.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operation-authz.util.d.ts","sourceRoot":"","sources":["../../../src/_collections/utils/operation-authz.util.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kCAAkC,EACnC,MAAM,8DAA8D,CAAC;AAEtE,OAAO,EACL,mCAAmC,EACpC,MAAM,+DAA+D,CAAC;AACvE,OAAO,EAAE,0BAA0B,EAAE,MAAM,2DAA2D,CAAC;AAGvG;;;;;;;;;;;;;GAaG;AACH,qBAAa,wBAAwB;IACnC;;;;OAIG;IACH,MAAM,CAAC,KAAK,CACV,SAAS,EAAE,mCAAmC,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAC3E,GAAG,EAAE,kCAAkC,GACtC,0BAA0B;
|
|
1
|
+
{"version":3,"file":"operation-authz.util.d.ts","sourceRoot":"","sources":["../../../src/_collections/utils/operation-authz.util.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kCAAkC,EACnC,MAAM,8DAA8D,CAAC;AAEtE,OAAO,EACL,mCAAmC,EACpC,MAAM,+DAA+D,CAAC;AACvE,OAAO,EAAE,0BAA0B,EAAE,MAAM,2DAA2D,CAAC;AAGvG;;;;;;;;;;;;;GAaG;AACH,qBAAa,wBAAwB;IACnC;;;;OAIG;IACH,MAAM,CAAC,KAAK,CACV,SAAS,EAAE,mCAAmC,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAC3E,GAAG,EAAE,kCAAkC,GACtC,0BAA0B;IAkD7B;;;OAGG;IACH,MAAM,CAAC,MAAM,CACX,SAAS,EAAE,mCAAmC,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAC3E,GAAG,EAAE,kCAAkC,GACtC,0BAA0B;IAM7B;;;;;OAKG;IACH,MAAM,CAAC,cAAc,CACnB,SAAS,EAAE,mCAAmC,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAC3E,GAAG,EAAE,kCAAkC,EACvC,MAAM,EAAE,MAAM,GACb,0BAA0B;IAgC7B,2FAA2F;IAC3F,MAAM,CAAC,eAAe,CACpB,SAAS,EAAE,mCAAmC,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAC3E,GAAG,EAAE,kCAAkC,EACvC,MAAM,EAAE,MAAM,GACb,0BAA0B;IAM7B,8BAA8B;IAC9B,OAAO,CAAC,MAAM,CAAC,IAAI;IAQnB,8FAA8F;IAC9F,OAAO,CAAC,MAAM,CAAC,aAAa;CAsB7B"}
|
|
@@ -29,7 +29,7 @@ class DyFM_OperationAuthz_Util {
|
|
|
29
29
|
const authKind = ctx?.authKind ?? operation_auth_type_enum_1.DyFM_OperationAuth_Type.none;
|
|
30
30
|
// a missing identity is 401, the caller may retry with credentials
|
|
31
31
|
if (issuerRequired && (authKind === operation_auth_type_enum_1.DyFM_OperationAuth_Type.none || !ctx?.issuer)) {
|
|
32
|
-
return DyFM_OperationAuthz_Util.deny('DyFM-OPZ-UNA', 401, `operation "${operation?.name}" requires an authenticated caller
|
|
32
|
+
return DyFM_OperationAuthz_Util.deny('DyFM-OPZ-UNA', 401, `operation "${operation?.name}" requires an authenticated caller`, 'This operation needs an authenticated caller — send an API key or a token.');
|
|
33
33
|
}
|
|
34
34
|
// scopes only restrict API keys; a token call is not scope-limited
|
|
35
35
|
if (authKind !== operation_auth_type_enum_1.DyFM_OperationAuth_Type.apiKey) {
|
|
@@ -46,11 +46,12 @@ class DyFM_OperationAuthz_Util {
|
|
|
46
46
|
}
|
|
47
47
|
// least privilege: a scoped key can not reach a protected operation that belongs to no scope
|
|
48
48
|
if (!requiredScope) {
|
|
49
|
-
return DyFM_OperationAuthz_Util.deny('DyFM-OPZ-NSC', 403, `operation "${operation?.name}" declares no apiKeyScope, a scoped API key can not call it
|
|
49
|
+
return DyFM_OperationAuthz_Util.deny('DyFM-OPZ-NSC', 403, `operation "${operation?.name}" declares no apiKeyScope, a scoped API key can not call it`, 'This operation can not be called with an API key. Call it with a user token.');
|
|
50
50
|
}
|
|
51
51
|
// exact match only — no wildcard until it is an explicit decision
|
|
52
52
|
if (!(ctx.apiKeyScopes ?? []).includes(requiredScope)) {
|
|
53
|
-
return DyFM_OperationAuthz_Util.deny('DyFM-OPZ-SCP', 403, `API key lacks scope "${requiredScope}" for operation "${operation?.name}"`
|
|
53
|
+
return DyFM_OperationAuthz_Util.deny('DyFM-OPZ-SCP', 403, `API key lacks scope "${requiredScope}" for operation "${operation?.name}"`, `The API key is missing the "${requiredScope}" scope, which this operation needs. ` +
|
|
54
|
+
'Create a key that has it (an existing key\'s scopes can not be widened).');
|
|
54
55
|
}
|
|
55
56
|
return { allowed: true };
|
|
56
57
|
}
|
|
@@ -75,12 +76,14 @@ class DyFM_OperationAuthz_Util {
|
|
|
75
76
|
}
|
|
76
77
|
// a declared ownership check without a caller identity must fail closed, not pass
|
|
77
78
|
if (!ctx?.clientUserId) {
|
|
78
|
-
return DyFM_OperationAuthz_Util.deny('DyFM-OPZ-OWN', 403, `operation "${operation?.name}" requires the caller's clientUserId for the ownership check
|
|
79
|
+
return DyFM_OperationAuthz_Util.deny('DyFM-OPZ-OWN', 403, `operation "${operation?.name}" requires the caller's clientUserId for the ownership check`, 'This operation works on your own data, so it needs to know which user you are.');
|
|
79
80
|
}
|
|
80
81
|
const owner = target ? Reflect.get(target, ownershipField) : undefined;
|
|
81
82
|
// strict equality: an entity without owner is not owned by anybody
|
|
82
83
|
if (owner === undefined || owner === null || String(owner) !== ctx.clientUserId) {
|
|
83
|
-
return DyFM_OperationAuthz_Util.deny('DyFM-OPZ-OWN', 403, `caller does not own the target of operation "${operation?.name}" (field: ${ownershipField})
|
|
84
|
+
return DyFM_OperationAuthz_Util.deny('DyFM-OPZ-OWN', 403, `caller does not own the target of operation "${operation?.name}" (field: ${ownershipField})`,
|
|
85
|
+
// ⛔ the owner and the field name stay inside: the caller only learns that it is not theirs
|
|
86
|
+
'This item belongs to somebody else.');
|
|
84
87
|
}
|
|
85
88
|
return { allowed: true };
|
|
86
89
|
}
|
|
@@ -89,8 +92,10 @@ class DyFM_OperationAuthz_Util {
|
|
|
89
92
|
return DyFM_OperationAuthz_Util.throwIfDenied(DyFM_OperationAuthz_Util.checkOwnership(operation, ctx, target), operation, ctx);
|
|
90
93
|
}
|
|
91
94
|
/** Builds a denial result. */
|
|
92
|
-
static deny(errorCode, status, reason) {
|
|
93
|
-
return {
|
|
95
|
+
static deny(errorCode, status, reason, userMessage) {
|
|
96
|
+
return {
|
|
97
|
+
allowed: false, errorCode: errorCode, status: status, reason: reason, userMessage: userMessage,
|
|
98
|
+
};
|
|
94
99
|
}
|
|
95
100
|
/** Converts a denial into a thrown `DyFM_Error`; the identity is logged by requestId only. */
|
|
96
101
|
static throwIfDenied(result, operation, ctx) {
|
|
@@ -101,6 +106,8 @@ class DyFM_OperationAuthz_Util {
|
|
|
101
106
|
errorCode: result.errorCode,
|
|
102
107
|
status: result.status,
|
|
103
108
|
message: `Operation authorization failed: ${result.reason}`,
|
|
109
|
+
// ⛔ the internal `message` never reaches the caller — this is the text written FOR them
|
|
110
|
+
userMessage: result.userMessage,
|
|
104
111
|
additionalContent: {
|
|
105
112
|
operation: operation?.name,
|
|
106
113
|
requestId: ctx?.requestId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operation-authz.util.js","sourceRoot":"","sources":["../../../src/_collections/utils/operation-authz.util.ts"],"names":[],"mappings":";;;AAAA,oFAAgF;AAChF,kHAEsE;AACtE,0FAA8E;AAO9E;;;;;;;;;;;;;GAaG;AACH,MAAa,wBAAwB;IACnC;;;;OAIG;IACH,MAAM,CAAC,KAAK,CACV,SAA2E,EAC3E,GAAuC;QAEvC,MAAM,cAAc,GAAY,SAAS,EAAE,KAAK,EAAE,cAAc,KAAK,KAAK,CAAC;QAC3E,MAAM,QAAQ,GAA4B,GAAG,EAAE,QAAQ,IAAI,kDAAuB,CAAC,IAAI,CAAC;QAExF,mEAAmE;QACnE,IAAI,cAAc,IAAI,CAAC,QAAQ,KAAK,kDAAuB,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC;YAClF,OAAO,wBAAwB,CAAC,IAAI,CAClC,cAAc,EAAE,GAAG,EAAE,cAAc,SAAS,EAAE,IAAI,oCAAoC,
|
|
1
|
+
{"version":3,"file":"operation-authz.util.js","sourceRoot":"","sources":["../../../src/_collections/utils/operation-authz.util.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,6 +17,13 @@ export interface DyFM_OperationAuthz_Result {
|
|
|
17
17
|
status?: 401 | 403;
|
|
18
18
|
/** Human-readable reason of the denial. */
|
|
19
19
|
reason?: string;
|
|
20
|
+
/**
|
|
21
|
+
* What the CALLER is told (HP-DOPL MP-5 closing review). The internal `reason` never leaves the server, so
|
|
22
|
+
* without this the caller only sees a generic text with the error code — and a key-based integration would
|
|
23
|
+
* not learn the ONE actionable fact: which scope it is missing. The scope name is part of the operation's
|
|
24
|
+
* own contract, not a secret (this is what `WWW-Authenticate: scope="…"` does).
|
|
25
|
+
*/
|
|
26
|
+
userMessage?: string;
|
|
20
27
|
/** Set when the call is allowed only through the legacy, scope-less API key path (D-6). */
|
|
21
28
|
warning?: 'legacy-api-key';
|
|
22
29
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operation-authz-result.interface.d.ts","sourceRoot":"","sources":["../../../src/_models/interfaces/operation-authz-result.interface.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4FAA4F;IAC5F,MAAM,CAAC,EAAE,GAAG,GAAG,GAAG,CAAC;IACnB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2FAA2F;IAC3F,OAAO,CAAC,EAAE,gBAAgB,CAAC;CAC5B"}
|
|
1
|
+
{"version":3,"file":"operation-authz-result.interface.d.ts","sourceRoot":"","sources":["../../../src/_models/interfaces/operation-authz-result.interface.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4FAA4F;IAC5F,MAAM,CAAC,EAAE,GAAG,GAAG,GAAG,CAAC;IACnB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2FAA2F;IAC3F,OAAO,CAAC,EAAE,gBAAgB,CAAC;CAC5B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@futdevpro/fsm-dynamo",
|
|
3
|
-
"version": "1.20.
|
|
3
|
+
"version": "1.20.68",
|
|
4
4
|
"description": "Full Stack Model Collection for Dynamic (NodeJS-Typescript) Framework called Dynamo, by Future Development Ltd.",
|
|
5
5
|
"DyBu_settings": {
|
|
6
6
|
"packageType": "full-stack-package",
|