@nextage/era-lib 1.0.218 → 1.0.220

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.
@@ -0,0 +1,38 @@
1
+ /*********************************************************************************************
2
+ * *
3
+ * The `@auth` directives of ERA - the framework directive, fed with the EFFECTIVE roles. *
4
+ * *
5
+ * The framework directive checks `user.hasRole(requires)`, that is `roles[]`: the roles of *
6
+ * the organization the user BELONGS to. On an organization reached through a grant those *
7
+ * are the wrong roles. These directives keep the framework's check - authenticated, active, *
8
+ * one of the required roles - and hand it the roles that actually hold, computed by the *
9
+ * single rule in `scope.ts` (`effectiveRoles`). *
10
+ * *
11
+ * Two of them, because the two kinds of service ask two different questions: *
12
+ * *
13
+ * tenantAuthDirective - a request that works inside ONE organization, the selected one *
14
+ * or the user's own (app-srv): the roles there decide. *
15
+ * reachableAuthDirective - a request whose operations NAME their organization in the *
16
+ * arguments (auth-srv): the directive cannot know it, so it only *
17
+ * asks whether the role holds SOMEWHERE, and the operation *
18
+ * decides on its own organization with `assertOrgRole`. *
19
+ * *
20
+ *********************************************************************************************/
21
+ /**
22
+ * `@auth` for a service whose requests work inside one organization: the roles that hold there.
23
+ */
24
+ export declare const tenantAuthDirective: {
25
+ name: string;
26
+ typeDefs: string;
27
+ transformer: (schema: import("graphql").GraphQLSchema) => import("graphql").GraphQLSchema;
28
+ };
29
+ /**
30
+ * `@auth` for a service whose operations name their organization: the roles that hold on at
31
+ * least one reachable organization. The operation must still decide on its own organization.
32
+ */
33
+ export declare const reachableAuthDirective: {
34
+ name: string;
35
+ typeDefs: string;
36
+ transformer: (schema: import("graphql").GraphQLSchema) => import("graphql").GraphQLSchema;
37
+ };
38
+ //# sourceMappingURL=auth-directive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-directive.d.ts","sourceRoot":"","sources":["../../src/utils/auth-directive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;+FAmB+F;AA2B/F;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;CAE/B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,sBAAsB;;;;CAElC,CAAC"}
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ /*********************************************************************************************
3
+ * *
4
+ * The `@auth` directives of ERA - the framework directive, fed with the EFFECTIVE roles. *
5
+ * *
6
+ * The framework directive checks `user.hasRole(requires)`, that is `roles[]`: the roles of *
7
+ * the organization the user BELONGS to. On an organization reached through a grant those *
8
+ * are the wrong roles. These directives keep the framework's check - authenticated, active, *
9
+ * one of the required roles - and hand it the roles that actually hold, computed by the *
10
+ * single rule in `scope.ts` (`effectiveRoles`). *
11
+ * *
12
+ * Two of them, because the two kinds of service ask two different questions: *
13
+ * *
14
+ * tenantAuthDirective - a request that works inside ONE organization, the selected one *
15
+ * or the user's own (app-srv): the roles there decide. *
16
+ * reachableAuthDirective - a request whose operations NAME their organization in the *
17
+ * arguments (auth-srv): the directive cannot know it, so it only *
18
+ * asks whether the role holds SOMEWHERE, and the operation *
19
+ * decides on its own organization with `assertOrgRole`. *
20
+ * *
21
+ *********************************************************************************************/
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.reachableAuthDirective = exports.tenantAuthDirective = void 0;
24
+ const nx_frame_be_1 = require("@nextage/nx-frame-be");
25
+ const scope_1 = require("./scope");
26
+ const tenant_1 = require("./tenant");
27
+ /**
28
+ * A stand-in of the request user that answers `hasRole` with the given roles.
29
+ *
30
+ * The directive reads `id`, `active` and `hasRole` and nothing else; the user itself is left
31
+ * untouched, so every later check still sees its memberships, grants and roles.
32
+ *
33
+ * @param user the authenticated user
34
+ * @param roles the roles that hold for this check
35
+ * @returns the user as the directive must see it
36
+ */
37
+ function withRoles(user, roles) {
38
+ return {
39
+ id: user.id,
40
+ active: user.active,
41
+ roles,
42
+ hasRole: (role) => (Array.isArray(role) ? role : [role]).some(r => roles.includes(r))
43
+ };
44
+ }
45
+ /**
46
+ * `@auth` for a service whose requests work inside one organization: the roles that hold there.
47
+ */
48
+ exports.tenantAuthDirective = (0, nx_frame_be_1.createAuthDirective)('auth', (context) => context.user ? withRoles(context.user, (0, tenant_1.tenantRoles)(context)) : null);
49
+ /**
50
+ * `@auth` for a service whose operations name their organization: the roles that hold on at
51
+ * least one reachable organization. The operation must still decide on its own organization.
52
+ */
53
+ exports.reachableAuthDirective = (0, nx_frame_be_1.createAuthDirective)('auth', (context) => context.user ? withRoles(context.user, (0, scope_1.reachableRoles)(context.user)) : null);
54
+ //# sourceMappingURL=auth-directive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-directive.js","sourceRoot":"","sources":["../../src/utils/auth-directive.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;+FAmB+F;;;AAE/F,sDAAgF;AAEhF,mCAAmE;AACnE,qCAAoE;AAEpE;;;;;;;;;GASG;AACH,SAAS,SAAS,CAAC,IAAc,EAAE,KAAe;IAEhD,OAAO;QACL,EAAE,EAAO,IAAI,CAAC,EAAE;QAChB,MAAM,EAAG,IAAI,CAAC,MAAM;QACpB,KAAK;QACL,OAAO,EAAE,CAAC,IAAuB,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;KAC7F,CAAC;AAChB,CAAC;AAED;;GAEG;AACU,QAAA,mBAAmB,GAAG,IAAA,iCAAmB,EAAC,MAAM,EAAE,CAAC,OAAkB,EAAE,EAAE,CACpF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,IAAA,oBAAW,EAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CACpE,CAAC;AAEF;;;GAGG;AACU,QAAA,sBAAsB,GAAG,IAAA,iCAAmB,EAAC,MAAM,EAAE,CAAC,OAAkB,EAAE,EAAE,CACvF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,IAAA,sBAAc,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAC5E,CAAC"}
@@ -49,9 +49,15 @@ export declare function sendErrorResponse(res: Response, err: any): void;
49
49
  */
50
50
  export declare function allowMethods(methods?: string[], message?: string): Handler;
51
51
  /**
52
+ * Authorizes a REST route: an authenticated user and, when `roles` is given, the roles it needs.
52
53
  *
53
- * @param {*} roles
54
- * @param {*} condition
54
+ * The roles are the ones of the REQUEST (`tenantRoles`): those that hold on the organization the
55
+ * request operates on, as on the GraphQL side - a grant decides on the organization it grants,
56
+ * and the membership role never travels to another one.
57
+ *
58
+ * @param roles the roles the route requires, when any
59
+ * @param condition `'&&'` for all of them, anything else for any of them
60
+ * @returns the Express middleware
55
61
  */
56
62
  export declare function authHandler(roles?: string[], condition?: string): (req: Request, res: Response, next: NextFunction) => void;
57
63
  //# sourceMappingURL=express.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/utils/express.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEnE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,MAAe,mBAAmB,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,MAA6B,0CAA0C,CAAC;AAIpG;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,iBAAiB,CAAC,EAAE,cAAc,IAAI,KAAK,MAAM,CAAC,eAAe,CAAC,EAAE,KAAK,OAAO,4BAAQ,IAE5H,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,UAYxD;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,GAAE,MAAY,EAAE,OAAO,GAAE,MAAW,QAMzF;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAoB/D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,MAAM,EAAO,EAAE,OAAO,GAAE,MAA6B,GAAG,OAAO,CAcpG;AAoBD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE,SAAS,CAAC,EAAE,MAAM,IAEtD,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,UAiCxD"}
1
+ {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/utils/express.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEnE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,MAAe,mBAAmB,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,MAA6B,0CAA0C,CAAC;AAKpG;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,iBAAiB,CAAC,EAAE,cAAc,IAAI,KAAK,MAAM,CAAC,eAAe,CAAC,EAAE,KAAK,OAAO,4BAAQ,IAE5H,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,UAYxD;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,GAAE,MAAY,EAAE,OAAO,GAAE,MAAW,QAMzF;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAoB/D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,MAAM,EAAO,EAAE,OAAO,GAAE,MAA6B,GAAG,OAAO,CAcpG;AAoBD;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE,SAAS,CAAC,EAAE,MAAM,IAEtD,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,UAmCxD"}
@@ -12,6 +12,7 @@ const http_errors_1 = __importDefault(require("http-errors"));
12
12
  const express_validator_1 = require("express-validator");
13
13
  const nx_frame_be_1 = require("@nextage/nx-frame-be");
14
14
  const constants_1 = require("../constants");
15
+ const tenant_1 = require("./tenant");
15
16
  /**
16
17
  *
17
18
  * @param schema
@@ -114,13 +115,20 @@ function normalizeAllowedMethods(methods) {
114
115
  .map(method => method.toUpperCase());
115
116
  }
116
117
  /**
118
+ * Authorizes a REST route: an authenticated user and, when `roles` is given, the roles it needs.
117
119
  *
118
- * @param {*} roles
119
- * @param {*} condition
120
+ * The roles are the ones of the REQUEST (`tenantRoles`): those that hold on the organization the
121
+ * request operates on, as on the GraphQL side - a grant decides on the organization it grants,
122
+ * and the membership role never travels to another one.
123
+ *
124
+ * @param roles the roles the route requires, when any
125
+ * @param condition `'&&'` for all of them, anything else for any of them
126
+ * @returns the Express middleware
120
127
  */
121
128
  function authHandler(roles, condition) {
122
129
  return (req, res, next) => {
123
- const user = (0, nx_frame_be_1.getAttr)(req, 'context.user');
130
+ const context = (0, nx_frame_be_1.getAttr)(req, 'context');
131
+ const user = context?.user;
124
132
  // On rejection we terminate the chain by WRITING the response body and returning.
125
133
  // We must NOT also `next(err)`/`throw`: the framework error classes carry the
126
134
  // code in `extensions.code` (GraphQL), not `.status`, so the REST error handler
@@ -130,14 +138,15 @@ function authHandler(roles, condition) {
130
138
  if (!user)
131
139
  return sendJSONResponse(res, 401, constants_1.RES_CODE.AUTH_REQUIRED);
132
140
  if (roles) {
141
+ const held = (0, tenant_1.tenantRoles)(context);
133
142
  let hasRoles = true;
134
143
  switch (condition) {
135
144
  case '&&':
136
- hasRoles = roles.every(role => user.roles.indexOf(role) >= 0);
145
+ hasRoles = roles.every(role => held.includes(role));
137
146
  break;
138
147
  case '||':
139
148
  default:
140
- hasRoles = roles.some(role => user.roles.indexOf(role) >= 0);
149
+ hasRoles = roles.some(role => held.includes(role));
141
150
  break;
142
151
  }
143
152
  if (!hasRoles)
@@ -1 +1 @@
1
- {"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/utils/express.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/utils/express.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ export * from './auth-directive';
1
2
  export * from './claims';
2
3
  export * from './claims.interfaces';
3
4
  export * from './domain';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,OAAO,CAAC;AACtB,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,OAAO,CAAC;AACtB,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC"}
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./auth-directive"), exports);
17
18
  __exportStar(require("./claims"), exports);
18
19
  __exportStar(require("./claims.interfaces"), exports);
19
20
  __exportStar(require("./domain"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,sDAAoC;AACpC,2CAAyB;AACzB,4CAA0B;AAC1B,2CAAyB;AACzB,wCAAsB;AACtB,kDAAgC;AAChC,mDAAiC;AACjC,0CAAwB;AACxB,qDAAmC;AACnC,kDAAgC;AAChC,4CAA0B;AAC1B,2CAAyB;AACzB,sDAAoC;AACpC,4DAA0C"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mDAAiC;AACjC,2CAAyB;AACzB,sDAAoC;AACpC,2CAAyB;AACzB,4CAA0B;AAC1B,2CAAyB;AACzB,wCAAsB;AACtB,kDAAgC;AAChC,mDAAiC;AACjC,0CAAwB;AACxB,qDAAmC;AACnC,kDAAgC;AAChC,4CAA0B;AAC1B,2CAAyB;AACzB,sDAAoC;AACpC,4DAA0C"}
@@ -50,6 +50,69 @@ export declare function resolveOrgScope(user?: BaseUser, orgId?: string): OrgSco
50
50
  * @throws `AppError('messages.authorization.missingRole')` when out of scope
51
51
  */
52
52
  export declare function assertOrgScope(user?: BaseUser, orgId?: string): OrgScope;
53
+ /**
54
+ * The roles that apply to `user` while operating on the organization `orgId`.
55
+ *
56
+ * THE single definition of the EFFECTIVE ORGANIZATION ROLE. A user holds one organization-tier
57
+ * role in `roles[]`, and that role belongs to the organization they are a MEMBER of; a grant
58
+ * carries its own role, which belongs to the granted organization alone. Reading `roles[]` on a
59
+ * granted organization - what every check did - handed the membership role to an organization
60
+ * that never conferred it: a manager granted read-only access wrote and managed, and a member
61
+ * granted management could not.
62
+ *
63
+ * Built on `resolveOrgScope`, so the answer follows the same tiers:
64
+ *
65
+ * PROVIDER (cross-tenant role) -> the user's roles, unchanged: the level reaches every tenant
66
+ * MEMBER of `orgId` -> the user's roles, unchanged: the membership role is theirs
67
+ * GRANTED on `orgId` -> the roles OUTSIDE the organization tier, plus the grant's role
68
+ * unreachable `orgId` -> the roles outside the organization tier, and no other
69
+ *
70
+ * System and application roles (`ADMIN`, `APP_CONFIG`, ...) are never narrowed: they are not a
71
+ * role on an organization, and they follow the user everywhere.
72
+ *
73
+ * @param user the authenticated user (`NxContext.user`)
74
+ * @param orgId the organization being operated on
75
+ * @returns the roles that hold on that organization
76
+ */
77
+ export declare function effectiveRoles(user?: BaseUser, orgId?: string): string[];
78
+ /**
79
+ * Whether `user` reaches the organization `orgId` AND holds one of `roles` there.
80
+ *
81
+ * The question every per-organization capability asks - "may this user do THIS on THAT
82
+ * organization?" - answered with the effective role, never with `roles[]`.
83
+ *
84
+ * @param user the authenticated user (`NxContext.user`)
85
+ * @param orgId the organization the operation targets
86
+ * @param roles the roles that grant the capability (any of them is enough)
87
+ * @returns `true` when the organization is reachable and one of the roles holds there
88
+ */
89
+ export declare function hasOrgRole(user: BaseUser | undefined, orgId: string | undefined, roles: readonly string[]): boolean;
90
+ /**
91
+ * Throwing variant of `hasOrgRole`, for the call sites that must simply deny.
92
+ *
93
+ * The error is the one of `assertOrgScope`, for the same reason: an organization out of reach,
94
+ * one that does not exist and one where the role does not hold are not told apart.
95
+ *
96
+ * @param user the authenticated user (`NxContext.user`)
97
+ * @param orgId the organization the operation targets
98
+ * @param roles the roles that grant the capability
99
+ * @returns the scope through which the user reaches the organization
100
+ * @throws `AppError('messages.authorization.missingRole')` when the capability does not hold
101
+ */
102
+ export declare function assertOrgRole(user: BaseUser | undefined, orgId: string | undefined, roles: readonly string[]): OrgScope;
103
+ /**
104
+ * Every role `user` holds on AT LEAST ONE organization they reach.
105
+ *
106
+ * For a gate that runs before the organization of the operation is known - the `@auth`
107
+ * directive of a service whose operations name their organization in the arguments. It is the
108
+ * union of the effective roles over the reachable organizations, so it answers "could this user
109
+ * be allowed somewhere?"; the operation itself must then decide on its own organization with
110
+ * `hasOrgRole`/`assertOrgRole`.
111
+ *
112
+ * @param user the authenticated user (`NxContext.user`)
113
+ * @returns the user's roles plus the roles of their grants
114
+ */
115
+ export declare function reachableRoles(user?: BaseUser): string[];
53
116
  /**
54
117
  * Every organization the user reaches, for the LIST case.
55
118
  *
@@ -72,4 +135,25 @@ export declare function assertOrgScope(user?: BaseUser, orgId?: string): OrgScop
72
135
  * @returns `undefined` for no constraint, otherwise the exact set of reachable ids
73
136
  */
74
137
  export declare function reachableOrgIds(user?: BaseUser): string[] | undefined;
138
+ /**
139
+ * Every organization the user reaches where one of `roles` holds, for the LIST case of a capability.
140
+ *
141
+ * `hasOrgRole` answers about ONE organization named by the request; this answers "on which ones
142
+ * does the capability hold at all?", which is what a list scoped to a capability needs - the users
143
+ * a caller administers, the invitations a caller manages. It is `reachableOrgIds` narrowed by
144
+ * `hasOrgRole`, so a list never shows an organization the point check would then deny, and the
145
+ * role that decides on each organization is its effective one: a grant decides on what it grants.
146
+ *
147
+ * Same three outcomes as `reachableOrgIds`, and the caller MUST tell them apart:
148
+ *
149
+ * `undefined` -> no constraint: a cross-tenant user holding one of `roles`, which then holds on
150
+ * every organization (its effective roles are its own everywhere)
151
+ * `string[]` -> exactly these ids, never any other
152
+ * `[]` -> the capability holds nowhere; the caller must yield an EMPTY result, never all
153
+ *
154
+ * @param user the authenticated user (`NxContext.user`)
155
+ * @param roles the roles that grant the capability (any of them is enough)
156
+ * @returns `undefined` for no constraint, otherwise the exact set of ids where the capability holds
157
+ */
158
+ export declare function orgIdsWithRole(user: BaseUser | undefined, roles: readonly string[]): string[] | undefined;
75
159
  //# sourceMappingURL=scope.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../src/utils/scope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;+FAa+F;AAE/F,OAAO,EAAY,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAM1D,OAAO,EAAE,QAAQ,EAAE,MAAgB,oBAAoB,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAqBhF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,CAQxE;AAcD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,EAAE,GAAG,SAAS,CAcrE"}
1
+ {"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../src/utils/scope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;+FAa+F;AAE/F,OAAO,EAAY,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAM1D,OAAO,EAAE,QAAQ,EAAE,MAAgB,oBAAoB,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAqBhF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,CAQxE;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,cAAc,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAWxE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAGnH;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,QAAQ,CAQvH;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,EAAE,CAOxD;AAcD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,EAAE,GAAG,SAAS,CAcrE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,SAAS,CAQzG"}
@@ -16,7 +16,12 @@
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.resolveOrgScope = resolveOrgScope;
18
18
  exports.assertOrgScope = assertOrgScope;
19
+ exports.effectiveRoles = effectiveRoles;
20
+ exports.hasOrgRole = hasOrgRole;
21
+ exports.assertOrgRole = assertOrgRole;
22
+ exports.reachableRoles = reachableRoles;
19
23
  exports.reachableOrgIds = reachableOrgIds;
24
+ exports.orgIdsWithRole = orgIdsWithRole;
20
25
  const nx_frame_be_1 = require("@nextage/nx-frame-be");
21
26
  const constants_1 = require("../constants");
22
27
  const constants_2 = require("../constants");
@@ -77,6 +82,87 @@ function assertOrgScope(user, orgId) {
77
82
  throw new nx_frame_be_1.AppError('messages.authorization.missingRole');
78
83
  return scope;
79
84
  }
85
+ /**
86
+ * The roles that apply to `user` while operating on the organization `orgId`.
87
+ *
88
+ * THE single definition of the EFFECTIVE ORGANIZATION ROLE. A user holds one organization-tier
89
+ * role in `roles[]`, and that role belongs to the organization they are a MEMBER of; a grant
90
+ * carries its own role, which belongs to the granted organization alone. Reading `roles[]` on a
91
+ * granted organization - what every check did - handed the membership role to an organization
92
+ * that never conferred it: a manager granted read-only access wrote and managed, and a member
93
+ * granted management could not.
94
+ *
95
+ * Built on `resolveOrgScope`, so the answer follows the same tiers:
96
+ *
97
+ * PROVIDER (cross-tenant role) -> the user's roles, unchanged: the level reaches every tenant
98
+ * MEMBER of `orgId` -> the user's roles, unchanged: the membership role is theirs
99
+ * GRANTED on `orgId` -> the roles OUTSIDE the organization tier, plus the grant's role
100
+ * unreachable `orgId` -> the roles outside the organization tier, and no other
101
+ *
102
+ * System and application roles (`ADMIN`, `APP_CONFIG`, ...) are never narrowed: they are not a
103
+ * role on an organization, and they follow the user everywhere.
104
+ *
105
+ * @param user the authenticated user (`NxContext.user`)
106
+ * @param orgId the organization being operated on
107
+ * @returns the roles that hold on that organization
108
+ */
109
+ function effectiveRoles(user, orgId) {
110
+ const roles = user?.roles ?? [];
111
+ const scope = resolveOrgScope(user, orgId);
112
+ if (scope?.tier === enums_1.OrgScopeTier.PROVIDER || scope?.tier === enums_1.OrgScopeTier.MEMBER)
113
+ return [...roles];
114
+ const outsideOrgTier = roles.filter(r => !constants_2.ORG_MEMBER_ROLES.includes(r));
115
+ return scope?.role ? [...outsideOrgTier, scope.role] : outsideOrgTier;
116
+ }
117
+ /**
118
+ * Whether `user` reaches the organization `orgId` AND holds one of `roles` there.
119
+ *
120
+ * The question every per-organization capability asks - "may this user do THIS on THAT
121
+ * organization?" - answered with the effective role, never with `roles[]`.
122
+ *
123
+ * @param user the authenticated user (`NxContext.user`)
124
+ * @param orgId the organization the operation targets
125
+ * @param roles the roles that grant the capability (any of them is enough)
126
+ * @returns `true` when the organization is reachable and one of the roles holds there
127
+ */
128
+ function hasOrgRole(user, orgId, roles) {
129
+ return !!resolveOrgScope(user, orgId) && effectiveRoles(user, orgId).some(r => roles.includes(r));
130
+ }
131
+ /**
132
+ * Throwing variant of `hasOrgRole`, for the call sites that must simply deny.
133
+ *
134
+ * The error is the one of `assertOrgScope`, for the same reason: an organization out of reach,
135
+ * one that does not exist and one where the role does not hold are not told apart.
136
+ *
137
+ * @param user the authenticated user (`NxContext.user`)
138
+ * @param orgId the organization the operation targets
139
+ * @param roles the roles that grant the capability
140
+ * @returns the scope through which the user reaches the organization
141
+ * @throws `AppError('messages.authorization.missingRole')` when the capability does not hold
142
+ */
143
+ function assertOrgRole(user, orgId, roles) {
144
+ const scope = assertOrgScope(user, orgId);
145
+ if (!hasOrgRole(user, orgId, roles))
146
+ throw new nx_frame_be_1.AppError('messages.authorization.missingRole');
147
+ return scope;
148
+ }
149
+ /**
150
+ * Every role `user` holds on AT LEAST ONE organization they reach.
151
+ *
152
+ * For a gate that runs before the organization of the operation is known - the `@auth`
153
+ * directive of a service whose operations name their organization in the arguments. It is the
154
+ * union of the effective roles over the reachable organizations, so it answers "could this user
155
+ * be allowed somewhere?"; the operation itself must then decide on its own organization with
156
+ * `hasOrgRole`/`assertOrgRole`.
157
+ *
158
+ * @param user the authenticated user (`NxContext.user`)
159
+ * @returns the user's roles plus the roles of their grants
160
+ */
161
+ function reachableRoles(user) {
162
+ const roles = new Set(user?.roles ?? []);
163
+ user?.grants?.forEach(g => g.id && g.role && roles.add(g.role));
164
+ return [...roles];
165
+ }
80
166
  /**
81
167
  * The highest organization-tier role the user holds, if any.
82
168
  *
@@ -118,4 +204,30 @@ function reachableOrgIds(user) {
118
204
  user.grants?.forEach(g => g.id && ids.add(String(g.id)));
119
205
  return [...ids];
120
206
  }
207
+ /**
208
+ * Every organization the user reaches where one of `roles` holds, for the LIST case of a capability.
209
+ *
210
+ * `hasOrgRole` answers about ONE organization named by the request; this answers "on which ones
211
+ * does the capability hold at all?", which is what a list scoped to a capability needs - the users
212
+ * a caller administers, the invitations a caller manages. It is `reachableOrgIds` narrowed by
213
+ * `hasOrgRole`, so a list never shows an organization the point check would then deny, and the
214
+ * role that decides on each organization is its effective one: a grant decides on what it grants.
215
+ *
216
+ * Same three outcomes as `reachableOrgIds`, and the caller MUST tell them apart:
217
+ *
218
+ * `undefined` -> no constraint: a cross-tenant user holding one of `roles`, which then holds on
219
+ * every organization (its effective roles are its own everywhere)
220
+ * `string[]` -> exactly these ids, never any other
221
+ * `[]` -> the capability holds nowhere; the caller must yield an EMPTY result, never all
222
+ *
223
+ * @param user the authenticated user (`NxContext.user`)
224
+ * @param roles the roles that grant the capability (any of them is enough)
225
+ * @returns `undefined` for no constraint, otherwise the exact set of ids where the capability holds
226
+ */
227
+ function orgIdsWithRole(user, roles) {
228
+ const reachable = reachableOrgIds(user);
229
+ if (!reachable)
230
+ return (user?.roles ?? []).some(r => roles.includes(r)) ? undefined : [];
231
+ return reachable.filter(id => hasOrgRole(user, id, roles));
232
+ }
121
233
  //# sourceMappingURL=scope.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scope.js","sourceRoot":"","sources":["../../src/utils/scope.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;+FAa+F;;AAiC/F,0CAqBC;AAaD,wCAQC;AAmCD,0CAcC;AA1HD,sDAA0D;AAE1D,4CAAkD;AAClD,4CAAkD;AAElD,oCAA8C;AAG9C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,SAAgB,eAAe,CAAC,IAAe,EAAE,KAAc;IAE7D,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK;QACjB,OAAO,IAAI,CAAC;IAEd,4EAA4E;IAC5E,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC,8BAAkB,CAAC;QACpC,OAAO,EAAE,IAAI,EAAE,oBAAY,CAAC,QAAQ,EAAE,CAAC;IAEzC,gFAAgF;IAChF,IAAI,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC;QAC/C,OAAO,EAAE,IAAI,EAAE,oBAAY,CAAC,MAAM,EAAE,IAAI,EAAE,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;IAEnE,6DAA6D;IAC7D,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC;IAErD,IAAI,KAAK;QACP,OAAO,EAAE,IAAI,EAAE,oBAAY,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;IAE1D,mCAAmC;IACnC,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,cAAc,CAAC,IAAe,EAAE,KAAc;IAE5D,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAE3C,IAAI,CAAC,KAAK;QACR,MAAM,IAAI,sBAAQ,CAAC,oCAAoC,CAAC,CAAC;IAE3D,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,SAAS,cAAc,CAAC,IAAc;IAEpC,OAAO,4BAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAgB,eAAe,CAAC,IAAe;IAE7C,IAAI,CAAC,IAAI;QACP,OAAO,EAAE,CAAC;IAEZ,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC,8BAAkB,CAAC;QACpC,OAAO,SAAS,CAAC;IAEnB,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAE9B,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAChE,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAEzD,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"scope.js","sourceRoot":"","sources":["../../src/utils/scope.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"tenancy.d.ts","sourceRoot":"","sources":["../../src/utils/tenancy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;+FAyB+F;AAI/F,OAAO,EAAe,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAOpE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAE7C;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,EAAE,eAgFxB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAGlC"}
1
+ {"version":3,"file":"tenancy.d.ts","sourceRoot":"","sources":["../../src/utils/tenancy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;+FAyB+F;AAI/F,OAAO,EAAe,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAOpE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAE7C;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,EAAE,eAiFxB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAGlC"}
@@ -98,8 +98,9 @@ exports.eraTenancy = {
98
98
  return exports.SHARED_TENANT_ID;
99
99
  }
100
100
  // Writing a tenant's own addition is CONFIGURING the organization, not entering data
101
- // into it: `ORG_EDITOR` and `ORG_MEMBER` use the catalogue, they do not shape it.
102
- if (!context.user?.hasRole?.(constants_2.TENANT_CONFIG_WRITE_ROLES))
101
+ // into it: `ORG_EDITOR` and `ORG_MEMBER` use the catalogue, they do not shape it. The
102
+ // role is the one of the REQUEST's organization, so a grant decides on what it grants.
103
+ if (!(0, tenant_1.hasTenantRole)(context, constants_2.TENANT_CONFIG_WRITE_ROLES))
103
104
  throw new nx_frame_be_3.AppError('messages.authorization.accessDenied');
104
105
  }
105
106
  return (0, tenant_1.resolveTenant)(context.user, context.orgId);
@@ -113,7 +114,7 @@ exports.eraTenancy = {
113
114
  canWrite(mode, current, context) {
114
115
  if (current === exports.SHARED_TENANT_ID)
115
116
  return !!context.user?.hasRole?.(constants_1.SYSTEM_ROLES);
116
- if (mode === nx_frame_be_2.TenancyMode.shared && !context.user?.hasRole?.(constants_2.TENANT_CONFIG_WRITE_ROLES))
117
+ if (mode === nx_frame_be_2.TenancyMode.shared && !(0, tenant_1.hasTenantRole)(context, constants_2.TENANT_CONFIG_WRITE_ROLES))
117
118
  return false;
118
119
  return current === (0, tenant_1.resolveTenant)(context.user, context.orgId);
119
120
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tenancy.js","sourceRoot":"","sources":["../../src/utils/tenancy.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;+FAyB+F;;;AAwH/F,kCAGC;AAzHD,sDAAoE;AAEpE,sDAAoE;AAEpE,sDAAoE;AACpE,4CAA4D;AAC5D,4CAA4D;AAC5D,qCAAwD;AAExD;;;;;;;;;;GAUG;AACU,QAAA,gBAAgB,GAAG,YAAY,CAAC;AAE7C;;;;;;GAMG;AACU,QAAA,UAAU,GAAoB;IAEzC,KAAK,EAAE,UAAU;IAEjB;;;;;OAKG;IACH,IAAI,CAAC,IAAiB,EAAE,OAAkB;QAExC,MAAM,MAAM,GAAG,IAAA,sBAAa,EAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QAE1D,OAAO,CAAC,IAAI,KAAK,yBAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,wBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACtF,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,KAAK,CAAC,IAAiB,EAAE,SAAkB,EAAE,OAAkB;QAE7D,IAAI,IAAI,KAAK,yBAAW,CAAC,MAAM,EAAE,CAAC;YAEhC,MAAM,QAAQ,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,wBAAY,CAAC,CAAC;YAEzD,IAAI,SAAS,KAAK,wBAAgB,IAAI,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBAEnE,IAAI,CAAC,QAAQ;oBACX,MAAM,IAAI,sBAAQ,CAAC,qCAAqC,CAAC,CAAC;gBAE5D,OAAO,wBAAgB,CAAC;YAC1B,CAAC;YAED,qFAAqF;YACrF,kFAAkF;YAClF,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,qCAAyB,CAAC;gBACrD,MAAM,IAAI,sBAAQ,CAAC,qCAAqC,CAAC,CAAC;QAC9D,CAAC;QAED,OAAO,IAAA,sBAAa,EAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACpD,CAAC;IAED;;;;;OAKG;IACH,QAAQ,CAAC,IAAiB,EAAE,OAAgB,EAAE,OAAkB;QAE9D,IAAI,OAAO,KAAK,wBAAgB;YAC9B,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,wBAAY,CAAC,CAAC;QAEjD,IAAI,IAAI,KAAK,yBAAW,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,qCAAyB,CAAC;YACpF,OAAO,KAAK,CAAC;QAEf,OAAO,OAAO,KAAK,IAAA,sBAAa,EAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAChE,CAAC;CACF,CAAC;AAEF;;;;;;GAMG;AACH,SAAgB,WAAW;IAEzB,iBAAG,CAAC,OAAO,GAAG,kBAAU,CAAC;AAC3B,CAAC"}
1
+ {"version":3,"file":"tenancy.js","sourceRoot":"","sources":["../../src/utils/tenancy.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;+FAyB+F;;;AAyH/F,kCAGC;AA1HD,sDAAoE;AAEpE,sDAAoE;AAEpE,sDAAoE;AACpE,4CAA4D;AAC5D,4CAA4D;AAC5D,qCAAwD;AAExD;;;;;;;;;;GAUG;AACU,QAAA,gBAAgB,GAAG,YAAY,CAAC;AAE7C;;;;;;GAMG;AACU,QAAA,UAAU,GAAoB;IAEzC,KAAK,EAAE,UAAU;IAEjB;;;;;OAKG;IACH,IAAI,CAAC,IAAiB,EAAE,OAAkB;QAExC,MAAM,MAAM,GAAG,IAAA,sBAAa,EAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QAE1D,OAAO,CAAC,IAAI,KAAK,yBAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,wBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACtF,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,KAAK,CAAC,IAAiB,EAAE,SAAkB,EAAE,OAAkB;QAE7D,IAAI,IAAI,KAAK,yBAAW,CAAC,MAAM,EAAE,CAAC;YAEhC,MAAM,QAAQ,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,wBAAY,CAAC,CAAC;YAEzD,IAAI,SAAS,KAAK,wBAAgB,IAAI,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBAEnE,IAAI,CAAC,QAAQ;oBACX,MAAM,IAAI,sBAAQ,CAAC,qCAAqC,CAAC,CAAC;gBAE5D,OAAO,wBAAgB,CAAC;YAC1B,CAAC;YAED,qFAAqF;YACrF,sFAAsF;YACtF,uFAAuF;YACvF,IAAI,CAAC,IAAA,sBAAa,EAAC,OAAO,EAAE,qCAAyB,CAAC;gBACpD,MAAM,IAAI,sBAAQ,CAAC,qCAAqC,CAAC,CAAC;QAC9D,CAAC;QAED,OAAO,IAAA,sBAAa,EAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACpD,CAAC;IAED;;;;;OAKG;IACH,QAAQ,CAAC,IAAiB,EAAE,OAAgB,EAAE,OAAkB;QAE9D,IAAI,OAAO,KAAK,wBAAgB;YAC9B,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,wBAAY,CAAC,CAAC;QAEjD,IAAI,IAAI,KAAK,yBAAW,CAAC,MAAM,IAAI,CAAC,IAAA,sBAAa,EAAC,OAAO,EAAE,qCAAyB,CAAC;YACnF,OAAO,KAAK,CAAC;QAEf,OAAO,OAAO,KAAK,IAAA,sBAAa,EAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAChE,CAAC;CACF,CAAC;AAEF;;;;;;GAMG;AACH,SAAgB,WAAW;IAEzB,iBAAG,CAAC,OAAO,GAAG,kBAAU,CAAC;AAC3B,CAAC"}
@@ -45,6 +45,31 @@ import { ExistenceCheckModel, ScopedReadModel } from './tenant.interfaces';
45
45
  * @throws `AppError('messages.forbidden')` when the selection is out of reach
46
46
  */
47
47
  export declare function resolveTenant(user?: BaseUser, orgId?: string): string;
48
+ /**
49
+ * The roles that apply to a request, on the organization it operates on.
50
+ *
51
+ * A request works inside ONE organization: the one it selected, or the user's own when it
52
+ * selected none - the rule of `resolveTenant`. Its roles are the effective roles there
53
+ * (`effectiveRoles`), so on an organization reached through a grant the grant's role decides,
54
+ * and nowhere does the membership role travel to an organization that did not confer it.
55
+ *
56
+ * It does NOT throw where `resolveTenant` does: an unreachable selection simply holds no
57
+ * organization role here, so a role check fails closed, and the scoping refuses the selection
58
+ * itself the moment a query runs. A user without any organization has nothing to narrow and
59
+ * keeps their roles.
60
+ *
61
+ * @param context the request context (authenticated user + selected organization)
62
+ * @returns the roles that hold on the organization of the request
63
+ */
64
+ export declare function tenantRoles(context?: NxContext): string[];
65
+ /**
66
+ * Whether one of `roles` holds for the request, on the organization it operates on.
67
+ *
68
+ * @param context the request context
69
+ * @param roles the roles that grant the capability (any of them is enough)
70
+ * @returns `true` when one of them is among the roles of the request
71
+ */
72
+ export declare function hasTenantRole(context: NxContext, roles: readonly string[]): boolean;
48
73
  /**
49
74
  * Forces `tenantId` on a payload or on a query filter, from the resolved organization.
50
75
  *
@@ -1 +1 @@
1
- {"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../../src/utils/tenant.ts"],"names":[],"mappings":"AAAA;;;;;;;;;+FAS+F;AAE/F,OAAO,EAAY,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAI/E,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAS,qBAAqB,CAAC;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,aAAa,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAkBrE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,GAAE,SAAc,GAAG,IAAI,CAGvE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAMjD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,SAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAMpH;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CASpG;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,uBAAuB,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIvG"}
1
+ {"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../../src/utils/tenant.ts"],"names":[],"mappings":"AAAA;;;;;;;;;+FAS+F;AAE/F,OAAO,EAAY,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAI/E,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAS,qBAAqB,CAAC;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,aAAa,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAkBrE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,SAAc,GAAG,MAAM,EAAE,CAM7D;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAGnF;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,GAAE,SAAc,GAAG,IAAI,CAGvE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAMjD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,SAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAMpH;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CASpG;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,uBAAuB,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIvG"}
@@ -11,6 +11,8 @@
11
11
  *********************************************************************************************/
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.resolveTenant = resolveTenant;
14
+ exports.tenantRoles = tenantRoles;
15
+ exports.hasTenantRole = hasTenantRole;
14
16
  exports.setTenant = setTenant;
15
17
  exports.getTenant = getTenant;
16
18
  exports.assertTenantScope = assertTenantScope;
@@ -67,6 +69,37 @@ function resolveTenant(user, orgId) {
67
69
  throw new nx_frame_be_1.AppError('messages.authorization.accessDenied');
68
70
  return orgId;
69
71
  }
72
+ /**
73
+ * The roles that apply to a request, on the organization it operates on.
74
+ *
75
+ * A request works inside ONE organization: the one it selected, or the user's own when it
76
+ * selected none - the rule of `resolveTenant`. Its roles are the effective roles there
77
+ * (`effectiveRoles`), so on an organization reached through a grant the grant's role decides,
78
+ * and nowhere does the membership role travel to an organization that did not confer it.
79
+ *
80
+ * It does NOT throw where `resolveTenant` does: an unreachable selection simply holds no
81
+ * organization role here, so a role check fails closed, and the scoping refuses the selection
82
+ * itself the moment a query runs. A user without any organization has nothing to narrow and
83
+ * keeps their roles.
84
+ *
85
+ * @param context the request context (authenticated user + selected organization)
86
+ * @returns the roles that hold on the organization of the request
87
+ */
88
+ function tenantRoles(context = {}) {
89
+ const user = context.user;
90
+ const orgId = context.orgId || (user?.organizations?.[0]?.id ? String(user.organizations[0].id) : undefined);
91
+ return orgId ? (0, scope_1.effectiveRoles)(user, orgId) : [...(user?.roles ?? [])];
92
+ }
93
+ /**
94
+ * Whether one of `roles` holds for the request, on the organization it operates on.
95
+ *
96
+ * @param context the request context
97
+ * @param roles the roles that grant the capability (any of them is enough)
98
+ * @returns `true` when one of them is among the roles of the request
99
+ */
100
+ function hasTenantRole(context, roles) {
101
+ return tenantRoles(context).some(r => roles.includes(r));
102
+ }
70
103
  /**
71
104
  * Forces `tenantId` on a payload or on a query filter, from the resolved organization.
72
105
  *
@@ -1 +1 @@
1
- {"version":3,"file":"tenant.js","sourceRoot":"","sources":["../../src/utils/tenant.ts"],"names":[],"mappings":";AAAA;;;;;;;;;+FAS+F;;AA0C/F,sCAkBC;AAqBD,8BAGC;AAaD,8BAMC;AAqCD,8CAMC;AAqDD,8CASC;AAkBD,0DAIC;AApOD,sDAA+E;AAC/E,oFAA6G;AAE7G,mCAAkE;AAGlE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,SAAgB,aAAa,CAAC,IAAe,EAAE,KAAc;IAE3D,IAAI,CAAC,KAAK;QACR,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;IAEzB,MAAM,SAAS,GAAG,IAAA,uBAAe,EAAC,IAAI,CAAC,CAAC;IAExC,sEAAsE;IACtE,IAAI,CAAC,SAAS;QACZ,OAAO,KAAK,CAAC;IAEf,2EAA2E;IAC3E,8EAA8E;IAC9E,uEAAuE;IACvE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC;QAC5B,MAAM,IAAI,sBAAQ,CAAC,qCAAqC,CAAC,CAAC;IAE5D,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,SAAgB,SAAS,CAAC,IAAc,EAAE,UAAqB,EAAE;IAE/D,IAAI,CAAC,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,SAAS,CAAC,IAAe;IAEvC,IAAI,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM;QAC9B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAE1D,OAAO,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACI,KAAK,UAAU,iBAAiB,CAAC,KAAsB,EAAE,EAAU,EAAE,UAAqB,EAAE;IAEjG,IAAI,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC;QAC/B,MAAM,IAAI,sBAAQ,CAAC,mBAAmB,CAAC,CAAC;IAE1C,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACI,KAAK,UAAU,iBAAiB,CAAC,KAA0B,EAAE,KAAc;IAEhF,IAAI,CAAC,KAAK;QACR,OAAO,IAAI,CAAC;IAEd,IAAI,CAAC,IAAA,6BAAe,EAAC,KAAK,CAAC;QACzB,OAAO,KAAK,CAAC;IAEf,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,IAAA,wBAAU,EAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAClE,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACI,KAAK,UAAU,uBAAuB,CAAC,KAA0B,EAAE,KAAc;IAEtF,IAAI,CAAC,MAAM,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC;QACxC,MAAM,IAAI,sBAAQ,CAAC,qCAAqC,CAAC,CAAC;AAC9D,CAAC"}
1
+ {"version":3,"file":"tenant.js","sourceRoot":"","sources":["../../src/utils/tenant.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextage/era-lib",
3
- "version": "1.0.218",
3
+ "version": "1.0.220",
4
4
  "main": "./build/index.js",
5
5
  "types": "./build/index.d.ts",
6
6
  "files": [