@mondaydotcomorg/monday-authorization 3.3.0-feature-bashanye-navigate-can-action-in-scope-to-graph-46d4fc5 → 3.3.0-feature-bashanye-navigate-can-action-in-scope-to-graph-9ad5fa5

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.
Files changed (41) hide show
  1. package/dist/authorization-service.d.ts +0 -8
  2. package/dist/authorization-service.d.ts.map +1 -1
  3. package/dist/authorization-service.js +30 -161
  4. package/dist/clients/graph-api.client.d.ts +24 -0
  5. package/dist/clients/graph-api.client.d.ts.map +1 -0
  6. package/dist/clients/graph-api.client.js +102 -0
  7. package/dist/clients/platform-api.client.d.ts +31 -0
  8. package/dist/clients/platform-api.client.d.ts.map +1 -0
  9. package/dist/clients/platform-api.client.js +86 -0
  10. package/dist/esm/authorization-service.d.ts +0 -8
  11. package/dist/esm/authorization-service.d.ts.map +1 -1
  12. package/dist/esm/authorization-service.mjs +31 -156
  13. package/dist/esm/clients/graph-api.client.d.ts +24 -0
  14. package/dist/esm/clients/graph-api.client.d.ts.map +1 -0
  15. package/dist/esm/clients/graph-api.client.mjs +100 -0
  16. package/dist/esm/clients/platform-api.client.d.ts +31 -0
  17. package/dist/esm/clients/platform-api.client.d.ts.map +1 -0
  18. package/dist/esm/clients/platform-api.client.mjs +84 -0
  19. package/dist/esm/prometheus-service.d.ts +3 -3
  20. package/dist/esm/prometheus-service.d.ts.map +1 -1
  21. package/dist/esm/prometheus-service.mjs +65 -3
  22. package/dist/esm/testKit/index.d.ts.map +1 -1
  23. package/dist/esm/testKit/index.mjs +9 -7
  24. package/dist/esm/types/graph-api.types.d.ts +11 -0
  25. package/dist/esm/types/graph-api.types.d.ts.map +1 -0
  26. package/dist/esm/types/graph-api.types.mjs +1 -0
  27. package/dist/esm/utils/authorization.utils.d.ts +22 -0
  28. package/dist/esm/utils/authorization.utils.d.ts.map +1 -0
  29. package/dist/esm/utils/authorization.utils.mjs +39 -0
  30. package/dist/prometheus-service.d.ts +3 -3
  31. package/dist/prometheus-service.d.ts.map +1 -1
  32. package/dist/prometheus-service.js +65 -3
  33. package/dist/testKit/index.d.ts.map +1 -1
  34. package/dist/testKit/index.js +9 -7
  35. package/dist/types/graph-api.types.d.ts +11 -0
  36. package/dist/types/graph-api.types.d.ts.map +1 -0
  37. package/dist/types/graph-api.types.js +1 -0
  38. package/dist/utils/authorization.utils.d.ts +22 -0
  39. package/dist/utils/authorization.utils.d.ts.map +1 -0
  40. package/dist/utils/authorization.utils.js +49 -0
  41. package/package.json +1 -1
@@ -30,14 +30,6 @@ export declare class AuthorizationService {
30
30
  static canActionInScope(accountId: number, userId: number, action: string, scope: ScopeOptions): Promise<ScopedActionPermit>;
31
31
  private static getProfile;
32
32
  static canActionInScopeMultiple(accountId: number, userId: number, scopedActions: ScopedAction[]): Promise<ScopedActionResponseObject[]>;
33
- private static buildScopedActionsPayload;
34
- private static scopeToResource;
35
- private static buildGraphRequestBody;
36
- private static fetchGraphIsAllowed;
37
- private static mapGraphResponse;
38
- private static fetchPlatformCanActions;
39
- private static toCamelCase;
40
- private static mapPlatformResponse;
41
33
  private static isAuthorizedSingular;
42
34
  private static isAuthorizedMultiple;
43
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"authorization-service.d.ts","sourceRoot":"","sources":["../src/authorization-service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGnE,OAAO,EAAmB,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAO7F,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACb,MAAM,kCAAkC,CAAC;AAc1C,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAC7C;AAED,wBAAgB,sBAAsB,CAAC,wBAAwB,EAAE,kBAAkB,QAElF;AAsCD,qBAAa,oBAAoB;IAC/B,MAAM,CAAC,WAAW,CAAC,MAAC;IACpB,MAAM,CAAC,sCAAsC,CAAC,EAAE,MAAM,CAAC;IACvD,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IAEnC;;;OAGG;WACU,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC;WAEhB,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,2BAA2B,EAAE,mBAAmB,EAAE,GACjD,OAAO,CAAC,iBAAiB,CAAC;IAY7B;;;OAGG;WACU,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAC1C,OAAO,CAAC,OAAO,CAAC;mBAkBE,6BAA6B;IAclD,OAAO,CAAC,MAAM,CAAC,gBAAgB;WAIlB,gBAAgB,CAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,kBAAkB,CAAC;IAM9B,OAAO,CAAC,MAAM,CAAC,UAAU;WAsBZ,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;IAyCxC,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAMxC,OAAO,CAAC,MAAM,CAAC,eAAe;IAmB9B,OAAO,CAAC,MAAM,CAAC,qBAAqB;mBAyBf,mBAAmB;IAwCxC,OAAO,CAAC,MAAM,CAAC,gBAAgB;mBAoBV,uBAAuB;IA2C5C,OAAO,CAAC,MAAM,CAAC,WAAW;IAI1B,OAAO,CAAC,MAAM,CAAC,mBAAmB;mBAiBb,oBAAoB;mBAUpB,oBAAoB;CAoF1C;AAED,wBAAgB,cAAc,CAC5B,MAAM,KAAA,EACN,sCAAsC,GAAE,MAAiD,QAY1F;AAED,wBAAsB,eAAe,kBAMpC;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAepG"}
1
+ {"version":3,"file":"authorization-service.d.ts","sourceRoot":"","sources":["../src/authorization-service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGnE,OAAO,EAAmB,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7F,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACb,MAAM,kCAAkC,CAAC;AAe1C,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAC7C;AAED,wBAAgB,sBAAsB,CAAC,wBAAwB,EAAE,kBAAkB,QAElF;AAMD,qBAAa,oBAAoB;IAC/B,MAAM,CAAC,WAAW,CAAC,MAAC;IACpB,MAAM,CAAC,sCAAsC,CAAC,EAAE,MAAM,CAAC;IACvD,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IAEnC;;;OAGG;WACU,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC;WAEhB,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,2BAA2B,EAAE,mBAAmB,EAAE,GACjD,OAAO,CAAC,iBAAiB,CAAC;IAY7B;;;OAGG;WACU,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAC1C,OAAO,CAAC,OAAO,CAAC;mBAkBE,6BAA6B;IAclD,OAAO,CAAC,MAAM,CAAC,gBAAgB;WAIlB,gBAAgB,CAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,kBAAkB,CAAC;IAM9B,OAAO,CAAC,MAAM,CAAC,UAAU;WAsBZ,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;mBA+DnB,oBAAoB;mBAUpB,oBAAoB;CAoF1C;AAED,wBAAgB,cAAc,CAC5B,MAAM,KAAA,EACN,sCAAsC,GAAE,MAAiD,QAY1F;AAED,wBAAsB,eAAe,kBAMpC;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAepG"}
@@ -1,26 +1,18 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
3
  const perf_hooks = require('perf_hooks');
4
- const snakeCase = require('lodash/snakeCase.js');
5
- const camelCase = require('lodash/camelCase.js');
6
- const mapKeys = require('lodash/mapKeys.js');
7
4
  const tridentBackendApi = require('@mondaydotcomorg/trident-backend-api');
8
5
  const mondayFetchApi = require('@mondaydotcomorg/monday-fetch-api');
9
6
  const igniteSdk = require('@mondaydotcomorg/ignite-sdk');
10
7
  const prometheusService = require('./prometheus-service.js');
11
8
  const authorizationInternalService = require('./authorization-internal-service.js');
12
9
  const attributionsService = require('./attributions-service.js');
13
-
14
- const _interopDefault = e => e && e.__esModule ? e : { default: e };
15
-
16
- const snakeCase__default = /*#__PURE__*/_interopDefault(snakeCase);
17
- const camelCase__default = /*#__PURE__*/_interopDefault(camelCase);
18
- const mapKeys__default = /*#__PURE__*/_interopDefault(mapKeys);
10
+ const clients_graphApi_client = require('./clients/graph-api.client.js');
11
+ const clients_platformApi_client = require('./clients/platform-api.client.js');
12
+ const utils_authorization_utils = require('./utils/authorization.utils.js');
19
13
 
20
14
  const GRANTED_FEATURE_CACHE_EXPIRATION_SECONDS = 5 * 60;
21
15
  const PLATFORM_AUTHORIZE_PATH = '/internal_ms/authorization/authorize';
22
- const PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH = '/internal_ms/authorization/can_actions_in_scopes';
23
- const CAN_ACTION_IN_SCOPE_GRAPH_PATH = '/permissions/is-allowed';
24
16
  const ALLOWED_SDK_PLATFORM_PROFILES_KEY = 'allowed-sdk-platform-profiles';
25
17
  const IN_RELEASE_SDK_PLATFORM_PROFILES_KEY = 'in-release-sdk-platform-profile';
26
18
  const PLATFORM_PROFILE_RELEASE_FF = 'sdk-platform-profiles';
@@ -101,167 +93,44 @@ class AuthorizationService {
101
93
  const internalAuthToken = authorizationInternalService.AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
102
94
  const startTime = perf_hooks.performance.now();
103
95
  let scopedActionResponseObjects;
96
+ let usedGraphApi = false;
104
97
  if (shouldNavigateToGraph) {
105
- const response = await this.fetchGraphIsAllowed(internalAuthToken, scopedActions);
106
- scopedActionResponseObjects = this.mapGraphResponse(scopedActions, userId, response);
98
+ try {
99
+ scopedActionResponseObjects = await clients_graphApi_client.GraphApiClient.checkPermissions(internalAuthToken, scopedActions);
100
+ usedGraphApi = true;
101
+ }
102
+ catch (error) {
103
+ // Fallback to Platform API if Graph API fails
104
+ authorizationInternalService.logger.warn({
105
+ tag: 'authorization-service',
106
+ error: error instanceof Error ? error.message : String(error),
107
+ accountId,
108
+ userId,
109
+ }, 'Graph API authorization failed, falling back to Platform API');
110
+ const profile = this.getProfile(accountId, userId);
111
+ scopedActionResponseObjects = await clients_platformApi_client.PlatformApiClient.checkPermissions(profile, internalAuthToken, userId, scopedActions);
112
+ usedGraphApi = false;
113
+ }
107
114
  }
108
115
  else {
109
116
  const profile = this.getProfile(accountId, userId);
110
- const scopedActionsPayload = this.buildScopedActionsPayload(scopedActions);
111
- const platformResponse = await this.fetchPlatformCanActions(profile, internalAuthToken, userId, scopedActionsPayload);
112
- scopedActionResponseObjects = this.mapPlatformResponse(platformResponse);
117
+ scopedActionResponseObjects = await clients_platformApi_client.PlatformApiClient.checkPermissions(profile, internalAuthToken, userId, scopedActions);
118
+ usedGraphApi = false;
113
119
  }
114
120
  const endTime = perf_hooks.performance.now();
115
121
  const time = endTime - startTime;
116
- const apiType = shouldNavigateToGraph ? 'graph' : 'platform';
122
+ const apiType = usedGraphApi ? 'graph' : 'platform';
123
+ // Record metrics for each authorization check
117
124
  for (const obj of scopedActionResponseObjects) {
118
- const { action } = obj.scopedAction;
119
- const resource_type = this.scopeToResource(obj.scopedAction.scope).resourceType;
125
+ const { action, scope } = obj.scopedAction;
126
+ const { resourceType } = utils_authorization_utils.scopeToResource(scope);
120
127
  const isAuthorized = obj.permit.can;
121
- prometheusService.sendAuthorizationCheckResponseTimeMetric(resource_type, action, isAuthorized, 200, time, apiType);
122
- if (obj.permit.can) ;
123
- }
124
- return scopedActionResponseObjects;
125
- }
126
- static buildScopedActionsPayload(scopedActions) {
127
- return scopedActions.map(scopedAction => {
128
- return { ...scopedAction, scope: mapKeys__default.default(scopedAction.scope, (_, key) => snakeCase__default.default(key)) };
129
- });
130
- }
131
- static scopeToResource(scope) {
132
- if ('workspaceId' in scope) {
133
- return { resourceType: 'workspace', resourceId: scope.workspaceId };
134
- }
135
- if ('boardId' in scope) {
136
- return { resourceType: 'board', resourceId: scope.boardId };
137
- }
138
- if ('pulseId' in scope) {
139
- return { resourceType: 'pulse', resourceId: scope.pulseId };
140
- }
141
- if ('accountProductId' in scope) {
142
- return { resourceType: 'account_product', resourceId: scope.accountProductId };
143
- }
144
- if ('accountId' in scope) {
145
- return { resourceType: 'account', resourceId: scope.accountId };
146
- }
147
- throw new Error('Unsupported scope provided');
148
- }
149
- static buildGraphRequestBody(scopedActions) {
150
- const resourcesAccumulator = {};
151
- for (const { action, scope } of scopedActions) {
152
- const { resourceType, resourceId } = this.scopeToResource(scope);
153
- if (!resourcesAccumulator[resourceType]) {
154
- resourcesAccumulator[resourceType] = {};
155
- }
156
- if (!resourcesAccumulator[resourceType][resourceId]) {
157
- resourcesAccumulator[resourceType][resourceId] = new Set();
158
- }
159
- resourcesAccumulator[resourceType][resourceId].add(action);
160
- }
161
- const resourcesPayload = {};
162
- for (const [resourceType, idMap] of Object.entries(resourcesAccumulator)) {
163
- resourcesPayload[resourceType] = {};
164
- for (const [idStr, actionsSet] of Object.entries(idMap)) {
165
- const idNum = Number(idStr);
166
- resourcesPayload[resourceType][idNum] = Array.from(actionsSet);
167
- }
168
- }
169
- return resourcesPayload;
170
- }
171
- static async fetchGraphIsAllowed(internalAuthToken, scopedActions) {
172
- const httpClient = tridentBackendApi.Api.getPart('httpClient');
173
- const attributionHeaders = attributionsService.getAttributionsFromApi();
174
- const bodyPayload = this.buildGraphRequestBody(scopedActions);
175
- try {
176
- const response = await httpClient.fetch({
177
- url: {
178
- appName: 'authorization-graph',
179
- path: CAN_ACTION_IN_SCOPE_GRAPH_PATH,
180
- },
181
- method: 'POST',
182
- headers: {
183
- Authorization: internalAuthToken,
184
- 'Content-Type': 'application/json',
185
- ...attributionHeaders,
186
- },
187
- body: JSON.stringify(bodyPayload),
188
- }, {
189
- timeout: authorizationInternalService.AuthorizationInternalService.getRequestTimeout(),
190
- retryPolicy: authorizationInternalService.AuthorizationInternalService.getRetriesPolicy(),
191
- });
192
- prometheusService.setGraphAvailability(true);
193
- return response;
194
- }
195
- catch (err) {
196
- if (err instanceof mondayFetchApi.HttpFetcherError) {
197
- authorizationInternalService.AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
198
- prometheusService.incrementAuthorizationError(this.scopeToResource(scopedActions[0].scope).resourceType, scopedActions[0].action, err.status);
128
+ prometheusService.sendAuthorizationCheckResponseTimeMetric(resourceType, action, isAuthorized, 200, time, apiType);
129
+ if (obj.permit.can) {
130
+ prometheusService.incrementAuthorizationSuccess(resourceType, action);
199
131
  }
200
- throw err;
201
132
  }
202
- }
203
- static mapGraphResponse(scopedActions, userId, graphResponse) {
204
- const resources = graphResponse ?? {};
205
- return scopedActions.map(scopedAction => {
206
- const { action, scope } = scopedAction;
207
- const { resourceType, resourceId } = this.scopeToResource(scope);
208
- const permissionResult = resources?.[resourceType]?.[String(resourceId)]?.[action];
209
- const permit = {
210
- can: permissionResult?.can ?? false,
211
- reason: { key: permissionResult?.reason ?? 'unknown' },
212
- technicalReason: 0,
213
- };
214
- return { scopedAction, permit };
215
- });
216
- }
217
- static async fetchPlatformCanActions(profile, internalAuthToken, userId, scopedActionsPayload) {
218
- const attributionHeaders = attributionsService.getAttributionsFromApi();
219
- const httpClient = tridentBackendApi.Api.getPart('httpClient');
220
- try {
221
- const response = await httpClient.fetch({
222
- url: {
223
- appName: 'platform',
224
- path: PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH,
225
- profile,
226
- },
227
- method: 'POST',
228
- headers: {
229
- Authorization: internalAuthToken,
230
- 'Content-Type': 'application/json',
231
- ...attributionHeaders,
232
- },
233
- body: JSON.stringify({ user_id: userId, scoped_actions: scopedActionsPayload }),
234
- }, {
235
- timeout: authorizationInternalService.AuthorizationInternalService.getRequestTimeout(),
236
- retryPolicy: authorizationInternalService.AuthorizationInternalService.getRetriesPolicy(),
237
- });
238
- return response;
239
- }
240
- catch (err) {
241
- if (err instanceof mondayFetchApi.HttpFetcherError) {
242
- authorizationInternalService.AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
243
- prometheusService.incrementAuthorizationError(this.scopeToResource(this.toCamelCase(scopedActionsPayload[0].scope)).resourceType, scopedActionsPayload[0].action, err.status);
244
- }
245
- throw err;
246
- }
247
- }
248
- static toCamelCase(obj) {
249
- return mapKeys__default.default(obj, (_, key) => camelCase__default.default(key));
250
- }
251
- static mapPlatformResponse(response) {
252
- if (!response) {
253
- authorizationInternalService.logger.error({ tag: 'authorization-service', response }, 'AuthorizationService: missing response');
254
- throw new Error('AuthorizationService: missing response');
255
- }
256
- return response.result.map(responseObject => {
257
- const { scopedAction, permit } = responseObject;
258
- const { scope } = scopedAction;
259
- return {
260
- ...responseObject,
261
- scopedAction: { ...scopedAction, scope: this.toCamelCase(scope) },
262
- permit: this.toCamelCase(permit),
263
- };
264
- });
133
+ return scopedActionResponseObjects;
265
134
  }
266
135
  static async isAuthorizedSingular(accountId, userId, resources, action) {
267
136
  const { authorizationObjects } = createAuthorizationParams(resources, action);
@@ -0,0 +1,24 @@
1
+ import { ScopedAction, ScopedActionResponseObject } from '../types/scoped-actions-contracts';
2
+ import { GraphIsAllowedDto, GraphIsAllowedResponse } from '../types/graph-api.types';
3
+ /**
4
+ * Client for handling Graph API authorization operations
5
+ */
6
+ export declare class GraphApiClient {
7
+ /**
8
+ * Builds the request body for Graph API calls
9
+ */
10
+ static buildRequestBody(scopedActions: ScopedAction[]): GraphIsAllowedDto;
11
+ /**
12
+ * Fetches authorization data from the Graph API
13
+ */
14
+ static fetchPermissions(internalAuthToken: string, scopedActions: ScopedAction[]): Promise<GraphIsAllowedResponse>;
15
+ /**
16
+ * Maps Graph API response to the expected format
17
+ */
18
+ static mapResponse(scopedActions: ScopedAction[], graphResponse: GraphIsAllowedResponse): ScopedActionResponseObject[];
19
+ /**
20
+ * Performs a complete authorization check using the Graph API
21
+ */
22
+ static checkPermissions(internalAuthToken: string, scopedActions: ScopedAction[]): Promise<ScopedActionResponseObject[]>;
23
+ }
24
+ //# sourceMappingURL=graph-api.client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-api.client.d.ts","sourceRoot":"","sources":["../../src/clients/graph-api.client.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,0BAA0B,EAAsB,MAAM,mCAAmC,CAAC;AAGjH,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EAIvB,MAAM,0BAA0B,CAAC;AAMlC;;GAEG;AACH,qBAAa,cAAc;IACzB;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,aAAa,EAAE,YAAY,EAAE,GAAG,iBAAiB;IAyBzE;;OAEG;WACU,gBAAgB,CAC3B,iBAAiB,EAAE,MAAM,EACzB,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,sBAAsB,CAAC;IAyClC;;OAEG;IACH,MAAM,CAAC,WAAW,CAChB,aAAa,EAAE,YAAY,EAAE,EAC7B,aAAa,EAAE,sBAAsB,GACpC,0BAA0B,EAAE;IAkB/B;;OAEG;WACU,gBAAgB,CAC3B,iBAAiB,EAAE,MAAM,EACzB,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;CAIzC"}
@@ -0,0 +1,102 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ const tridentBackendApi = require('@mondaydotcomorg/trident-backend-api');
4
+ const mondayFetchApi = require('@mondaydotcomorg/monday-fetch-api');
5
+ const authorizationInternalService = require('../authorization-internal-service.js');
6
+ const attributionsService = require('../attributions-service.js');
7
+ const utils_authorization_utils = require('../utils/authorization.utils.js');
8
+ const prometheusService = require('../prometheus-service.js');
9
+
10
+ const CAN_ACTION_IN_SCOPE_GRAPH_PATH = '/permissions/is-allowed';
11
+ /**
12
+ * Client for handling Graph API authorization operations
13
+ */
14
+ class GraphApiClient {
15
+ /**
16
+ * Builds the request body for Graph API calls
17
+ */
18
+ static buildRequestBody(scopedActions) {
19
+ const resourcesAccumulator = {};
20
+ for (const { action, scope } of scopedActions) {
21
+ const { resourceType, resourceId } = utils_authorization_utils.scopeToResource(scope);
22
+ if (!resourcesAccumulator[resourceType]) {
23
+ resourcesAccumulator[resourceType] = {};
24
+ }
25
+ if (!resourcesAccumulator[resourceType][resourceId]) {
26
+ resourcesAccumulator[resourceType][resourceId] = new Set();
27
+ }
28
+ resourcesAccumulator[resourceType][resourceId].add(action);
29
+ }
30
+ const resourcesPayload = {};
31
+ for (const [resourceType, idMap] of Object.entries(resourcesAccumulator)) {
32
+ resourcesPayload[resourceType] = {};
33
+ for (const [idStr, actionsSet] of Object.entries(idMap)) {
34
+ const idNum = Number(idStr);
35
+ resourcesPayload[resourceType][idNum] = Array.from(actionsSet);
36
+ }
37
+ }
38
+ return resourcesPayload;
39
+ }
40
+ /**
41
+ * Fetches authorization data from the Graph API
42
+ */
43
+ static async fetchPermissions(internalAuthToken, scopedActions) {
44
+ const httpClient = tridentBackendApi.Api.getPart('httpClient');
45
+ const attributionHeaders = attributionsService.getAttributionsFromApi();
46
+ const bodyPayload = this.buildRequestBody(scopedActions);
47
+ try {
48
+ const response = await httpClient.fetch({
49
+ url: {
50
+ appName: 'authorization-graph',
51
+ path: CAN_ACTION_IN_SCOPE_GRAPH_PATH,
52
+ },
53
+ method: 'POST',
54
+ headers: {
55
+ Authorization: internalAuthToken,
56
+ 'Content-Type': 'application/json',
57
+ ...attributionHeaders,
58
+ },
59
+ body: JSON.stringify(bodyPayload),
60
+ }, {
61
+ timeout: authorizationInternalService.AuthorizationInternalService.getRequestTimeout(),
62
+ retryPolicy: authorizationInternalService.AuthorizationInternalService.getRetriesPolicy(),
63
+ });
64
+ prometheusService.setGraphAvailability(true);
65
+ return response;
66
+ }
67
+ catch (err) {
68
+ prometheusService.setGraphAvailability(false);
69
+ if (err instanceof mondayFetchApi.HttpFetcherError) {
70
+ authorizationInternalService.AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
71
+ prometheusService.incrementAuthorizationError(utils_authorization_utils.scopeToResource(scopedActions[0].scope).resourceType, scopedActions[0].action, err.status);
72
+ }
73
+ throw err;
74
+ }
75
+ }
76
+ /**
77
+ * Maps Graph API response to the expected format
78
+ */
79
+ static mapResponse(scopedActions, graphResponse) {
80
+ const resources = graphResponse ?? {};
81
+ return scopedActions.map(scopedAction => {
82
+ const { action, scope } = scopedAction;
83
+ const { resourceType, resourceId } = utils_authorization_utils.scopeToResource(scope);
84
+ const permissionResult = resources?.[resourceType]?.[String(resourceId)]?.[action];
85
+ const permit = {
86
+ can: permissionResult?.can ?? false,
87
+ reason: { key: permissionResult?.reason ?? 'unknown' },
88
+ technicalReason: 0,
89
+ };
90
+ return { scopedAction, permit };
91
+ });
92
+ }
93
+ /**
94
+ * Performs a complete authorization check using the Graph API
95
+ */
96
+ static async checkPermissions(internalAuthToken, scopedActions) {
97
+ const response = await this.fetchPermissions(internalAuthToken, scopedActions);
98
+ return this.mapResponse(scopedActions, response);
99
+ }
100
+ }
101
+
102
+ exports.GraphApiClient = GraphApiClient;
@@ -0,0 +1,31 @@
1
+ import { ScopedAction, ScopedActionResponseObject } from '../types/scoped-actions-contracts';
2
+ import { PlatformProfile } from '../attributions-service';
3
+ type ScopedActionPlatformPayload = Omit<ScopedAction, 'scope'> & {
4
+ scope: Record<string, number>;
5
+ };
6
+ interface CanActionsInScopesResponse {
7
+ result: ScopedActionResponseObject[];
8
+ }
9
+ /**
10
+ * Client for handling Platform API authorization operations
11
+ */
12
+ export declare class PlatformApiClient {
13
+ /**
14
+ * Builds the request payload for Platform API calls
15
+ */
16
+ static buildRequestPayload(scopedActions: ScopedAction[]): ScopedActionPlatformPayload[];
17
+ /**
18
+ * Fetches authorization data from the Platform API
19
+ */
20
+ static fetchPermissions(profile: PlatformProfile, internalAuthToken: string, userId: number, scopedActionsPayload: ScopedActionPlatformPayload[]): Promise<CanActionsInScopesResponse>;
21
+ /**
22
+ * Maps Platform API response to the expected format
23
+ */
24
+ static mapResponse(response: CanActionsInScopesResponse): ScopedActionResponseObject[];
25
+ /**
26
+ * Performs a complete authorization check using the Platform API
27
+ */
28
+ static checkPermissions(profile: PlatformProfile, internalAuthToken: string, userId: number, scopedActions: ScopedAction[]): Promise<ScopedActionResponseObject[]>;
29
+ }
30
+ export {};
31
+ //# sourceMappingURL=platform-api.client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-api.client.d.ts","sourceRoot":"","sources":["../../src/clients/platform-api.client.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;AAE7F,OAAO,EAA0B,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAOlF,KAAK,2BAA2B,GAAG,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,GAAG;IAC/D,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B,CAAC;AAEF,UAAU,0BAA0B;IAClC,MAAM,EAAE,0BAA0B,EAAE,CAAC;CACtC;AAED;;GAEG;AACH,qBAAa,iBAAiB;IAC5B;;OAEG;IACH,MAAM,CAAC,mBAAmB,CAAC,aAAa,EAAE,YAAY,EAAE,GAAG,2BAA2B,EAAE;IAOxF;;OAEG;WACU,gBAAgB,CAC3B,OAAO,EAAE,eAAe,EACxB,iBAAiB,EAAE,MAAM,EACzB,MAAM,EAAE,MAAM,EACd,oBAAoB,EAAE,2BAA2B,EAAE,GAClD,OAAO,CAAC,0BAA0B,CAAC;IAuCtC;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,0BAA0B,GAAG,0BAA0B,EAAE;IAkBtF;;OAEG;WACU,gBAAgB,CAC3B,OAAO,EAAE,eAAe,EACxB,iBAAiB,EAAE,MAAM,EACzB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;CAKzC"}
@@ -0,0 +1,86 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ const tridentBackendApi = require('@mondaydotcomorg/trident-backend-api');
4
+ const mondayFetchApi = require('@mondaydotcomorg/monday-fetch-api');
5
+ const authorizationInternalService = require('../authorization-internal-service.js');
6
+ const attributionsService = require('../attributions-service.js');
7
+ const utils_authorization_utils = require('../utils/authorization.utils.js');
8
+ const prometheusService = require('../prometheus-service.js');
9
+
10
+ const PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH = '/internal_ms/authorization/can_actions_in_scopes';
11
+ /**
12
+ * Client for handling Platform API authorization operations
13
+ */
14
+ class PlatformApiClient {
15
+ /**
16
+ * Builds the request payload for Platform API calls
17
+ */
18
+ static buildRequestPayload(scopedActions) {
19
+ return scopedActions.map(scopedAction => ({
20
+ ...scopedAction,
21
+ scope: utils_authorization_utils.toSnakeCase(scopedAction.scope),
22
+ }));
23
+ }
24
+ /**
25
+ * Fetches authorization data from the Platform API
26
+ */
27
+ static async fetchPermissions(profile, internalAuthToken, userId, scopedActionsPayload) {
28
+ const attributionHeaders = attributionsService.getAttributionsFromApi();
29
+ const httpClient = tridentBackendApi.Api.getPart('httpClient');
30
+ try {
31
+ const response = await httpClient.fetch({
32
+ url: {
33
+ appName: 'platform',
34
+ path: PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH,
35
+ profile,
36
+ },
37
+ method: 'POST',
38
+ headers: {
39
+ Authorization: internalAuthToken,
40
+ 'Content-Type': 'application/json',
41
+ ...attributionHeaders,
42
+ },
43
+ body: JSON.stringify({ user_id: userId, scoped_actions: scopedActionsPayload }),
44
+ }, {
45
+ timeout: authorizationInternalService.AuthorizationInternalService.getRequestTimeout(),
46
+ retryPolicy: authorizationInternalService.AuthorizationInternalService.getRetriesPolicy(),
47
+ });
48
+ return response;
49
+ }
50
+ catch (err) {
51
+ if (err instanceof mondayFetchApi.HttpFetcherError) {
52
+ authorizationInternalService.AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
53
+ prometheusService.incrementAuthorizationError(utils_authorization_utils.scopeToResource(utils_authorization_utils.toCamelCase(scopedActionsPayload[0].scope)).resourceType, scopedActionsPayload[0].action, err.status);
54
+ }
55
+ throw err;
56
+ }
57
+ }
58
+ /**
59
+ * Maps Platform API response to the expected format
60
+ */
61
+ static mapResponse(response) {
62
+ if (!response) {
63
+ authorizationInternalService.logger.error({ tag: 'platform-api-client', response }, 'PlatformApiClient: missing response');
64
+ throw new Error('PlatformApiClient: missing response');
65
+ }
66
+ return response.result.map(responseObject => {
67
+ const { scopedAction, permit } = responseObject;
68
+ const { scope } = scopedAction;
69
+ return {
70
+ ...responseObject,
71
+ scopedAction: { ...scopedAction, scope: utils_authorization_utils.toCamelCase(scope) },
72
+ permit: utils_authorization_utils.toCamelCase(permit),
73
+ };
74
+ });
75
+ }
76
+ /**
77
+ * Performs a complete authorization check using the Platform API
78
+ */
79
+ static async checkPermissions(profile, internalAuthToken, userId, scopedActions) {
80
+ const scopedActionsPayload = this.buildRequestPayload(scopedActions);
81
+ const platformResponse = await this.fetchPermissions(profile, internalAuthToken, userId, scopedActionsPayload);
82
+ return this.mapResponse(platformResponse);
83
+ }
84
+ }
85
+
86
+ exports.PlatformApiClient = PlatformApiClient;
@@ -30,14 +30,6 @@ export declare class AuthorizationService {
30
30
  static canActionInScope(accountId: number, userId: number, action: string, scope: ScopeOptions): Promise<ScopedActionPermit>;
31
31
  private static getProfile;
32
32
  static canActionInScopeMultiple(accountId: number, userId: number, scopedActions: ScopedAction[]): Promise<ScopedActionResponseObject[]>;
33
- private static buildScopedActionsPayload;
34
- private static scopeToResource;
35
- private static buildGraphRequestBody;
36
- private static fetchGraphIsAllowed;
37
- private static mapGraphResponse;
38
- private static fetchPlatformCanActions;
39
- private static toCamelCase;
40
- private static mapPlatformResponse;
41
33
  private static isAuthorizedSingular;
42
34
  private static isAuthorizedMultiple;
43
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"authorization-service.d.ts","sourceRoot":"","sources":["../../src/authorization-service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGnE,OAAO,EAAmB,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAO7F,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACb,MAAM,kCAAkC,CAAC;AAc1C,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAC7C;AAED,wBAAgB,sBAAsB,CAAC,wBAAwB,EAAE,kBAAkB,QAElF;AAsCD,qBAAa,oBAAoB;IAC/B,MAAM,CAAC,WAAW,CAAC,MAAC;IACpB,MAAM,CAAC,sCAAsC,CAAC,EAAE,MAAM,CAAC;IACvD,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IAEnC;;;OAGG;WACU,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC;WAEhB,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,2BAA2B,EAAE,mBAAmB,EAAE,GACjD,OAAO,CAAC,iBAAiB,CAAC;IAY7B;;;OAGG;WACU,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAC1C,OAAO,CAAC,OAAO,CAAC;mBAkBE,6BAA6B;IAclD,OAAO,CAAC,MAAM,CAAC,gBAAgB;WAIlB,gBAAgB,CAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,kBAAkB,CAAC;IAM9B,OAAO,CAAC,MAAM,CAAC,UAAU;WAsBZ,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;IAyCxC,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAMxC,OAAO,CAAC,MAAM,CAAC,eAAe;IAmB9B,OAAO,CAAC,MAAM,CAAC,qBAAqB;mBAyBf,mBAAmB;IAwCxC,OAAO,CAAC,MAAM,CAAC,gBAAgB;mBAoBV,uBAAuB;IA2C5C,OAAO,CAAC,MAAM,CAAC,WAAW;IAI1B,OAAO,CAAC,MAAM,CAAC,mBAAmB;mBAiBb,oBAAoB;mBAUpB,oBAAoB;CAoF1C;AAED,wBAAgB,cAAc,CAC5B,MAAM,KAAA,EACN,sCAAsC,GAAE,MAAiD,QAY1F;AAED,wBAAsB,eAAe,kBAMpC;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAepG"}
1
+ {"version":3,"file":"authorization-service.d.ts","sourceRoot":"","sources":["../../src/authorization-service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGnE,OAAO,EAAmB,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7F,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACb,MAAM,kCAAkC,CAAC;AAe1C,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAC7C;AAED,wBAAgB,sBAAsB,CAAC,wBAAwB,EAAE,kBAAkB,QAElF;AAMD,qBAAa,oBAAoB;IAC/B,MAAM,CAAC,WAAW,CAAC,MAAC;IACpB,MAAM,CAAC,sCAAsC,CAAC,EAAE,MAAM,CAAC;IACvD,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IAEnC;;;OAGG;WACU,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC;WAEhB,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,2BAA2B,EAAE,mBAAmB,EAAE,GACjD,OAAO,CAAC,iBAAiB,CAAC;IAY7B;;;OAGG;WACU,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAC1C,OAAO,CAAC,OAAO,CAAC;mBAkBE,6BAA6B;IAclD,OAAO,CAAC,MAAM,CAAC,gBAAgB;WAIlB,gBAAgB,CAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,kBAAkB,CAAC;IAM9B,OAAO,CAAC,MAAM,CAAC,UAAU;WAsBZ,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;mBA+DnB,oBAAoB;mBAUpB,oBAAoB;CAoF1C;AAED,wBAAgB,cAAc,CAC5B,MAAM,KAAA,EACN,sCAAsC,GAAE,MAAiD,QAY1F;AAED,wBAAsB,eAAe,kBAMpC;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAepG"}