@mondaydotcomorg/monday-authorization 3.2.3-feature-bashanye-navigate-can-action-in-scope-to-graph-af77c6b → 3.3.0-feat-add-graph-api-routing-support-2d70b30

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 (43) hide show
  1. package/README.md +29 -0
  2. package/dist/authorization-service.d.ts +0 -8
  3. package/dist/authorization-service.d.ts.map +1 -1
  4. package/dist/authorization-service.js +39 -151
  5. package/dist/clients/graph-api.client.d.ts +24 -0
  6. package/dist/clients/graph-api.client.d.ts.map +1 -0
  7. package/dist/clients/graph-api.client.js +123 -0
  8. package/dist/clients/platform-api.client.d.ts +31 -0
  9. package/dist/clients/platform-api.client.d.ts.map +1 -0
  10. package/dist/clients/platform-api.client.js +89 -0
  11. package/dist/esm/authorization-service.d.ts +0 -8
  12. package/dist/esm/authorization-service.d.ts.map +1 -1
  13. package/dist/esm/authorization-service.mjs +40 -146
  14. package/dist/esm/clients/graph-api.client.d.ts +24 -0
  15. package/dist/esm/clients/graph-api.client.d.ts.map +1 -0
  16. package/dist/esm/clients/graph-api.client.mjs +121 -0
  17. package/dist/esm/clients/platform-api.client.d.ts +31 -0
  18. package/dist/esm/clients/platform-api.client.d.ts.map +1 -0
  19. package/dist/esm/clients/platform-api.client.mjs +87 -0
  20. package/dist/esm/prometheus-service.d.ts +3 -1
  21. package/dist/esm/prometheus-service.d.ts.map +1 -1
  22. package/dist/esm/prometheus-service.mjs +61 -5
  23. package/dist/esm/testKit/index.d.ts.map +1 -1
  24. package/dist/esm/testKit/index.mjs +9 -7
  25. package/dist/esm/types/graph-api.types.d.ts +15 -0
  26. package/dist/esm/types/graph-api.types.d.ts.map +1 -0
  27. package/dist/esm/types/graph-api.types.mjs +1 -0
  28. package/dist/esm/utils/authorization.utils.d.ts +22 -0
  29. package/dist/esm/utils/authorization.utils.d.ts.map +1 -0
  30. package/dist/esm/utils/authorization.utils.mjs +39 -0
  31. package/dist/prometheus-service.d.ts +3 -1
  32. package/dist/prometheus-service.d.ts.map +1 -1
  33. package/dist/prometheus-service.js +62 -4
  34. package/dist/testKit/index.d.ts.map +1 -1
  35. package/dist/testKit/index.js +9 -7
  36. package/dist/types/graph-api.types.d.ts +15 -0
  37. package/dist/types/graph-api.types.d.ts.map +1 -0
  38. package/dist/types/graph-api.types.js +1 -0
  39. package/dist/utils/authorization.utils.d.ts +22 -0
  40. package/dist/utils/authorization.utils.d.ts.map +1 -0
  41. package/dist/utils/authorization.utils.js +49 -0
  42. package/package.json +2 -2
  43. package/CHANGELOG.md +0 -46
@@ -9,18 +9,20 @@ const clearTestPermittedActions = () => {
9
9
  testPermittedActions = [];
10
10
  };
11
11
  const isActionAuthorized = (accountId, userId, resources, action) => {
12
+ // If no resources to check, deny access
13
+ if (resources.length === 0) {
14
+ return { isAuthorized: false };
15
+ }
12
16
  return {
13
- isAuthorized: resources.every(_ => {
17
+ isAuthorized: resources.every(resource => {
14
18
  return testPermittedActions.some(combination => {
15
19
  return (combination.accountId === accountId &&
16
20
  combination.userId === userId &&
17
21
  combination.action === action &&
18
22
  combination.resources.some(combinationResource => {
19
- return resources.some(resource => {
20
- return (combinationResource.id === resource.id &&
21
- combinationResource.type === resource.type &&
22
- JSON.stringify(combinationResource.wrapperData) === JSON.stringify(resource.wrapperData));
23
- });
23
+ return (combinationResource.id === resource.id &&
24
+ combinationResource.type === resource.type &&
25
+ JSON.stringify(combinationResource.wrapperData) === JSON.stringify(resource.wrapperData));
24
26
  }));
25
27
  });
26
28
  }),
@@ -32,11 +34,11 @@ const getTestAuthorizationMiddleware = (action, resourceGetter, contextGetter) =
32
34
  const { userId, accountId } = contextGetter(request);
33
35
  const resources = resourceGetter(request);
34
36
  const { isAuthorized } = isActionAuthorized(accountId, userId, resources, action);
35
- AuthorizationInternalService.markAuthorized(request);
36
37
  if (!isAuthorized) {
37
38
  response.status(403).json({ message: 'Access denied' });
38
39
  return;
39
40
  }
41
+ AuthorizationInternalService.markAuthorized(request);
40
42
  next();
41
43
  };
42
44
  };
@@ -0,0 +1,15 @@
1
+ export type ResourceType = string;
2
+ export type ResourceId = number;
3
+ export type ActionName = string;
4
+ export type GraphIsAllowedDto = Record<ResourceType, Record<ResourceId, ActionName[]>>;
5
+ export type GraphPermissionResult = {
6
+ can: boolean;
7
+ reason: string | {
8
+ key: string;
9
+ additionalOptions?: Record<string, string>;
10
+ technicalReason?: number;
11
+ };
12
+ };
13
+ export type GraphPermissionResults = Record<ActionName, GraphPermissionResult>;
14
+ export type GraphIsAllowedResponse = Record<ResourceType, Record<string, GraphPermissionResults>>;
15
+ //# sourceMappingURL=graph-api.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-api.types.d.ts","sourceRoot":"","sources":["../../../src/types/graph-api.types.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAClC,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAChC,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAEhC,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;AAEvF,MAAM,MAAM,qBAAqB,GAAG;IAClC,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EACF,MAAM,GACN;QACE,GAAG,EAAE,MAAM,CAAC;QACZ,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC3C,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;CACP,CAAC;AAGF,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC,UAAU,EAAE,qBAAqB,CAAC,CAAC;AAI/E,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,22 @@
1
+ import { ScopeOptions } from '../types/scoped-actions-contracts';
2
+ import { ResourceType, ResourceId } from '../types/graph-api.types';
3
+ export type CamelCase<S extends string> = S extends `${infer F}_${infer R}` ? `${F}${Capitalize<CamelCase<R>>}` : S;
4
+ export type CamelCaseKeys<T> = T extends object ? {
5
+ [K in keyof T as K extends string ? CamelCase<K> : K]: CamelCaseKeys<T[K]>;
6
+ } : T;
7
+ /**
8
+ * Converts a scope object to resource type and resource ID
9
+ */
10
+ export declare function scopeToResource(scope: ScopeOptions): {
11
+ resourceType: ResourceType;
12
+ resourceId: ResourceId;
13
+ };
14
+ /**
15
+ * Converts object keys from snake_case to camelCase
16
+ */
17
+ export declare function toCamelCase<T extends object>(obj: T): CamelCaseKeys<T>;
18
+ /**
19
+ * Converts object keys from camelCase to snake_case
20
+ */
21
+ export declare function toSnakeCase<T extends object>(obj: T): Record<string, any>;
22
+ //# sourceMappingURL=authorization.utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorization.utils.d.ts","sourceRoot":"","sources":["../../../src/utils/authorization.utils.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEpE,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,IAAI,MAAM,CAAC,EAAE,GAAG,GAAG,CAAC,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACpH,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,GAC3C;KAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GAC9E,CAAC,CAAC;AAEN;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG;IAAE,YAAY,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,UAAU,CAAA;CAAE,CAkB3G;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAEtE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAEzE"}
@@ -0,0 +1,39 @@
1
+ import snakeCase from 'lodash/snakeCase.js';
2
+ import camelCase from 'lodash/camelCase.js';
3
+ import mapKeys from 'lodash/mapKeys.js';
4
+
5
+ /**
6
+ * Converts a scope object to resource type and resource ID
7
+ */
8
+ function scopeToResource(scope) {
9
+ if ('workspaceId' in scope) {
10
+ return { resourceType: 'workspace', resourceId: scope.workspaceId };
11
+ }
12
+ if ('boardId' in scope) {
13
+ return { resourceType: 'board', resourceId: scope.boardId };
14
+ }
15
+ if ('pulseId' in scope) {
16
+ return { resourceType: 'pulse', resourceId: scope.pulseId };
17
+ }
18
+ if ('accountProductId' in scope) {
19
+ return { resourceType: 'account_product', resourceId: scope.accountProductId };
20
+ }
21
+ if ('accountId' in scope) {
22
+ return { resourceType: 'account', resourceId: scope.accountId };
23
+ }
24
+ throw new Error('Unsupported scope provided');
25
+ }
26
+ /**
27
+ * Converts object keys from snake_case to camelCase
28
+ */
29
+ function toCamelCase(obj) {
30
+ return mapKeys(obj, (_, key) => camelCase(key));
31
+ }
32
+ /**
33
+ * Converts object keys from camelCase to snake_case
34
+ */
35
+ function toSnakeCase(obj) {
36
+ return mapKeys(obj, (_, key) => snakeCase(key));
37
+ }
38
+
39
+ export { scopeToResource, toCamelCase, toSnakeCase };
@@ -6,5 +6,7 @@ export declare const METRICS: {
6
6
  };
7
7
  export declare function setPrometheus(customPrometheus: any): void;
8
8
  export declare function getMetricsManager(): any;
9
- export declare function sendAuthorizationCheckResponseTimeMetric(resourceType: string, action: Action, isAuthorized: boolean, responseStatus: number, time: number): void;
9
+ export declare function sendAuthorizationCheckResponseTimeMetric(resourceType: string, action: Action, isAuthorized: boolean, responseStatus: number, time: number, apiType?: 'platform' | 'graph'): void;
10
+ export declare function incrementAuthorizationSuccess(resourceType: string, action: Action, apiType: 'platform' | 'graph'): void;
11
+ export declare function incrementAuthorizationError(resourceType: string, action: Action, statusCode: number, apiType: 'platform' | 'graph'): void;
10
12
  //# sourceMappingURL=prometheus-service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prometheus-service.d.ts","sourceRoot":"","sources":["../src/prometheus-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAKzC,eAAO,MAAM,OAAO;;;;CAInB,CAAC;AAQF,wBAAgB,aAAa,CAAC,gBAAgB,KAAA,QAU7C;AAED,wBAAgB,iBAAiB,QAEhC;AAED,wBAAgB,wCAAwC,CACtD,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,OAAO,EACrB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,QASb"}
1
+ {"version":3,"file":"prometheus-service.d.ts","sourceRoot":"","sources":["../src/prometheus-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAOzC,eAAO,MAAM,OAAO;;;;CAInB,CAAC;AAQF,wBAAgB,aAAa,CAAC,gBAAgB,KAAA,QAqB7C;AAED,wBAAgB,iBAAiB,QAEhC;AAED,wBAAgB,wCAAwC,CACtD,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,OAAO,EACrB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,UAAU,GAAG,OAAoB,QAW3C;AAcD,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,QAQhH;AAED,wBAAgB,2BAA2B,CACzC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,UAAU,GAAG,OAAO,QAS9B"}
@@ -2,6 +2,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
3
  let prometheus = null;
4
4
  let authorizationCheckResponseTimeMetric = null;
5
+ let authorizationSuccessMetric = null;
6
+ let authorizationErrorMetric = null;
5
7
  const METRICS = {
6
8
  AUTHORIZATION_CHECK: 'authorization_check',
7
9
  AUTHORIZATION_CHECKS_PER_REQUEST: 'authorization_checks_per_request',
@@ -9,29 +11,85 @@ const METRICS = {
9
11
  };
10
12
  const authorizationCheckResponseTimeMetricConfig = {
11
13
  name: METRICS.AUTHORIZATION_CHECK_RESPONSE_TIME,
12
- labels: ['resourceType', 'action', 'isAuthorized', 'responseStatus'],
14
+ labels: ['resourceType', 'action', 'isAuthorized', 'responseStatus', 'apiType'],
13
15
  description: 'Authorization check response time summary',
14
16
  };
15
17
  function setPrometheus(customPrometheus) {
16
18
  prometheus = customPrometheus;
19
+ if (!prometheus) {
20
+ authorizationCheckResponseTimeMetric = null;
21
+ authorizationSuccessMetric = null;
22
+ authorizationErrorMetric = null;
23
+ return;
24
+ }
17
25
  const { METRICS_TYPES } = prometheus;
18
- authorizationCheckResponseTimeMetric = getMetricsManager().addMetric(METRICS_TYPES.SUMMARY, authorizationCheckResponseTimeMetricConfig.name, authorizationCheckResponseTimeMetricConfig.labels, authorizationCheckResponseTimeMetricConfig.description);
26
+ const metricsManager = getMetricsManager();
27
+ if (metricsManager) {
28
+ authorizationCheckResponseTimeMetric = metricsManager.addMetric(METRICS_TYPES.SUMMARY, authorizationCheckResponseTimeMetricConfig.name, authorizationCheckResponseTimeMetricConfig.labels, authorizationCheckResponseTimeMetricConfig.description);
29
+ initializeAdditionalMetrics();
30
+ }
19
31
  }
20
32
  function getMetricsManager() {
21
33
  return prometheus?.metricsManager;
22
34
  }
23
- function sendAuthorizationCheckResponseTimeMetric(resourceType, action, isAuthorized, responseStatus, time) {
35
+ function sendAuthorizationCheckResponseTimeMetric(resourceType, action, isAuthorized, responseStatus, time, apiType = 'platform') {
24
36
  try {
25
37
  if (authorizationCheckResponseTimeMetric) {
26
- authorizationCheckResponseTimeMetric.labels(resourceType, action, isAuthorized, responseStatus).observe(time);
38
+ authorizationCheckResponseTimeMetric
39
+ .labels(resourceType, action, isAuthorized, responseStatus, apiType)
40
+ .observe(time);
41
+ }
42
+ }
43
+ catch (e) {
44
+ // ignore
45
+ }
46
+ }
47
+ const authorizationSuccessMetricConfig = {
48
+ name: 'authorization_success_total',
49
+ labels: ['resourceType', 'action', 'apiType'],
50
+ description: 'Total number of successful authorization checks',
51
+ };
52
+ const authorizationErrorMetricConfig = {
53
+ name: 'authorization_error_total',
54
+ labels: ['resourceType', 'action', 'statusCode', 'apiType'],
55
+ description: 'Total number of authorization errors',
56
+ };
57
+ function incrementAuthorizationSuccess(resourceType, action, apiType) {
58
+ try {
59
+ if (authorizationSuccessMetric) {
60
+ authorizationSuccessMetric.labels(resourceType, action, apiType).inc();
27
61
  }
28
62
  }
29
63
  catch (e) {
30
64
  // ignore
31
65
  }
32
66
  }
67
+ function incrementAuthorizationError(resourceType, action, statusCode, apiType) {
68
+ try {
69
+ if (authorizationErrorMetric) {
70
+ authorizationErrorMetric.labels(resourceType, action, statusCode, apiType).inc();
71
+ }
72
+ }
73
+ catch (e) {
74
+ // ignore
75
+ }
76
+ }
77
+ // Initialize additional metrics when prometheus is set
78
+ function initializeAdditionalMetrics() {
79
+ if (!prometheus) {
80
+ return;
81
+ }
82
+ const { METRICS_TYPES } = prometheus;
83
+ const metricsManager = getMetricsManager();
84
+ if (metricsManager) {
85
+ authorizationSuccessMetric = metricsManager.addMetric(METRICS_TYPES.COUNTER, authorizationSuccessMetricConfig.name, authorizationSuccessMetricConfig.labels, authorizationSuccessMetricConfig.description);
86
+ authorizationErrorMetric = metricsManager.addMetric(METRICS_TYPES.COUNTER, authorizationErrorMetricConfig.name, authorizationErrorMetricConfig.labels, authorizationErrorMetricConfig.description);
87
+ }
88
+ }
33
89
 
34
90
  exports.METRICS = METRICS;
35
91
  exports.getMetricsManager = getMetricsManager;
92
+ exports.incrementAuthorizationError = incrementAuthorizationError;
93
+ exports.incrementAuthorizationSuccess = incrementAuthorizationSuccess;
36
94
  exports.sendAuthorizationCheckResponseTimeMetric = sendAuthorizationCheckResponseTimeMetric;
37
95
  exports.setPrometheus = setPrometheus;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testKit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAG9G,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAGF,eAAO,MAAM,sBAAsB,GAAI,WAAW,MAAM,EAAE,QAAQ,MAAM,EAAE,WAAW,QAAQ,EAAE,EAAE,QAAQ,MAAM,SAE9G,CAAC;AAEF,eAAO,MAAM,yBAAyB,YAErC,CAAC;AAyBF,eAAO,MAAM,8BAA8B,GACzC,QAAQ,MAAM,EACd,gBAAgB,cAAc,EAC9B,gBAAgB,aAAa,MAG3B,SAAS,WAAW,EACpB,UAAU,YAAY,EACtB,MAAM,YAAY,KACjB,OAAO,CAAC,IAAI,CAYhB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testKit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAG9G,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAGF,eAAO,MAAM,sBAAsB,GAAI,WAAW,MAAM,EAAE,QAAQ,MAAM,EAAE,WAAW,QAAQ,EAAE,EAAE,QAAQ,MAAM,SAE9G,CAAC;AAEF,eAAO,MAAM,yBAAyB,YAErC,CAAC;AA4BF,eAAO,MAAM,8BAA8B,GACzC,QAAQ,MAAM,EACd,gBAAgB,cAAc,EAC9B,gBAAgB,aAAa,MAG3B,SAAS,WAAW,EACpB,UAAU,YAAY,EACtB,MAAM,YAAY,KACjB,OAAO,CAAC,IAAI,CAYhB,CAAC"}
@@ -11,18 +11,20 @@ const clearTestPermittedActions = () => {
11
11
  testPermittedActions = [];
12
12
  };
13
13
  const isActionAuthorized = (accountId, userId, resources, action) => {
14
+ // If no resources to check, deny access
15
+ if (resources.length === 0) {
16
+ return { isAuthorized: false };
17
+ }
14
18
  return {
15
- isAuthorized: resources.every(_ => {
19
+ isAuthorized: resources.every(resource => {
16
20
  return testPermittedActions.some(combination => {
17
21
  return (combination.accountId === accountId &&
18
22
  combination.userId === userId &&
19
23
  combination.action === action &&
20
24
  combination.resources.some(combinationResource => {
21
- return resources.some(resource => {
22
- return (combinationResource.id === resource.id &&
23
- combinationResource.type === resource.type &&
24
- JSON.stringify(combinationResource.wrapperData) === JSON.stringify(resource.wrapperData));
25
- });
25
+ return (combinationResource.id === resource.id &&
26
+ combinationResource.type === resource.type &&
27
+ JSON.stringify(combinationResource.wrapperData) === JSON.stringify(resource.wrapperData));
26
28
  }));
27
29
  });
28
30
  }),
@@ -34,11 +36,11 @@ const getTestAuthorizationMiddleware = (action, resourceGetter, contextGetter) =
34
36
  const { userId, accountId } = contextGetter(request);
35
37
  const resources = resourceGetter(request);
36
38
  const { isAuthorized } = isActionAuthorized(accountId, userId, resources, action);
37
- authorizationInternalService.AuthorizationInternalService.markAuthorized(request);
38
39
  if (!isAuthorized) {
39
40
  response.status(403).json({ message: 'Access denied' });
40
41
  return;
41
42
  }
43
+ authorizationInternalService.AuthorizationInternalService.markAuthorized(request);
42
44
  next();
43
45
  };
44
46
  };
@@ -0,0 +1,15 @@
1
+ export type ResourceType = string;
2
+ export type ResourceId = number;
3
+ export type ActionName = string;
4
+ export type GraphIsAllowedDto = Record<ResourceType, Record<ResourceId, ActionName[]>>;
5
+ export type GraphPermissionResult = {
6
+ can: boolean;
7
+ reason: string | {
8
+ key: string;
9
+ additionalOptions?: Record<string, string>;
10
+ technicalReason?: number;
11
+ };
12
+ };
13
+ export type GraphPermissionResults = Record<ActionName, GraphPermissionResult>;
14
+ export type GraphIsAllowedResponse = Record<ResourceType, Record<string, GraphPermissionResults>>;
15
+ //# sourceMappingURL=graph-api.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-api.types.d.ts","sourceRoot":"","sources":["../../src/types/graph-api.types.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAClC,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAChC,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAEhC,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;AAEvF,MAAM,MAAM,qBAAqB,GAAG;IAClC,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EACF,MAAM,GACN;QACE,GAAG,EAAE,MAAM,CAAC;QACZ,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC3C,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;CACP,CAAC;AAGF,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC,UAAU,EAAE,qBAAqB,CAAC,CAAC;AAI/E,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,22 @@
1
+ import { ScopeOptions } from '../types/scoped-actions-contracts';
2
+ import { ResourceType, ResourceId } from '../types/graph-api.types';
3
+ export type CamelCase<S extends string> = S extends `${infer F}_${infer R}` ? `${F}${Capitalize<CamelCase<R>>}` : S;
4
+ export type CamelCaseKeys<T> = T extends object ? {
5
+ [K in keyof T as K extends string ? CamelCase<K> : K]: CamelCaseKeys<T[K]>;
6
+ } : T;
7
+ /**
8
+ * Converts a scope object to resource type and resource ID
9
+ */
10
+ export declare function scopeToResource(scope: ScopeOptions): {
11
+ resourceType: ResourceType;
12
+ resourceId: ResourceId;
13
+ };
14
+ /**
15
+ * Converts object keys from snake_case to camelCase
16
+ */
17
+ export declare function toCamelCase<T extends object>(obj: T): CamelCaseKeys<T>;
18
+ /**
19
+ * Converts object keys from camelCase to snake_case
20
+ */
21
+ export declare function toSnakeCase<T extends object>(obj: T): Record<string, any>;
22
+ //# sourceMappingURL=authorization.utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorization.utils.d.ts","sourceRoot":"","sources":["../../src/utils/authorization.utils.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEpE,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,IAAI,MAAM,CAAC,EAAE,GAAG,GAAG,CAAC,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACpH,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,GAC3C;KAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GAC9E,CAAC,CAAC;AAEN;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG;IAAE,YAAY,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,UAAU,CAAA;CAAE,CAkB3G;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAEtE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAEzE"}
@@ -0,0 +1,49 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ const snakeCase = require('lodash/snakeCase.js');
4
+ const camelCase = require('lodash/camelCase.js');
5
+ const mapKeys = require('lodash/mapKeys.js');
6
+
7
+ const _interopDefault = e => e && e.__esModule ? e : { default: e };
8
+
9
+ const snakeCase__default = /*#__PURE__*/_interopDefault(snakeCase);
10
+ const camelCase__default = /*#__PURE__*/_interopDefault(camelCase);
11
+ const mapKeys__default = /*#__PURE__*/_interopDefault(mapKeys);
12
+
13
+ /**
14
+ * Converts a scope object to resource type and resource ID
15
+ */
16
+ function scopeToResource(scope) {
17
+ if ('workspaceId' in scope) {
18
+ return { resourceType: 'workspace', resourceId: scope.workspaceId };
19
+ }
20
+ if ('boardId' in scope) {
21
+ return { resourceType: 'board', resourceId: scope.boardId };
22
+ }
23
+ if ('pulseId' in scope) {
24
+ return { resourceType: 'pulse', resourceId: scope.pulseId };
25
+ }
26
+ if ('accountProductId' in scope) {
27
+ return { resourceType: 'account_product', resourceId: scope.accountProductId };
28
+ }
29
+ if ('accountId' in scope) {
30
+ return { resourceType: 'account', resourceId: scope.accountId };
31
+ }
32
+ throw new Error('Unsupported scope provided');
33
+ }
34
+ /**
35
+ * Converts object keys from snake_case to camelCase
36
+ */
37
+ function toCamelCase(obj) {
38
+ return mapKeys__default.default(obj, (_, key) => camelCase__default.default(key));
39
+ }
40
+ /**
41
+ * Converts object keys from camelCase to snake_case
42
+ */
43
+ function toSnakeCase(obj) {
44
+ return mapKeys__default.default(obj, (_, key) => snakeCase__default.default(key));
45
+ }
46
+
47
+ exports.scopeToResource = scopeToResource;
48
+ exports.toCamelCase = toCamelCase;
49
+ exports.toSnakeCase = toSnakeCase;
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.3.0-feat-add-graph-api-routing-support-2d70b30",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "BSD-3-Clause",
@@ -62,4 +62,4 @@
62
62
  "url": "https://github.com/DaPulse/authorization-domain.git",
63
63
  "directory": "packages/monday-authorization"
64
64
  }
65
- }
65
+ }
package/CHANGELOG.md DELETED
@@ -1,46 +0,0 @@
1
- # Change Log
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](http://keepachangelog.com/)
6
- and this project adheres to [Semantic Versioning](http://semver.org/).
7
-
8
- ## [2.0.0] - 2025-04-07
9
-
10
- ### ⚠ MAJOR CHANGE - PLEASE READ
11
-
12
- ### Fixed
13
-
14
- - Calls to the monolith will be spread across the different profiles - `api-internal`, `slow` and `internal` (originally, all the calls to the platform went directly to `monday-app`)
15
-
16
- ## [1.2.9] - 2024-10-06
17
-
18
- ### Added
19
-
20
- - [`authz/bashanye/add-async-resource-attributes-support`](https://github.com/DaPulse/monday-npm-packages/pull/6859)
21
- - `AuthorizationAttributesService` - now supports async upsert and delete - requests sent through SNS-SQS).
22
-
23
- ## [1.2.3] - 2024-06-10
24
-
25
- ### Added
26
-
27
- - [`feature/yarden/resource-attributes-api-support-authz-sdk (#5826)`](https://github.com/DaPulse/monday-npm-packages/pull/5826)
28
- - `AuthorizationAttributesService` - now supports upsert (`upsertResourceAttributesSync`) and delete (`deleteResourceAttributesSync`) resource attributes in the authorization MS
29
-
30
- ## [1.2.0] - 2024-01-05
31
-
32
- ### Added
33
-
34
- - `isAuthorized` now return the unauthorized objects - regardless to the unauthorized ids (which may be missing resource ids if resource has no id, like `feature` e.g.)
35
-
36
- ## [1.1.0] - 2023-08-09
37
-
38
- ### ⚠ BREAKING CHANGES
39
-
40
- - `canActionInScope` now returns an object of type `{ can: boolean; reason: string; }` instead of `boolean`.
41
- This version is considered minor because no one uses this function yet.
42
-
43
- ### Changed
44
-
45
- - [`feature/idan/can-action-in-scope/change-behavior-on-error (#3689)`](https://github.com/DaPulse/monday-npm-packages/pull/3689)
46
- - `canActionInScope`, `canActionInScopeMultiple` and `isAuthorized` are now throwing an error instead of returning `false` when an error occurs as part of the authorization http request (status code is not 2XX)