@mondaydotcomorg/monday-authorization 3.2.3-feature-bashanye-navigate-can-action-in-scope-to-graph-af77c6b → 3.2.4

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.
@@ -2,9 +2,10 @@ import { Context, ExecutionContext } from '@mondaydotcomorg/trident-backend-api'
2
2
  export declare enum PlatformProfile {
3
3
  API_INTERNAL = "api-internal",
4
4
  SLOW = "slow",
5
- INTERNAL = "internal"
5
+ INTERNAL = "internal",
6
+ APP = "app"
6
7
  }
7
- export declare function getProfile(): PlatformProfile;
8
+ export declare function getProfile(): PlatformProfile.API_INTERNAL | PlatformProfile.SLOW | PlatformProfile.INTERNAL;
8
9
  export declare function getExecutionContext(context: Context): ExecutionContext;
9
10
  export declare function getAttributionsFromApi(): {
10
11
  [key: string]: string;
@@ -1 +1 @@
1
- {"version":3,"file":"attributions-service.d.ts","sourceRoot":"","sources":["../src/attributions-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAStF,oBAAY,eAAe;IACzB,YAAY,iBAAiB;IAC7B,IAAI,SAAS;IACb,QAAQ,aAAa;CACtB;AAED,wBAAgB,UAAU,oBAiBzB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,CAEtE;AAED,wBAAgB,sBAAsB,IAAI;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAqClE"}
1
+ {"version":3,"file":"attributions-service.d.ts","sourceRoot":"","sources":["../src/attributions-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAStF,oBAAY,eAAe;IACzB,YAAY,iBAAiB;IAC7B,IAAI,SAAS;IACb,QAAQ,aAAa;IACrB,GAAG,QAAQ;CACZ;AAED,wBAAgB,UAAU,mFAiBzB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,CAEtE;AAED,wBAAgB,sBAAsB,IAAI;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAqClE"}
@@ -12,6 +12,7 @@ exports.PlatformProfile = void 0;
12
12
  PlatformProfile["API_INTERNAL"] = "api-internal";
13
13
  PlatformProfile["SLOW"] = "slow";
14
14
  PlatformProfile["INTERNAL"] = "internal";
15
+ PlatformProfile["APP"] = "app";
15
16
  })(exports.PlatformProfile || (exports.PlatformProfile = {}));
16
17
  function getProfile() {
17
18
  const tridentContext = tridentBackendApi.Api.getPart('context');
@@ -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;AAE7F,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;AA6BD,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;IAsBxC,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAMxC,OAAO,CAAC,MAAM,CAAC,eAAe;IAmB9B,OAAO,CAAC,MAAM,CAAC,qBAAqB;mBAyBf,mBAAmB;IAoCxC,OAAO,CAAC,MAAM,CAAC,gBAAgB;mBAoBV,uBAAuB;IAsC5C,OAAO,CAAC,MAAM,CAAC,WAAW;IAI1B,OAAO,CAAC,MAAM,CAAC,mBAAmB;mBAiBb,oBAAoB;mBAUpB,oBAAoB;CAmF1C;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":"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;AAE7F,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACb,MAAM,kCAAkC,CAAC;AAY1C,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;AAeD,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;mBAkEnB,oBAAoB;mBAUpB,oBAAoB;CAmF1C;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"}
@@ -23,8 +23,6 @@ const PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH = '/internal_ms/authorization/can_acti
23
23
  const ALLOWED_SDK_PLATFORM_PROFILES_KEY = 'allowed-sdk-platform-profiles';
24
24
  const IN_RELEASE_SDK_PLATFORM_PROFILES_KEY = 'in-release-sdk-platform-profile';
25
25
  const PLATFORM_PROFILE_RELEASE_FF = 'sdk-platform-profiles';
26
- const NAVIGATE_CAN_ACTION_IN_SCOPE_TO_GRAPH_FF = 'navigate-can-action-in-scope-to-graph';
27
- const GRAPH_IS_ALLOWED_PATH = '/permissions/is-allowed';
28
26
  function setRequestFetchOptions(customMondayFetchOptions) {
29
27
  authorizationInternalService.AuthorizationInternalService.setRequestFetchOptions(customMondayFetchOptions);
30
28
  }
@@ -94,114 +92,19 @@ class AuthorizationService {
94
92
  this.igniteClient.isReleased(PLATFORM_PROFILE_RELEASE_FF, { accountId, userId })) {
95
93
  return attributionsService.getProfile();
96
94
  }
97
- return attributionsService.PlatformProfile.INTERNAL;
95
+ return attributionsService.PlatformProfile.APP;
98
96
  }
99
97
  static async canActionInScopeMultiple(accountId, userId, scopedActions) {
100
- const shouldNavigateToGraph = Boolean(this.igniteClient?.isReleased(NAVIGATE_CAN_ACTION_IN_SCOPE_TO_GRAPH_FF, { accountId, userId }));
101
- const internalAuthToken = authorizationInternalService.AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
102
- if (shouldNavigateToGraph) {
103
- const response = await this.fetchGraphIsAllowed(internalAuthToken, scopedActions);
104
- return this.mapGraphResponse(scopedActions, userId, response);
105
- }
106
98
  const profile = this.getProfile(accountId, userId);
107
- const scopedActionsPayload = this.buildScopedActionsPayload(scopedActions);
108
- const platformResponse = await this.fetchPlatformCanActions(profile, internalAuthToken, userId, scopedActionsPayload);
109
- return this.mapPlatformResponse(platformResponse);
110
- }
111
- static buildScopedActionsPayload(scopedActions) {
112
- return scopedActions.map(scopedAction => {
113
- return { ...scopedAction, scope: mapKeys__default.default(scopedAction.scope, (_, key) => snakeCase__default.default(key)) };
114
- });
115
- }
116
- static scopeToResource(scope) {
117
- if ('workspaceId' in scope) {
118
- return { resourceType: 'workspace', resourceId: scope.workspaceId };
119
- }
120
- if ('boardId' in scope) {
121
- return { resourceType: 'board', resourceId: scope.boardId };
122
- }
123
- if ('pulseId' in scope) {
124
- return { resourceType: 'pulse', resourceId: scope.pulseId };
125
- }
126
- if ('accountProductId' in scope) {
127
- return { resourceType: 'account_product', resourceId: scope.accountProductId };
128
- }
129
- if ('accountId' in scope) {
130
- return { resourceType: 'account', resourceId: scope.accountId };
131
- }
132
- throw new Error('Unsupported scope provided');
133
- }
134
- static buildGraphRequestBody(scopedActions) {
135
- const resourcesAccumulator = {};
136
- for (const { action, scope } of scopedActions) {
137
- const { resourceType, resourceId } = this.scopeToResource(scope);
138
- if (!resourcesAccumulator[resourceType]) {
139
- resourcesAccumulator[resourceType] = {};
140
- }
141
- if (!resourcesAccumulator[resourceType][resourceId]) {
142
- resourcesAccumulator[resourceType][resourceId] = new Set();
143
- }
144
- resourcesAccumulator[resourceType][resourceId].add(action);
145
- }
146
- const resourcesPayload = {};
147
- for (const [resourceType, idMap] of Object.entries(resourcesAccumulator)) {
148
- resourcesPayload[resourceType] = {};
149
- for (const [idStr, actionsSet] of Object.entries(idMap)) {
150
- const idNum = Number(idStr);
151
- resourcesPayload[resourceType][idNum] = Array.from(actionsSet);
152
- }
153
- }
154
- return resourcesPayload;
155
- }
156
- static async fetchGraphIsAllowed(internalAuthToken, scopedActions) {
157
- const httpClient = tridentBackendApi.Api.getPart('httpClient');
158
- const attributionHeaders = attributionsService.getAttributionsFromApi();
159
- const bodyPayload = this.buildGraphRequestBody(scopedActions);
160
- try {
161
- const response = await httpClient.fetch({
162
- url: {
163
- appName: 'authorization-graph',
164
- path: GRAPH_IS_ALLOWED_PATH,
165
- },
166
- method: 'POST',
167
- headers: {
168
- Authorization: internalAuthToken,
169
- 'Content-Type': 'application/json',
170
- ...attributionHeaders,
171
- },
172
- body: JSON.stringify(bodyPayload),
173
- }, {
174
- timeout: authorizationInternalService.AuthorizationInternalService.getRequestTimeout(),
175
- retryPolicy: authorizationInternalService.AuthorizationInternalService.getRetriesPolicy(),
176
- });
177
- return response;
178
- }
179
- catch (err) {
180
- if (err instanceof mondayFetchApi.HttpFetcherError) {
181
- authorizationInternalService.AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
182
- }
183
- throw err;
184
- }
185
- }
186
- static mapGraphResponse(scopedActions, userId, graphResponse) {
187
- const resources = graphResponse ?? {};
188
- return scopedActions.map(scopedAction => {
189
- const { action, scope } = scopedAction;
190
- const { resourceType, resourceId } = this.scopeToResource(scope);
191
- const permissionResult = resources?.[resourceType]?.[String(resourceId)]?.[action];
192
- const permit = {
193
- can: permissionResult?.can ?? false,
194
- reason: { key: permissionResult?.reason ?? 'unknown' },
195
- technicalReason: 0,
196
- };
197
- return { scopedAction, permit };
99
+ const internalAuthToken = authorizationInternalService.AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
100
+ const scopedActionsPayload = scopedActions.map(scopedAction => {
101
+ return { ...scopedAction, scope: mapKeys__default.default(scopedAction.scope, (_, key) => snakeCase__default.default(key)) }; // for example: { workspaceId: 1 } => { workspace_id: 1 }
198
102
  });
199
- }
200
- static async fetchPlatformCanActions(profile, internalAuthToken, userId, scopedActionsPayload) {
201
103
  const attributionHeaders = attributionsService.getAttributionsFromApi();
202
104
  const httpClient = tridentBackendApi.Api.getPart('httpClient');
105
+ let response;
203
106
  try {
204
- const response = await httpClient.fetch({
107
+ response = await httpClient.fetch({
205
108
  url: {
206
109
  appName: 'platform',
207
110
  path: PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH,
@@ -213,37 +116,40 @@ class AuthorizationService {
213
116
  'Content-Type': 'application/json',
214
117
  ...attributionHeaders,
215
118
  },
216
- body: JSON.stringify({ user_id: userId, scoped_actions: scopedActionsPayload }),
119
+ body: JSON.stringify({
120
+ user_id: userId,
121
+ scoped_actions: scopedActionsPayload,
122
+ }),
217
123
  }, {
218
124
  timeout: authorizationInternalService.AuthorizationInternalService.getRequestTimeout(),
219
125
  retryPolicy: authorizationInternalService.AuthorizationInternalService.getRetriesPolicy(),
220
126
  });
221
- return response;
222
127
  }
223
128
  catch (err) {
224
129
  if (err instanceof mondayFetchApi.HttpFetcherError) {
225
130
  authorizationInternalService.AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
226
131
  }
227
- throw err;
132
+ else {
133
+ throw err;
134
+ }
135
+ }
136
+ function toCamelCase(obj) {
137
+ return mapKeys__default.default(obj, (_, key) => camelCase__default.default(key));
228
138
  }
229
- }
230
- static toCamelCase(obj) {
231
- return mapKeys__default.default(obj, (_, key) => camelCase__default.default(key));
232
- }
233
- static mapPlatformResponse(response) {
234
139
  if (!response) {
235
140
  authorizationInternalService.logger.error({ tag: 'authorization-service', response }, 'AuthorizationService: missing response');
236
141
  throw new Error('AuthorizationService: missing response');
237
142
  }
238
- return response.result.map(responseObject => {
143
+ const scopedActionsResponseObjects = response.result.map(responseObject => {
239
144
  const { scopedAction, permit } = responseObject;
240
145
  const { scope } = scopedAction;
241
146
  return {
242
147
  ...responseObject,
243
- scopedAction: { ...scopedAction, scope: this.toCamelCase(scope) },
244
- permit: this.toCamelCase(permit),
148
+ scopedAction: { ...scopedAction, scope: toCamelCase(scope) },
149
+ permit: toCamelCase(permit),
245
150
  };
246
151
  });
152
+ return scopedActionsResponseObjects;
247
153
  }
248
154
  static async isAuthorizedSingular(accountId, userId, resources, action) {
249
155
  const { authorizationObjects } = createAuthorizationParams(resources, action);
@@ -2,9 +2,10 @@ import { Context, ExecutionContext } from '@mondaydotcomorg/trident-backend-api'
2
2
  export declare enum PlatformProfile {
3
3
  API_INTERNAL = "api-internal",
4
4
  SLOW = "slow",
5
- INTERNAL = "internal"
5
+ INTERNAL = "internal",
6
+ APP = "app"
6
7
  }
7
- export declare function getProfile(): PlatformProfile;
8
+ export declare function getProfile(): PlatformProfile.API_INTERNAL | PlatformProfile.SLOW | PlatformProfile.INTERNAL;
8
9
  export declare function getExecutionContext(context: Context): ExecutionContext;
9
10
  export declare function getAttributionsFromApi(): {
10
11
  [key: string]: string;
@@ -1 +1 @@
1
- {"version":3,"file":"attributions-service.d.ts","sourceRoot":"","sources":["../../src/attributions-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAStF,oBAAY,eAAe;IACzB,YAAY,iBAAiB;IAC7B,IAAI,SAAS;IACb,QAAQ,aAAa;CACtB;AAED,wBAAgB,UAAU,oBAiBzB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,CAEtE;AAED,wBAAgB,sBAAsB,IAAI;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAqClE"}
1
+ {"version":3,"file":"attributions-service.d.ts","sourceRoot":"","sources":["../../src/attributions-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAStF,oBAAY,eAAe;IACzB,YAAY,iBAAiB;IAC7B,IAAI,SAAS;IACb,QAAQ,aAAa;IACrB,GAAG,QAAQ;CACZ;AAED,wBAAgB,UAAU,mFAiBzB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,CAEtE;AAED,wBAAgB,sBAAsB,IAAI;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAqClE"}
@@ -10,6 +10,7 @@ var PlatformProfile;
10
10
  PlatformProfile["API_INTERNAL"] = "api-internal";
11
11
  PlatformProfile["SLOW"] = "slow";
12
12
  PlatformProfile["INTERNAL"] = "internal";
13
+ PlatformProfile["APP"] = "app";
13
14
  })(PlatformProfile || (PlatformProfile = {}));
14
15
  function getProfile() {
15
16
  const tridentContext = Api.getPart('context');
@@ -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;AAE7F,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;AA6BD,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;IAsBxC,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAMxC,OAAO,CAAC,MAAM,CAAC,eAAe;IAmB9B,OAAO,CAAC,MAAM,CAAC,qBAAqB;mBAyBf,mBAAmB;IAoCxC,OAAO,CAAC,MAAM,CAAC,gBAAgB;mBAoBV,uBAAuB;IAsC5C,OAAO,CAAC,MAAM,CAAC,WAAW;IAI1B,OAAO,CAAC,MAAM,CAAC,mBAAmB;mBAiBb,oBAAoB;mBAUpB,oBAAoB;CAmF1C;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":"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;AAE7F,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACb,MAAM,kCAAkC,CAAC;AAY1C,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;AAeD,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;mBAkEnB,oBAAoB;mBAUpB,oBAAoB;CAmF1C;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"}
@@ -15,8 +15,6 @@ const PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH = '/internal_ms/authorization/can_acti
15
15
  const ALLOWED_SDK_PLATFORM_PROFILES_KEY = 'allowed-sdk-platform-profiles';
16
16
  const IN_RELEASE_SDK_PLATFORM_PROFILES_KEY = 'in-release-sdk-platform-profile';
17
17
  const PLATFORM_PROFILE_RELEASE_FF = 'sdk-platform-profiles';
18
- const NAVIGATE_CAN_ACTION_IN_SCOPE_TO_GRAPH_FF = 'navigate-can-action-in-scope-to-graph';
19
- const GRAPH_IS_ALLOWED_PATH = '/permissions/is-allowed';
20
18
  function setRequestFetchOptions(customMondayFetchOptions) {
21
19
  AuthorizationInternalService.setRequestFetchOptions(customMondayFetchOptions);
22
20
  }
@@ -86,114 +84,19 @@ class AuthorizationService {
86
84
  this.igniteClient.isReleased(PLATFORM_PROFILE_RELEASE_FF, { accountId, userId })) {
87
85
  return getProfile();
88
86
  }
89
- return PlatformProfile.INTERNAL;
87
+ return PlatformProfile.APP;
90
88
  }
91
89
  static async canActionInScopeMultiple(accountId, userId, scopedActions) {
92
- const shouldNavigateToGraph = Boolean(this.igniteClient?.isReleased(NAVIGATE_CAN_ACTION_IN_SCOPE_TO_GRAPH_FF, { accountId, userId }));
93
- const internalAuthToken = AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
94
- if (shouldNavigateToGraph) {
95
- const response = await this.fetchGraphIsAllowed(internalAuthToken, scopedActions);
96
- return this.mapGraphResponse(scopedActions, userId, response);
97
- }
98
90
  const profile = this.getProfile(accountId, userId);
99
- const scopedActionsPayload = this.buildScopedActionsPayload(scopedActions);
100
- const platformResponse = await this.fetchPlatformCanActions(profile, internalAuthToken, userId, scopedActionsPayload);
101
- return this.mapPlatformResponse(platformResponse);
102
- }
103
- static buildScopedActionsPayload(scopedActions) {
104
- return scopedActions.map(scopedAction => {
105
- return { ...scopedAction, scope: mapKeys(scopedAction.scope, (_, key) => snakeCase(key)) };
106
- });
107
- }
108
- static scopeToResource(scope) {
109
- if ('workspaceId' in scope) {
110
- return { resourceType: 'workspace', resourceId: scope.workspaceId };
111
- }
112
- if ('boardId' in scope) {
113
- return { resourceType: 'board', resourceId: scope.boardId };
114
- }
115
- if ('pulseId' in scope) {
116
- return { resourceType: 'pulse', resourceId: scope.pulseId };
117
- }
118
- if ('accountProductId' in scope) {
119
- return { resourceType: 'account_product', resourceId: scope.accountProductId };
120
- }
121
- if ('accountId' in scope) {
122
- return { resourceType: 'account', resourceId: scope.accountId };
123
- }
124
- throw new Error('Unsupported scope provided');
125
- }
126
- static buildGraphRequestBody(scopedActions) {
127
- const resourcesAccumulator = {};
128
- for (const { action, scope } of scopedActions) {
129
- const { resourceType, resourceId } = this.scopeToResource(scope);
130
- if (!resourcesAccumulator[resourceType]) {
131
- resourcesAccumulator[resourceType] = {};
132
- }
133
- if (!resourcesAccumulator[resourceType][resourceId]) {
134
- resourcesAccumulator[resourceType][resourceId] = new Set();
135
- }
136
- resourcesAccumulator[resourceType][resourceId].add(action);
137
- }
138
- const resourcesPayload = {};
139
- for (const [resourceType, idMap] of Object.entries(resourcesAccumulator)) {
140
- resourcesPayload[resourceType] = {};
141
- for (const [idStr, actionsSet] of Object.entries(idMap)) {
142
- const idNum = Number(idStr);
143
- resourcesPayload[resourceType][idNum] = Array.from(actionsSet);
144
- }
145
- }
146
- return resourcesPayload;
147
- }
148
- static async fetchGraphIsAllowed(internalAuthToken, scopedActions) {
149
- const httpClient = Api.getPart('httpClient');
150
- const attributionHeaders = getAttributionsFromApi();
151
- const bodyPayload = this.buildGraphRequestBody(scopedActions);
152
- try {
153
- const response = await httpClient.fetch({
154
- url: {
155
- appName: 'authorization-graph',
156
- path: GRAPH_IS_ALLOWED_PATH,
157
- },
158
- method: 'POST',
159
- headers: {
160
- Authorization: internalAuthToken,
161
- 'Content-Type': 'application/json',
162
- ...attributionHeaders,
163
- },
164
- body: JSON.stringify(bodyPayload),
165
- }, {
166
- timeout: AuthorizationInternalService.getRequestTimeout(),
167
- retryPolicy: AuthorizationInternalService.getRetriesPolicy(),
168
- });
169
- return response;
170
- }
171
- catch (err) {
172
- if (err instanceof HttpFetcherError) {
173
- AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
174
- }
175
- throw err;
176
- }
177
- }
178
- static mapGraphResponse(scopedActions, userId, graphResponse) {
179
- const resources = graphResponse ?? {};
180
- return scopedActions.map(scopedAction => {
181
- const { action, scope } = scopedAction;
182
- const { resourceType, resourceId } = this.scopeToResource(scope);
183
- const permissionResult = resources?.[resourceType]?.[String(resourceId)]?.[action];
184
- const permit = {
185
- can: permissionResult?.can ?? false,
186
- reason: { key: permissionResult?.reason ?? 'unknown' },
187
- technicalReason: 0,
188
- };
189
- return { scopedAction, permit };
91
+ const internalAuthToken = AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
92
+ const scopedActionsPayload = scopedActions.map(scopedAction => {
93
+ return { ...scopedAction, scope: mapKeys(scopedAction.scope, (_, key) => snakeCase(key)) }; // for example: { workspaceId: 1 } => { workspace_id: 1 }
190
94
  });
191
- }
192
- static async fetchPlatformCanActions(profile, internalAuthToken, userId, scopedActionsPayload) {
193
95
  const attributionHeaders = getAttributionsFromApi();
194
96
  const httpClient = Api.getPart('httpClient');
97
+ let response;
195
98
  try {
196
- const response = await httpClient.fetch({
99
+ response = await httpClient.fetch({
197
100
  url: {
198
101
  appName: 'platform',
199
102
  path: PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH,
@@ -205,37 +108,40 @@ class AuthorizationService {
205
108
  'Content-Type': 'application/json',
206
109
  ...attributionHeaders,
207
110
  },
208
- body: JSON.stringify({ user_id: userId, scoped_actions: scopedActionsPayload }),
111
+ body: JSON.stringify({
112
+ user_id: userId,
113
+ scoped_actions: scopedActionsPayload,
114
+ }),
209
115
  }, {
210
116
  timeout: AuthorizationInternalService.getRequestTimeout(),
211
117
  retryPolicy: AuthorizationInternalService.getRetriesPolicy(),
212
118
  });
213
- return response;
214
119
  }
215
120
  catch (err) {
216
121
  if (err instanceof HttpFetcherError) {
217
122
  AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
218
123
  }
219
- throw err;
124
+ else {
125
+ throw err;
126
+ }
127
+ }
128
+ function toCamelCase(obj) {
129
+ return mapKeys(obj, (_, key) => camelCase(key));
220
130
  }
221
- }
222
- static toCamelCase(obj) {
223
- return mapKeys(obj, (_, key) => camelCase(key));
224
- }
225
- static mapPlatformResponse(response) {
226
131
  if (!response) {
227
132
  logger.error({ tag: 'authorization-service', response }, 'AuthorizationService: missing response');
228
133
  throw new Error('AuthorizationService: missing response');
229
134
  }
230
- return response.result.map(responseObject => {
135
+ const scopedActionsResponseObjects = response.result.map(responseObject => {
231
136
  const { scopedAction, permit } = responseObject;
232
137
  const { scope } = scopedAction;
233
138
  return {
234
139
  ...responseObject,
235
- scopedAction: { ...scopedAction, scope: this.toCamelCase(scope) },
236
- permit: this.toCamelCase(permit),
140
+ scopedAction: { ...scopedAction, scope: toCamelCase(scope) },
141
+ permit: toCamelCase(permit),
237
142
  };
238
143
  });
144
+ return scopedActionsResponseObjects;
239
145
  }
240
146
  static async isAuthorizedSingular(accountId, userId, resources, action) {
241
147
  const { authorizationObjects } = createAuthorizationParams(resources, action);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mondaydotcomorg/monday-authorization",
3
- "version": "3.2.3-feature-bashanye-navigate-can-action-in-scope-to-graph-af77c6b",
3
+ "version": "3.2.4",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "BSD-3-Clause",
@@ -46,7 +46,9 @@
46
46
  "typescript": "^5.2.2"
47
47
  },
48
48
  "files": [
49
- "dist/"
49
+ "dist/",
50
+ "src/",
51
+ "dist/node_modules/lodash-cjs/"
50
52
  ],
51
53
  "eslintConfig": {
52
54
  "extends": "@mondaydotcomorg/trident-library",
@@ -62,4 +64,4 @@
62
64
  "url": "https://github.com/DaPulse/authorization-domain.git",
63
65
  "directory": "packages/monday-authorization"
64
66
  }
65
- }
67
+ }
@@ -0,0 +1,93 @@
1
+ import { Api, Context, ExecutionContext } from '@mondaydotcomorg/trident-backend-api';
2
+ import { logger } from './authorization-internal-service';
3
+
4
+ const APP_NAME_VARIABLE_KEY = 'APP_NAME';
5
+ const APP_NAME_HEADER_NAME = 'x-caller-app-name-from-sdk';
6
+ const FROM_SDK_HEADER_SUFFIX = `-from-sdk`;
7
+
8
+ let didSendFailureLogOnce = false;
9
+
10
+ export enum PlatformProfile {
11
+ API_INTERNAL = 'api-internal',
12
+ SLOW = 'slow',
13
+ INTERNAL = 'internal',
14
+ APP = 'app',
15
+ }
16
+
17
+ export function getProfile() {
18
+ const tridentContext = Api.getPart('context');
19
+ if (!tridentContext) {
20
+ return PlatformProfile.INTERNAL;
21
+ }
22
+ const { mondayRequestSource } = getExecutionContext(tridentContext);
23
+
24
+ switch (mondayRequestSource) {
25
+ case 'api': {
26
+ return PlatformProfile.API_INTERNAL;
27
+ }
28
+ case 'slow': {
29
+ return PlatformProfile.SLOW;
30
+ }
31
+ default:
32
+ return PlatformProfile.INTERNAL;
33
+ }
34
+ }
35
+
36
+ export function getExecutionContext(context: Context): ExecutionContext {
37
+ return context.execution.get();
38
+ }
39
+
40
+ export function getAttributionsFromApi(): { [key: string]: string } {
41
+ const callerAppNameFromSdk = {
42
+ [APP_NAME_HEADER_NAME]: tryJsonParse(getEnvVariable(APP_NAME_VARIABLE_KEY)),
43
+ };
44
+
45
+ try {
46
+ const tridentContext = Api.getPart('context');
47
+
48
+ if (!tridentContext) {
49
+ return callerAppNameFromSdk;
50
+ }
51
+
52
+ const { runtimeAttributions } = tridentContext;
53
+ const runtimeAttributionsOutgoingHeaders = runtimeAttributions?.buildOutgoingHeaders('HTTP_INTERNAL');
54
+
55
+ if (!runtimeAttributionsOutgoingHeaders) {
56
+ return callerAppNameFromSdk;
57
+ }
58
+
59
+ const attributionsHeaders = Object.fromEntries(runtimeAttributionsOutgoingHeaders);
60
+
61
+ const attributionHeadersFromSdk = {};
62
+ Object.keys(attributionsHeaders).forEach(function (key) {
63
+ attributionHeadersFromSdk[`${key}${FROM_SDK_HEADER_SUFFIX}`] = attributionsHeaders[key];
64
+ });
65
+
66
+ return attributionHeadersFromSdk;
67
+ } catch (error) {
68
+ if (!didSendFailureLogOnce) {
69
+ logger.warn(
70
+ { tag: 'authorization-service', error },
71
+ 'Failed to generate attributions headers from the API. Unexpected error while extracting headers. It may be caused by out of date Trident version.'
72
+ );
73
+ didSendFailureLogOnce = true;
74
+ }
75
+ return callerAppNameFromSdk;
76
+ }
77
+ }
78
+
79
+ function getEnvVariable(key: string) {
80
+ const envVar = process.env[key] || process.env[key.toUpperCase()] || process.env[key.toLowerCase()];
81
+ return envVar;
82
+ }
83
+
84
+ function tryJsonParse(value: string | undefined) {
85
+ if (!value) {
86
+ return value;
87
+ }
88
+ try {
89
+ return JSON.parse(value);
90
+ } catch (_err) {
91
+ return value;
92
+ }
93
+ }