@mondaydotcomorg/monday-authorization 1.1.9-featureorcomonday-jwt-ts.472 → 1.1.9-featureyardenresource-attributes-api-support-authz-sdk.1565

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](http://keepachangelog.com/)
6
6
  and this project adheres to [Semantic Versioning](http://semver.org/).
7
7
 
8
+ ## [1.2.0] - 2024-01-05
9
+ ### Added
10
+ - `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.)
11
+
8
12
  ## [1.1.0] - 2023-08-09
9
13
 
10
14
  ### ⚠ BREAKING CHANGES
@@ -0,0 +1,11 @@
1
+ import { ResourceAttributeAssignment } from 'lib/types/authorization-attributes-contracts';
2
+ import { Resource } from 'lib/types/general';
3
+ export declare class AuthorizationAttributesService {
4
+ static upsertResourceAttributesSync(accountId: number, userId: number, resourceAttributesAssignments: ResourceAttributeAssignment[]): Promise<{
5
+ attributes: any;
6
+ }>;
7
+ static deleteResourceAttributesSync(accountId: number, resource: Resource, attributeKeys: string[]): Promise<{
8
+ attributes: any;
9
+ }>;
10
+ private static getResourceAttributesUrl;
11
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.AuthorizationAttributesService = void 0;
13
+ const monday_fetch_1 = require("@mondaydotcomorg/monday-fetch");
14
+ const authorization_internal_service_1 = require("lib/authorization-internal-service");
15
+ // TODO : Delete this once done
16
+ class AuthorizationAttributesService {
17
+ static upsertResourceAttributesSync(accountId, userId, resourceAttributesAssignments) {
18
+ return __awaiter(this, void 0, void 0, function* () {
19
+ const internalAuthToken = authorization_internal_service_1.AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
20
+ const response = yield (0, monday_fetch_1.fetch)(this.getResourceAttributesUrl(accountId), {
21
+ method: 'POST',
22
+ headers: { Authorization: internalAuthToken, 'Content-Type': 'application/json' },
23
+ timeout: authorization_internal_service_1.AuthorizationInternalService.getRequestTimeout(),
24
+ body: JSON.stringify({ resourceAttributesAssignments }),
25
+ }, authorization_internal_service_1.AuthorizationInternalService.getRequestFetchOptions());
26
+ const responseBody = yield response.json();
27
+ authorization_internal_service_1.AuthorizationInternalService.throwOnHttpErrorIfNeeded(response, 'upsertResourceAttributesSync');
28
+ return { attributes: responseBody['attributes'] };
29
+ });
30
+ }
31
+ static deleteResourceAttributesSync(accountId, resource, attributeKeys) {
32
+ return __awaiter(this, void 0, void 0, function* () {
33
+ const internalAuthToken = authorization_internal_service_1.AuthorizationInternalService.generateInternalAuthToken(accountId, 0);
34
+ const url = `${this.getResourceAttributesUrl(accountId)}/${resource.type}/${resource.id}`;
35
+ const response = yield (0, monday_fetch_1.fetch)(url, {
36
+ method: 'DELETE',
37
+ headers: { Authorization: internalAuthToken, 'Content-Type': 'application/json' },
38
+ timeout: authorization_internal_service_1.AuthorizationInternalService.getRequestTimeout(),
39
+ body: JSON.stringify({ keys: attributeKeys }),
40
+ }, authorization_internal_service_1.AuthorizationInternalService.getRequestFetchOptions());
41
+ const responseBody = yield response.json();
42
+ authorization_internal_service_1.AuthorizationInternalService.throwOnHttpErrorIfNeeded(response, 'deleteResourceAttributesSync');
43
+ return { attributes: responseBody['attributes'] };
44
+ });
45
+ }
46
+ static getResourceAttributesUrl(accountId) {
47
+ return `${process.env.AUTHORIZATION_URL}/attributes/${accountId}/resource`;
48
+ }
49
+ }
50
+ exports.AuthorizationAttributesService = AuthorizationAttributesService;
@@ -1,6 +1,15 @@
1
+ /// <reference types="bunyan" />
1
2
  import { Request } from 'express';
3
+ import { fetch, MondayFetchOptions } from '@mondaydotcomorg/monday-fetch';
4
+ import * as MondayLogger from '@mondaydotcomorg/monday-logger';
5
+ export declare const logger: MondayLogger.Logger;
2
6
  export declare class AuthorizationInternalService {
3
7
  static skipAuthorization(requset: Request): void;
4
8
  static markAuthorized(request: Request): void;
5
9
  static failIfNotCoveredByAuthorization(request: Request): void;
10
+ static throwOnHttpErrorIfNeeded(response: Awaited<ReturnType<typeof fetch>>, placement: string): void;
11
+ static generateInternalAuthToken(accountId: number, userId: number): string;
12
+ static setRequestFetchOptions(customMondayFetchOptions: MondayFetchOptions): void;
13
+ static getRequestFetchOptions(): MondayFetchOptions;
14
+ static getRequestTimeout(): 60000 | 2000;
6
15
  }
@@ -1,6 +1,46 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AuthorizationInternalService = void 0;
26
+ exports.AuthorizationInternalService = exports.logger = void 0;
27
+ const monday_jwt_1 = require("@mondaydotcomorg/monday-jwt");
28
+ const MondayLogger = __importStar(require("@mondaydotcomorg/monday-logger"));
29
+ const INTERNAL_APP_NAME = 'internal_ms';
30
+ const defaultMondayFetchOptions = {
31
+ retries: 3,
32
+ callback: logOnFetchFail,
33
+ };
34
+ function logOnFetchFail(retriesLeft, error) {
35
+ if (retriesLeft == 0) {
36
+ exports.logger.error({ retriesLeft, error }, 'Authorization attempt failed due to network issues');
37
+ }
38
+ else {
39
+ exports.logger.info({ retriesLeft, error }, 'Authorization attempt failed due to network issues, trying again');
40
+ }
41
+ }
42
+ let mondayFetchOptions = defaultMondayFetchOptions;
43
+ exports.logger = MondayLogger.getLogger();
4
44
  class AuthorizationInternalService {
5
45
  static skipAuthorization(requset) {
6
46
  requset.authorizationSkipPerformed = true;
@@ -13,5 +53,26 @@ class AuthorizationInternalService {
13
53
  throw 'Endpoint is not covered by authorization check';
14
54
  }
15
55
  }
56
+ static throwOnHttpErrorIfNeeded(response, placement) {
57
+ if (response.ok) {
58
+ return;
59
+ }
60
+ const status = response.status;
61
+ exports.logger.error({ tag: 'authorization-service', placement, status }, 'AuthorizationService: authorization request failed');
62
+ throw new Error(`AuthorizationService: [${placement}] authorization request failed with status ${status}`);
63
+ }
64
+ static generateInternalAuthToken(accountId, userId) {
65
+ return (0, monday_jwt_1.signAuthorizationHeader)({ appName: INTERNAL_APP_NAME, accountId, userId });
66
+ }
67
+ static setRequestFetchOptions(customMondayFetchOptions) {
68
+ mondayFetchOptions = Object.assign(Object.assign({}, defaultMondayFetchOptions), customMondayFetchOptions);
69
+ }
70
+ static getRequestFetchOptions() {
71
+ return mondayFetchOptions;
72
+ }
73
+ static getRequestTimeout() {
74
+ const isDevEnv = process.env.NODE_ENV === 'development';
75
+ return isDevEnv ? 60000 : 2000;
76
+ }
16
77
  }
17
78
  exports.AuthorizationInternalService = AuthorizationInternalService;
@@ -4,6 +4,7 @@ import { ScopedAction, ScopedActionPermit, ScopedActionResponseObject, ScopeOpti
4
4
  export interface AuthorizeResponse {
5
5
  isAuthorized: boolean;
6
6
  unauthorizedIds?: number[];
7
+ unauthorizedObjects?: AuthorizationObject[];
7
8
  }
8
9
  export declare function setRequestFetchOptions(customMondayFetchOptions: MondayFetchOptions): void;
9
10
  export declare function setRedisClient(client: any, grantedFeatureRedisExpirationInSeconds?: number): void;
@@ -1,27 +1,4 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
2
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
3
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
4
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -35,20 +12,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
35
12
  exports.AuthorizationService = exports.setRedisClient = exports.setRequestFetchOptions = void 0;
36
13
  const lodash_1 = require("lodash");
37
14
  const perf_hooks_1 = require("perf_hooks");
38
- const monday_jwt_1 = require("@mondaydotcomorg/monday-jwt");
39
- const MondayLogger = __importStar(require("@mondaydotcomorg/monday-logger"));
40
15
  const monday_fetch_1 = require("@mondaydotcomorg/monday-fetch");
41
16
  const prometheus_service_1 = require("./prometheus-service");
42
- const INTERNAL_APP_NAME = 'internal_ms';
43
- const logger = MondayLogger.getLogger();
17
+ const authorization_internal_service_1 = require("lib/authorization-internal-service");
44
18
  const GRANTED_FEATURE_CACHE_EXPIRATION_SECONDS = 5 * 60;
45
- const defaultMondayFetchOptions = {
46
- retries: 3,
47
- callback: logOnFetchFail,
48
- };
49
- let mondayFetchOptions = defaultMondayFetchOptions;
50
19
  function setRequestFetchOptions(customMondayFetchOptions) {
51
- mondayFetchOptions = Object.assign(Object.assign({}, defaultMondayFetchOptions), customMondayFetchOptions);
20
+ authorization_internal_service_1.AuthorizationInternalService.setRequestFetchOptions(customMondayFetchOptions);
52
21
  }
53
22
  exports.setRequestFetchOptions = setRequestFetchOptions;
54
23
  function setRedisClient(client, grantedFeatureRedisExpirationInSeconds = GRANTED_FEATURE_CACHE_EXPIRATION_SECONDS) {
@@ -57,7 +26,7 @@ function setRedisClient(client, grantedFeatureRedisExpirationInSeconds = GRANTED
57
26
  AuthorizationService.grantedFeatureRedisExpirationInSeconds = grantedFeatureRedisExpirationInSeconds;
58
27
  }
59
28
  else {
60
- logger.warn({ grantedFeatureRedisExpirationInSeconds }, 'Invalid input for grantedFeatureRedisExpirationInSeconds, must be positive number. using default ttl.');
29
+ authorization_internal_service_1.logger.warn({ grantedFeatureRedisExpirationInSeconds }, 'Invalid input for grantedFeatureRedisExpirationInSeconds, must be positive number. using default ttl.');
61
30
  AuthorizationService.grantedFeatureRedisExpirationInSeconds = GRANTED_FEATURE_CACHE_EXPIRATION_SECONDS;
62
31
  }
63
32
  }
@@ -117,20 +86,20 @@ class AuthorizationService {
117
86
  }
118
87
  static canActionInScopeMultiple(accountId, userId, scopedActions) {
119
88
  return __awaiter(this, void 0, void 0, function* () {
120
- const internalAuthToken = (0, monday_jwt_1.signAuthorizationHeader)({ appName: INTERNAL_APP_NAME, accountId, userId });
89
+ const internalAuthToken = authorization_internal_service_1.AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
121
90
  const scopedActionsPayload = scopedActions.map(scopedAction => {
122
91
  return Object.assign(Object.assign({}, scopedAction), { scope: (0, lodash_1.mapKeys)(scopedAction.scope, (_, key) => (0, lodash_1.snakeCase)(key)) }); // for example: { workspaceId: 1 } => { workspace_id: 1 }
123
92
  });
124
93
  const response = yield (0, monday_fetch_1.fetch)(getCanActionsInScopesUrl(), {
125
94
  method: 'POST',
126
95
  headers: { Authorization: internalAuthToken, 'Content-Type': 'application/json' },
127
- timeout: getRequestTimeout(),
96
+ timeout: authorization_internal_service_1.AuthorizationInternalService.getRequestTimeout(),
128
97
  body: JSON.stringify({
129
98
  user_id: userId,
130
99
  scoped_actions: scopedActionsPayload,
131
100
  }),
132
- }, mondayFetchOptions);
133
- throwOnHttpErrorIfNeeded(response, 'canActionInScopeMultiple');
101
+ }, authorization_internal_service_1.AuthorizationInternalService.getRequestFetchOptions());
102
+ authorization_internal_service_1.AuthorizationInternalService.throwOnHttpErrorIfNeeded(response, 'canActionInScopeMultiple');
134
103
  const responseBody = yield response.json();
135
104
  const camelCaseKeys = (obj) => Object.fromEntries(Object.entries(obj).map(([key, value]) => [(0, lodash_1.camelCase)(key), value]));
136
105
  const scopedActionsResponseObjects = responseBody.result.map(responseObject => {
@@ -150,22 +119,22 @@ class AuthorizationService {
150
119
  }
151
120
  static isAuthorizedMultiple(accountId, userId, authorizationRequestObjects) {
152
121
  return __awaiter(this, void 0, void 0, function* () {
153
- const internalAuthToken = (0, monday_jwt_1.signAuthorizationHeader)({ appName: INTERNAL_APP_NAME, accountId, userId });
122
+ const internalAuthToken = authorization_internal_service_1.AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
154
123
  const startTime = perf_hooks_1.performance.now();
155
124
  const response = yield (0, monday_fetch_1.fetch)(getAuthorizeUrl(), {
156
125
  method: 'POST',
157
126
  headers: { Authorization: internalAuthToken, 'Content-Type': 'application/json' },
158
- timeout: getRequestTimeout(),
127
+ timeout: authorization_internal_service_1.AuthorizationInternalService.getRequestTimeout(),
159
128
  body: JSON.stringify({
160
129
  user_id: userId,
161
130
  authorize_request_objects: authorizationRequestObjects,
162
131
  }),
163
- }, mondayFetchOptions);
132
+ }, authorization_internal_service_1.AuthorizationInternalService.getRequestFetchOptions());
164
133
  const endTime = perf_hooks_1.performance.now();
165
134
  const time = endTime - startTime;
166
135
  const responseStatus = response.status;
167
136
  (0, prometheus_service_1.sendAuthorizationChecksPerRequestMetric)(responseStatus, authorizationRequestObjects.length);
168
- throwOnHttpErrorIfNeeded(response, 'isAuthorizedMultiple');
137
+ authorization_internal_service_1.AuthorizationInternalService.throwOnHttpErrorIfNeeded(response, 'isAuthorizedMultiple');
169
138
  const responseBody = yield response.json();
170
139
  const unauthorizedObjects = [];
171
140
  responseBody.result.forEach(function (isAuthorized, index) {
@@ -176,13 +145,13 @@ class AuthorizationService {
176
145
  (0, prometheus_service_1.sendAuthorizationCheckResponseTimeMetric)(authorizationObject.resource_type, authorizationObject.action, isAuthorized, responseStatus, time);
177
146
  });
178
147
  if (unauthorizedObjects.length > 0) {
179
- logger.info({
148
+ authorization_internal_service_1.logger.info({
180
149
  resources: JSON.stringify(unauthorizedObjects),
181
150
  }, 'AuthorizationService: resource is unauthorized');
182
151
  const unauthorizedIds = unauthorizedObjects
183
152
  .filter(obj => !!obj.resource_id)
184
153
  .map(obj => obj.resource_id);
185
- return { isAuthorized: false, unauthorizedIds };
154
+ return { isAuthorized: false, unauthorizedIds, unauthorizedObjects };
186
155
  }
187
156
  return { isAuthorized: true };
188
157
  });
@@ -205,29 +174,9 @@ function createAuthorizationParams(resources, action) {
205
174
  };
206
175
  return params;
207
176
  }
208
- function logOnFetchFail(retriesLeft, error) {
209
- if (retriesLeft == 0) {
210
- logger.error({ retriesLeft, error }, 'Authorization attempt failed due to network issues');
211
- }
212
- else {
213
- logger.info({ retriesLeft, error }, 'Authorization attempt failed due to network issues, trying again');
214
- }
215
- }
216
177
  function getAuthorizeUrl() {
217
178
  return `${process.env.MONDAY_INTERNAL_URL}/internal_ms/authorization/authorize`;
218
179
  }
219
180
  function getCanActionsInScopesUrl() {
220
181
  return `${process.env.MONDAY_INTERNAL_URL}/internal_ms/authorization/can_actions_in_scopes`;
221
182
  }
222
- function getRequestTimeout() {
223
- const isDevEnv = process.env.NODE_ENV === 'development';
224
- return isDevEnv ? 60000 : 2000;
225
- }
226
- function throwOnHttpErrorIfNeeded(response, placement) {
227
- if (response.ok) {
228
- return;
229
- }
230
- const status = response.status;
231
- logger.error({ tag: 'authorization-service', placement, status }, 'AuthorizationService: authorization request failed');
232
- throw new Error(`AuthorizationService: [${placement}] authorization request failed with status ${status}`);
233
- }
@@ -0,0 +1,7 @@
1
+ import { Resource } from 'lib/types/general';
2
+ export interface ResourceAttributeAssignment {
3
+ resourceType: Resource['type'];
4
+ resourceId: Resource['id'];
5
+ key: string;
6
+ value: string;
7
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mondaydotcomorg/monday-authorization",
3
- "version": "1.1.9-featureorcomonday-jwt-ts.472+0053951b7",
3
+ "version": "1.1.9-featureyardenresource-attributes-api-support-authz-sdk.1565+f9c972a7f",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "BSD-3-Clause",
@@ -10,9 +10,10 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "@mondaydotcomorg/monday-fetch": "^0.0.7",
13
- "@mondaydotcomorg/monday-jwt": "^3.0.9-featureorcomonday-jwt-ts.472+0053951b7",
13
+ "@mondaydotcomorg/monday-jwt": "^3.0.10",
14
14
  "@mondaydotcomorg/monday-logger": "^3.0.10",
15
15
  "node-fetch": "^2.6.7",
16
+ "on-headers": "^1.0.2",
16
17
  "ts-node": "^10.0.0"
17
18
  },
18
19
  "devDependencies": {
@@ -24,7 +25,6 @@
24
25
  "ioredis": "^5.2.4",
25
26
  "ioredis-mock": "^8.2.2",
26
27
  "mocha": "^9.0.1",
27
- "on-headers": "^1.0.2",
28
28
  "supertest": "^6.1.3",
29
29
  "tsconfig-paths": "^3.9.0",
30
30
  "typescript": "^5.1.6"
@@ -32,5 +32,5 @@
32
32
  "files": [
33
33
  "dist/"
34
34
  ],
35
- "gitHead": "0053951b70f13ef040d8646d709dd3cdcce11168"
35
+ "gitHead": "f9c972a7f2c5b339d0c7a012bc8e4d2568d44549"
36
36
  }