@mondaydotcomorg/monday-authorization 3.3.0-feature-bashanye-navigate-can-action-in-scope-to-graph-63c65ad → 3.3.1
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/README.md +36 -10
- package/dist/attributions-service.d.ts +3 -2
- package/dist/attributions-service.d.ts.map +1 -1
- package/dist/attributions-service.js +1 -0
- package/dist/authorization-internal-service.d.ts +1 -1
- package/dist/authorization-internal-service.d.ts.map +1 -1
- package/dist/authorization-service.d.ts +5 -0
- package/dist/authorization-service.d.ts.map +1 -1
- package/dist/authorization-service.js +30 -26
- package/dist/clients/graph-api.d.ts +28 -0
- package/dist/clients/graph-api.d.ts.map +1 -0
- package/dist/clients/{graph-api.client.js → graph-api.js} +48 -40
- package/dist/clients/platform-api.d.ts +26 -0
- package/dist/clients/platform-api.d.ts.map +1 -0
- package/dist/clients/{platform-api.client.js → platform-api.js} +20 -20
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +2 -0
- package/dist/esm/attributions-service.d.ts +3 -2
- package/dist/esm/attributions-service.d.ts.map +1 -1
- package/dist/esm/attributions-service.mjs +1 -0
- package/dist/esm/authorization-internal-service.d.ts +1 -1
- package/dist/esm/authorization-internal-service.d.ts.map +1 -1
- package/dist/esm/authorization-service.d.ts +5 -0
- package/dist/esm/authorization-service.d.ts.map +1 -1
- package/dist/esm/authorization-service.mjs +31 -27
- package/dist/esm/clients/graph-api.d.ts +28 -0
- package/dist/esm/clients/graph-api.d.ts.map +1 -0
- package/dist/esm/clients/{graph-api.client.mjs → graph-api.mjs} +48 -40
- package/dist/esm/clients/platform-api.d.ts +26 -0
- package/dist/esm/clients/platform-api.d.ts.map +1 -0
- package/dist/esm/clients/{platform-api.client.mjs → platform-api.mjs} +21 -21
- package/dist/esm/constants.d.ts +1 -0
- package/dist/esm/constants.d.ts.map +1 -1
- package/dist/esm/constants.mjs +2 -1
- package/dist/esm/index.d.ts +6 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.mjs +8 -0
- package/dist/esm/metrics-service.d.ts +12 -0
- package/dist/esm/metrics-service.d.ts.map +1 -0
- package/dist/esm/metrics-service.mjs +54 -0
- package/dist/esm/prometheus-service.d.ts +1 -3
- package/dist/esm/prometheus-service.d.ts.map +1 -1
- package/dist/esm/prometheus-service.mjs +5 -58
- package/dist/esm/types/graph-api.types.d.ts +8 -7
- package/dist/esm/types/graph-api.types.d.ts.map +1 -1
- package/dist/esm/types/scoped-actions-contracts.d.ts +10 -1
- package/dist/esm/types/scoped-actions-contracts.d.ts.map +1 -1
- package/dist/esm/types/scoped-actions-contracts.mjs +9 -0
- package/dist/esm/utils/api-error-handler.d.ts +2 -0
- package/dist/esm/utils/api-error-handler.d.ts.map +1 -0
- package/dist/esm/utils/api-error-handler.mjs +18 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/metrics-service.d.ts +12 -0
- package/dist/metrics-service.d.ts.map +1 -0
- package/dist/metrics-service.js +58 -0
- package/dist/prometheus-service.d.ts +1 -3
- package/dist/prometheus-service.d.ts.map +1 -1
- package/dist/prometheus-service.js +4 -59
- package/dist/types/graph-api.types.d.ts +8 -7
- package/dist/types/graph-api.types.d.ts.map +1 -1
- package/dist/types/scoped-actions-contracts.d.ts +10 -1
- package/dist/types/scoped-actions-contracts.d.ts.map +1 -1
- package/dist/types/scoped-actions-contracts.js +9 -0
- package/dist/utils/api-error-handler.d.ts +2 -0
- package/dist/utils/api-error-handler.d.ts.map +1 -0
- package/dist/utils/api-error-handler.js +20 -0
- package/package.json +5 -2
- package/src/attributions-service.ts +93 -0
- package/src/authorization-attributes-service.ts +234 -0
- package/src/authorization-internal-service.ts +129 -0
- package/src/authorization-middleware.ts +51 -0
- package/src/authorization-service.ts +356 -0
- package/src/clients/graph-api.ts +170 -0
- package/src/clients/platform-api.ts +117 -0
- package/src/constants/sns.ts +5 -0
- package/src/constants.ts +23 -0
- package/src/index.ts +62 -0
- package/src/metrics-service.ts +67 -0
- package/src/prometheus-service.ts +51 -0
- package/src/roles-service.ts +125 -0
- package/src/testKit/index.ts +69 -0
- package/src/types/authorization-attributes-contracts.ts +33 -0
- package/src/types/express.ts +8 -0
- package/src/types/general.ts +32 -0
- package/src/types/graph-api.types.ts +25 -0
- package/src/types/roles.ts +42 -0
- package/src/types/scoped-actions-contracts.ts +57 -0
- package/src/utils/api-error-handler.ts +21 -0
- package/src/utils/authorization.utils.ts +47 -0
- package/dist/clients/graph-api.client.d.ts +0 -24
- package/dist/clients/graph-api.client.d.ts.map +0 -1
- package/dist/clients/platform-api.client.d.ts +0 -31
- package/dist/clients/platform-api.client.d.ts.map +0 -1
- package/dist/esm/clients/graph-api.client.d.ts +0 -24
- package/dist/esm/clients/graph-api.client.d.ts.map +0 -1
- package/dist/esm/clients/platform-api.client.d.ts +0 -31
- package/dist/esm/clients/platform-api.client.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -27,6 +27,9 @@ import * as MondayAuthorization from '@mondaydotcomorg/monday-authorization';
|
|
|
27
27
|
|
|
28
28
|
MondayAuthorization.init({
|
|
29
29
|
prometheus: getPrometheus(),
|
|
30
|
+
metrics: {
|
|
31
|
+
serviceName: process.env.APP_NAME,
|
|
32
|
+
},
|
|
30
33
|
redisClient: redisClient,
|
|
31
34
|
grantedFeatureRedisExpirationInSeconds: 10 * 60
|
|
32
35
|
});
|
|
@@ -36,6 +39,16 @@ startServer(...)
|
|
|
36
39
|
**Recommended** - optionally init authorization with redisClient so the granted feature results will be cached and reduce http calls.
|
|
37
40
|
|
|
38
41
|
- grantedFeatureRedisExpirationInSeconds - (optional), redis TTL for cached granted features, default set to 5 minutes
|
|
42
|
+
- metrics - (optional), configure internal DataDog/observability integration. Defaults to `process.env.APP_NAME` as the service name, uses the standard StatsD endpoint (`localhost:8125`) when host/port are not provided, and disables emission automatically in test/development environments (override with `disabled`).
|
|
43
|
+
|
|
44
|
+
### Metrics & Observability
|
|
45
|
+
|
|
46
|
+
- `prometheus` (optional) enables the legacy Prometheus summary `authorization_check_response_time` with labels `resourceType`, `action`, `isAuthorized`, and `responseStatus`.
|
|
47
|
+
- `metrics` (optional) enables StatsD emission through `@mondaydotcomorg/monday-observability-kit` with:
|
|
48
|
+
- `authorization.authorizationCheck.platform.duration` / `.graph.duration` (distributions per API path)
|
|
49
|
+
- `authorization.authorizationCheck.platform.error` / `.graph.error` counters (with `statusCode` tag)
|
|
50
|
+
- When `metrics.disabled` is omitted, the SDK automatically disables StatsD in `test`/`development` environments.
|
|
51
|
+
- StatsD requires `DOGSTATSD_HOST` / `DOGSTATSD_PORT` (or the defaults `localhost:8125`). Errors are logged and skipped if the client is unavailable.
|
|
39
52
|
|
|
40
53
|
## Usage
|
|
41
54
|
|
|
@@ -137,17 +150,13 @@ const canActionInScopeMultipleResponse: ScopedActionResponseObject[] =
|
|
|
137
150
|
* /
|
|
138
151
|
```
|
|
139
152
|
|
|
140
|
-
**Graph API Routing (v3.3.0+)
|
|
141
|
-
|
|
142
|
-
Starting from version 3.3.0, `canActionInScope` and `canActionInScopeMultiple` can route authorization checks to the Graph API (`authorization-graph` service) instead of the Platform API. This routing is controlled by the Ignite feature flag `navigate-can-action-in-scope-to-graph`.
|
|
153
|
+
**Graph API Routing (v3.3.0+)**
|
|
143
154
|
|
|
144
|
-
- **Feature Flag**: `navigate-can-action-in-scope-to-graph`
|
|
145
|
-
- **
|
|
146
|
-
- **
|
|
147
|
-
- **
|
|
148
|
-
- **
|
|
149
|
-
|
|
150
|
-
The Graph API provides the same authorization results with improved performance and scalability. The feature flag allows for gradual rollout and easy rollback if needed.
|
|
155
|
+
- **Feature Flag**: `navigate-can-action-in-scope-to-graph` must be enabled in Ignite for the specific account/user.
|
|
156
|
+
- **Environment Variable**: `APP_NAME` must be defined (Graph API uses it to sign JWTs). Missing `APP_NAME` throws `GraphApi: APP_NAME environment variable is required for Graph API authentication`.
|
|
157
|
+
- **Routing Logic**: when the flag is released, `canActionInScope` / `canActionInScopeMultiple` call `authorization-graph` (`/permissions/is-allowed`). Otherwise they continue to call Platform API.
|
|
158
|
+
- **Fallback**: If Graph responses are missing permissions, the SDK defaults to `can=false` with `reason.key = 'unknown'`. HTTP errors propagate and are counted in the StatsD error metric.
|
|
159
|
+
- **Migration**: upgrade to v3.3.0+, set `APP_NAME`, and roll out the feature flag gradually—no code changes required for consumers.
|
|
151
160
|
|
|
152
161
|
### Authorization Attributes API
|
|
153
162
|
|
|
@@ -256,6 +265,7 @@ const rolesResponse = await rolesService.getRoles(accountId, resourceTypes, styl
|
|
|
256
265
|
```
|
|
257
266
|
|
|
258
267
|
**Parameters:**
|
|
268
|
+
|
|
259
269
|
- `accountId` - The account ID
|
|
260
270
|
- `resourceTypes` - Array of resource types to filter roles by (e.g., ['account', 'workspace'])
|
|
261
271
|
- `style` - Deprecated, don't use it. the style of the roles to return, either 'A' or 'B' (default is 'A'). Note that basic role IDs are returned in A style and not B style.
|
|
@@ -285,6 +295,7 @@ const rolesResponse = await rolesService.createCustomRole(accountId, customRoles
|
|
|
285
295
|
```
|
|
286
296
|
|
|
287
297
|
**Parameters:**
|
|
298
|
+
|
|
288
299
|
- `accountId` - The account ID
|
|
289
300
|
- `roles` - Array of `RoleCreateRequest` objects (cannot be empty)
|
|
290
301
|
|
|
@@ -310,6 +321,7 @@ const rolesResponse = await rolesService.updateCustomRole(accountId, updateReque
|
|
|
310
321
|
```
|
|
311
322
|
|
|
312
323
|
**Parameters:**
|
|
324
|
+
|
|
313
325
|
- `accountId` - The account ID
|
|
314
326
|
- `updateRequests` - Array of `RoleUpdateRequest` objects
|
|
315
327
|
|
|
@@ -328,6 +340,7 @@ const rolesResponse = await rolesService.deleteCustomRole(accountId, roleIds);
|
|
|
328
340
|
```
|
|
329
341
|
|
|
330
342
|
**Parameters:**
|
|
343
|
+
|
|
331
344
|
- `accountId` - The account ID
|
|
332
345
|
- `roleIds` - Array of custom role IDs to delete
|
|
333
346
|
|
|
@@ -388,3 +401,16 @@ interface RolesResponse {
|
|
|
388
401
|
basicRoles?: BasicRole[];
|
|
389
402
|
}
|
|
390
403
|
```
|
|
404
|
+
|
|
405
|
+
## Development
|
|
406
|
+
|
|
407
|
+
### Local Development and Testing
|
|
408
|
+
|
|
409
|
+
This package includes an `ignite-local-overrides.json` file for local development and testing only. It does **not** affect consumers of this package - they use their own Ignite configuration.
|
|
410
|
+
|
|
411
|
+
The file enables feature flags for testing:
|
|
412
|
+
|
|
413
|
+
- `sdk-platform-profiles`: Platform profile routing
|
|
414
|
+
- `navigate-can-action-in-scope-to-graph`: Graph API routing for `canActionInScope` methods
|
|
415
|
+
|
|
416
|
+
Modify this file for different local test scenarios, but remember changes only affect this package's development/testing.
|
|
@@ -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;
|
|
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');
|
|
@@ -10,7 +10,7 @@ export declare class AuthorizationInternalService {
|
|
|
10
10
|
static markAuthorized(request: BaseRequest): void;
|
|
11
11
|
static failIfNotCoveredByAuthorization(request: BaseRequest): void;
|
|
12
12
|
static throwOnHttpErrorIfNeeded(response: Awaited<ReturnType<typeof fetch>>, placement: string): void;
|
|
13
|
-
static throwOnHttpError(status: number, placement: string):
|
|
13
|
+
static throwOnHttpError(status: number, placement: string): never;
|
|
14
14
|
static generateInternalAuthToken(accountId: number, userId: number): string;
|
|
15
15
|
static setRequestFetchOptions(customMondayFetchOptions: MondayFetchOptions): void;
|
|
16
16
|
static getRequestFetchOptions(): MondayFetchOptions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authorization-internal-service.d.ts","sourceRoot":"","sources":["../src/authorization-internal-service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAE1E,OAAO,EAAyB,eAAe,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AACxG,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAK9C,eAAO,MAAM,MAAM,kBAA2B,CAAC;AAO/C,eAAO,MAAM,eAAe,EAAE,eAM7B,CAAC;AAYF,qBAAa,4BAA4B;IACvC,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IACnC,MAAM,CAAC,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAIpD,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAIjD,MAAM,CAAC,+BAA+B,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAMlE,MAAM,CAAC,wBAAwB,CAAC,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAcrG,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;
|
|
1
|
+
{"version":3,"file":"authorization-internal-service.d.ts","sourceRoot":"","sources":["../src/authorization-internal-service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAE1E,OAAO,EAAyB,eAAe,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AACxG,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAK9C,eAAO,MAAM,MAAM,kBAA2B,CAAC;AAO/C,eAAO,MAAM,eAAe,EAAE,eAM7B,CAAC;AAYF,qBAAa,4BAA4B;IACvC,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IACnC,MAAM,CAAC,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAIpD,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAIjD,MAAM,CAAC,+BAA+B,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAMlE,MAAM,CAAC,wBAAwB,CAAC,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAcrG,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,KAAK;IAQjE,MAAM,CAAC,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAIlE,MAAM,CAAC,sBAAsB,CAAC,wBAAwB,EAAE,kBAAkB;IAO1E,MAAM,CAAC,sBAAsB,IAAI,kBAAkB;IAInD,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,YAAY;IAI3C,MAAM,CAAC,iBAAiB;IA2BxB,MAAM,CAAC,gBAAgB,IAAI,WAAW;CASvC"}
|
|
@@ -9,6 +9,11 @@ export interface AuthorizeResponse {
|
|
|
9
9
|
}
|
|
10
10
|
export declare function setRequestFetchOptions(customMondayFetchOptions: MondayFetchOptions): void;
|
|
11
11
|
export declare class AuthorizationService {
|
|
12
|
+
private static get graphApi();
|
|
13
|
+
private static _graphApi?;
|
|
14
|
+
private static get platformApi();
|
|
15
|
+
private static _platformApi?;
|
|
16
|
+
static resetApiClients(): void;
|
|
12
17
|
static redisClient?: any;
|
|
13
18
|
static grantedFeatureRedisExpirationInSeconds?: number;
|
|
14
19
|
static igniteClient?: IgniteClient;
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AAG7F,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,OAAO,CAAC,MAAM,KAAK,QAAQ,GAK1B;IACD,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAW;IAEpC,OAAO,CAAC,MAAM,KAAK,WAAW,GAK7B;IACD,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAc;IAE1C,MAAM,CAAC,eAAe,IAAI,IAAI;IAK9B,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;mBA4CnB,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"}
|
|
@@ -5,10 +5,11 @@ const tridentBackendApi = require('@mondaydotcomorg/trident-backend-api');
|
|
|
5
5
|
const mondayFetchApi = require('@mondaydotcomorg/monday-fetch-api');
|
|
6
6
|
const igniteSdk = require('@mondaydotcomorg/ignite-sdk');
|
|
7
7
|
const prometheusService = require('./prometheus-service.js');
|
|
8
|
+
const metricsService = require('./metrics-service.js');
|
|
8
9
|
const authorizationInternalService = require('./authorization-internal-service.js');
|
|
9
10
|
const attributionsService = require('./attributions-service.js');
|
|
10
|
-
const
|
|
11
|
-
const
|
|
11
|
+
const clients_graphApi = require('./clients/graph-api.js');
|
|
12
|
+
const clients_platformApi = require('./clients/platform-api.js');
|
|
12
13
|
const utils_authorization_utils = require('./utils/authorization.utils.js');
|
|
13
14
|
|
|
14
15
|
const GRANTED_FEATURE_CACHE_EXPIRATION_SECONDS = 5 * 60;
|
|
@@ -21,6 +22,24 @@ function setRequestFetchOptions(customMondayFetchOptions) {
|
|
|
21
22
|
authorizationInternalService.AuthorizationInternalService.setRequestFetchOptions(customMondayFetchOptions);
|
|
22
23
|
}
|
|
23
24
|
class AuthorizationService {
|
|
25
|
+
static get graphApi() {
|
|
26
|
+
if (!this._graphApi) {
|
|
27
|
+
this._graphApi = new clients_graphApi.GraphApi();
|
|
28
|
+
}
|
|
29
|
+
return this._graphApi;
|
|
30
|
+
}
|
|
31
|
+
static _graphApi;
|
|
32
|
+
static get platformApi() {
|
|
33
|
+
if (!this._platformApi) {
|
|
34
|
+
this._platformApi = new clients_platformApi.PlatformApi();
|
|
35
|
+
}
|
|
36
|
+
return this._platformApi;
|
|
37
|
+
}
|
|
38
|
+
static _platformApi;
|
|
39
|
+
static resetApiClients() {
|
|
40
|
+
this._graphApi = undefined;
|
|
41
|
+
this._platformApi = undefined;
|
|
42
|
+
}
|
|
24
43
|
static redisClient;
|
|
25
44
|
static grantedFeatureRedisExpirationInSeconds;
|
|
26
45
|
static igniteClient;
|
|
@@ -86,38 +105,25 @@ class AuthorizationService {
|
|
|
86
105
|
this.igniteClient.isReleased(PLATFORM_PROFILE_RELEASE_FF, { accountId, userId })) {
|
|
87
106
|
return attributionsService.getProfile();
|
|
88
107
|
}
|
|
89
|
-
return attributionsService.PlatformProfile.
|
|
108
|
+
return attributionsService.PlatformProfile.APP;
|
|
90
109
|
}
|
|
91
110
|
static async canActionInScopeMultiple(accountId, userId, scopedActions) {
|
|
92
111
|
if (scopedActions.length === 0) {
|
|
93
112
|
return [];
|
|
94
113
|
}
|
|
95
114
|
const shouldNavigateToGraph = Boolean(this.igniteClient?.isReleased(NAVIGATE_CAN_ACTION_IN_SCOPE_TO_GRAPH_FF, { accountId, userId }));
|
|
96
|
-
const internalAuthToken = authorizationInternalService.AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
|
|
97
115
|
const startTime = perf_hooks.performance.now();
|
|
98
116
|
let scopedActionResponseObjects;
|
|
99
117
|
let apiType;
|
|
100
118
|
if (shouldNavigateToGraph) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
apiType = 'graph';
|
|
104
|
-
}
|
|
105
|
-
catch (error) {
|
|
106
|
-
const status = error instanceof mondayFetchApi.HttpFetcherError ? error.status : undefined;
|
|
107
|
-
authorizationInternalService.logger.warn({
|
|
108
|
-
tag: 'authorization-service',
|
|
109
|
-
error: error instanceof Error ? error.message : String(error),
|
|
110
|
-
accountId,
|
|
111
|
-
userId,
|
|
112
|
-
status,
|
|
113
|
-
}, 'Graph API authorization failed');
|
|
114
|
-
throw error;
|
|
115
|
-
}
|
|
119
|
+
apiType = 'graph';
|
|
120
|
+
scopedActionResponseObjects = await this.graphApi.checkPermissions(accountId, userId, scopedActions);
|
|
116
121
|
}
|
|
117
122
|
else {
|
|
118
|
-
const profile = this.getProfile(accountId, userId);
|
|
119
|
-
scopedActionResponseObjects = await clients_platformApi_client.PlatformApiClient.checkPermissions(profile, internalAuthToken, userId, scopedActions);
|
|
120
123
|
apiType = 'platform';
|
|
124
|
+
const profile = this.getProfile(accountId, userId);
|
|
125
|
+
const internalAuthToken = authorizationInternalService.AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
|
|
126
|
+
scopedActionResponseObjects = await this.platformApi.checkPermissions(profile, internalAuthToken, userId, scopedActions);
|
|
121
127
|
}
|
|
122
128
|
const endTime = perf_hooks.performance.now();
|
|
123
129
|
const time = endTime - startTime;
|
|
@@ -126,10 +132,8 @@ class AuthorizationService {
|
|
|
126
132
|
const { action, scope } = obj.scopedAction;
|
|
127
133
|
const { resourceType } = utils_authorization_utils.scopeToResource(scope);
|
|
128
134
|
const isAuthorized = obj.permit.can;
|
|
129
|
-
prometheusService.sendAuthorizationCheckResponseTimeMetric(resourceType, action, isAuthorized, 200, time
|
|
130
|
-
|
|
131
|
-
prometheusService.incrementAuthorizationSuccess(resourceType, action, apiType);
|
|
132
|
-
}
|
|
135
|
+
prometheusService.sendAuthorizationCheckResponseTimeMetric(resourceType, action, isAuthorized, 200, time);
|
|
136
|
+
metricsService.recordAuthorizationTiming(apiType, time);
|
|
133
137
|
}
|
|
134
138
|
return scopedActionResponseObjects;
|
|
135
139
|
}
|
|
@@ -186,7 +190,7 @@ class AuthorizationService {
|
|
|
186
190
|
if (!isAuthorized) {
|
|
187
191
|
unauthorizedObjects.push(authorizationObject);
|
|
188
192
|
}
|
|
189
|
-
prometheusService.sendAuthorizationCheckResponseTimeMetric(authorizationObject.resource_type, authorizationObject.action, isAuthorized, 200, time
|
|
193
|
+
prometheusService.sendAuthorizationCheckResponseTimeMetric(authorizationObject.resource_type, authorizationObject.action, isAuthorized, 200, time);
|
|
190
194
|
});
|
|
191
195
|
if (unauthorizedObjects.length > 0) {
|
|
192
196
|
authorizationInternalService.logger.info({
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ScopedAction, ScopedActionResponseObject } from '../types/scoped-actions-contracts';
|
|
2
|
+
import { GraphIsAllowedResponse } from '../types/graph-api.types';
|
|
3
|
+
/**
|
|
4
|
+
* Client for handling Graph API authorization operations
|
|
5
|
+
*/
|
|
6
|
+
export declare class GraphApi {
|
|
7
|
+
private readonly httpClient;
|
|
8
|
+
private readonly consumerAppName;
|
|
9
|
+
constructor();
|
|
10
|
+
/**
|
|
11
|
+
* Builds the request body for Graph API calls
|
|
12
|
+
*/
|
|
13
|
+
private static buildRequestBody;
|
|
14
|
+
/**
|
|
15
|
+
* Fetches authorization data from the Graph API
|
|
16
|
+
*/
|
|
17
|
+
fetchPermissions(authToken: string, scopedActions: ScopedAction[]): Promise<GraphIsAllowedResponse>;
|
|
18
|
+
/**
|
|
19
|
+
* Maps Graph API response to the expected format
|
|
20
|
+
*/
|
|
21
|
+
private static mapResponse;
|
|
22
|
+
/**
|
|
23
|
+
* Performs a complete authorization check using the Graph API
|
|
24
|
+
*/
|
|
25
|
+
checkPermissions(accountId: number, userId: number, scopedActions: ScopedAction[]): Promise<ScopedActionResponseObject[]>;
|
|
26
|
+
private static ensureGraphReason;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=graph-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-api.d.ts","sourceRoot":"","sources":["../../src/clients/graph-api.ts"],"names":[],"mappings":"AACA,OAAO,EACL,YAAY,EACZ,0BAA0B,EAG3B,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAEL,sBAAsB,EAMvB,MAAM,0BAA0B,CAAC;AASlC;;GAEG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;IACxC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;;IAezC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAyB/B;;OAEG;IACG,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAgCzG;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;IAiC1B;;OAEG;IACG,gBAAgB,CACpB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;IAMxC,OAAO,CAAC,MAAM,CAAC,iBAAiB;CAWjC"}
|
|
@@ -1,18 +1,34 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
|
|
3
3
|
const tridentBackendApi = require('@mondaydotcomorg/trident-backend-api');
|
|
4
|
-
const mondayFetchApi = require('@mondaydotcomorg/monday-fetch-api');
|
|
5
4
|
const types_scopedActionsContracts = require('../types/scoped-actions-contracts.js');
|
|
6
5
|
const authorizationInternalService = require('../authorization-internal-service.js');
|
|
7
6
|
const attributionsService = require('../attributions-service.js');
|
|
8
7
|
const utils_authorization_utils = require('../utils/authorization.utils.js');
|
|
9
|
-
const
|
|
8
|
+
const mondayJwt = require('@mondaydotcomorg/monday-jwt');
|
|
9
|
+
const constants = require('../constants.js');
|
|
10
|
+
const utils_apiErrorHandler = require('../utils/api-error-handler.js');
|
|
10
11
|
|
|
11
12
|
const CAN_ACTION_IN_SCOPE_GRAPH_PATH = '/permissions/is-allowed';
|
|
13
|
+
const APP_NAME_REQUIRED_ERROR = 'GraphApi: APP_NAME environment variable is required for Graph API authentication';
|
|
12
14
|
/**
|
|
13
15
|
* Client for handling Graph API authorization operations
|
|
14
16
|
*/
|
|
15
|
-
class
|
|
17
|
+
class GraphApi {
|
|
18
|
+
httpClient;
|
|
19
|
+
consumerAppName;
|
|
20
|
+
constructor() {
|
|
21
|
+
const httpClient = tridentBackendApi.Api.getPart('httpClient');
|
|
22
|
+
if (!httpClient) {
|
|
23
|
+
throw new Error('GraphApi: http client is not initialized');
|
|
24
|
+
}
|
|
25
|
+
const consumerAppName = process.env.APP_NAME?.trim();
|
|
26
|
+
if (!consumerAppName) {
|
|
27
|
+
throw new Error(APP_NAME_REQUIRED_ERROR);
|
|
28
|
+
}
|
|
29
|
+
this.httpClient = httpClient;
|
|
30
|
+
this.consumerAppName = consumerAppName;
|
|
31
|
+
}
|
|
16
32
|
/**
|
|
17
33
|
* Builds the request body for Graph API calls
|
|
18
34
|
*/
|
|
@@ -41,19 +57,18 @@ class GraphApiClient {
|
|
|
41
57
|
/**
|
|
42
58
|
* Fetches authorization data from the Graph API
|
|
43
59
|
*/
|
|
44
|
-
|
|
45
|
-
const httpClient = tridentBackendApi.Api.getPart('httpClient');
|
|
60
|
+
async fetchPermissions(authToken, scopedActions) {
|
|
46
61
|
const attributionHeaders = attributionsService.getAttributionsFromApi();
|
|
47
|
-
const bodyPayload =
|
|
62
|
+
const bodyPayload = GraphApi.buildRequestBody(scopedActions);
|
|
48
63
|
try {
|
|
49
|
-
const response = await httpClient.fetch({
|
|
64
|
+
const response = await this.httpClient.fetch({
|
|
50
65
|
url: {
|
|
51
|
-
appName:
|
|
66
|
+
appName: constants.GRAPH_APP_NAME,
|
|
52
67
|
path: CAN_ACTION_IN_SCOPE_GRAPH_PATH,
|
|
53
68
|
},
|
|
54
69
|
method: 'POST',
|
|
55
70
|
headers: {
|
|
56
|
-
Authorization:
|
|
71
|
+
Authorization: authToken,
|
|
57
72
|
'Content-Type': 'application/json',
|
|
58
73
|
...attributionHeaders,
|
|
59
74
|
},
|
|
@@ -65,13 +80,8 @@ class GraphApiClient {
|
|
|
65
80
|
return response;
|
|
66
81
|
}
|
|
67
82
|
catch (err) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (scopedActions.length > 0) {
|
|
71
|
-
prometheusService.incrementAuthorizationError(utils_authorization_utils.scopeToResource(scopedActions[0].scope).resourceType, scopedActions[0].action, err.status, 'graph');
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
throw err;
|
|
83
|
+
// handleApiError never returns (throws)
|
|
84
|
+
return utils_apiErrorHandler.handleApiError(err, 'graph', 'canActionInScopeMultiple');
|
|
75
85
|
}
|
|
76
86
|
}
|
|
77
87
|
/**
|
|
@@ -83,41 +93,39 @@ class GraphApiClient {
|
|
|
83
93
|
const { action, scope } = scopedAction;
|
|
84
94
|
const { resourceType, resourceId } = utils_authorization_utils.scopeToResource(scope);
|
|
85
95
|
const permissionResult = resources?.[resourceType]?.[String(resourceId)]?.[action];
|
|
86
|
-
const graphReason = permissionResult?.reason;
|
|
87
|
-
let reasonKey;
|
|
88
|
-
let additionalOptions = {};
|
|
89
|
-
let technicalReason = types_scopedActionsContracts.PermitTechnicalReason.NO_REASON;
|
|
90
|
-
if (typeof graphReason === 'string') {
|
|
91
|
-
reasonKey = graphReason;
|
|
92
|
-
}
|
|
93
|
-
else if (graphReason && typeof graphReason === 'object') {
|
|
94
|
-
reasonKey = graphReason.key ?? 'unknown';
|
|
95
|
-
additionalOptions = graphReason.additionalOptions ?? {};
|
|
96
|
-
if (graphReason.technicalReason !== undefined) {
|
|
97
|
-
technicalReason = (graphReason.technicalReason ?? types_scopedActionsContracts.PermitTechnicalReason.NO_REASON);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
else {
|
|
101
|
-
reasonKey = 'unknown';
|
|
102
|
-
}
|
|
103
96
|
const permit = {
|
|
104
97
|
can: permissionResult?.can ?? false,
|
|
105
98
|
reason: {
|
|
106
|
-
key:
|
|
107
|
-
...additionalOptions,
|
|
99
|
+
key: 'unknown',
|
|
108
100
|
},
|
|
109
|
-
technicalReason,
|
|
101
|
+
technicalReason: types_scopedActionsContracts.PermitTechnicalReason.NO_REASON,
|
|
110
102
|
};
|
|
103
|
+
if (permissionResult) {
|
|
104
|
+
const graphReason = GraphApi.ensureGraphReason(permissionResult.reason, { resourceType, resourceId, action });
|
|
105
|
+
permit.reason = {
|
|
106
|
+
key: graphReason.key,
|
|
107
|
+
...(graphReason.additionalOptions ?? {}),
|
|
108
|
+
};
|
|
109
|
+
permit.technicalReason = (graphReason.technicalReason ??
|
|
110
|
+
types_scopedActionsContracts.PermitTechnicalReason.NO_REASON);
|
|
111
|
+
}
|
|
111
112
|
return { scopedAction, permit };
|
|
112
113
|
});
|
|
113
114
|
}
|
|
114
115
|
/**
|
|
115
116
|
* Performs a complete authorization check using the Graph API
|
|
116
117
|
*/
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
|
|
118
|
+
async checkPermissions(accountId, userId, scopedActions) {
|
|
119
|
+
const authToken = mondayJwt.signAuthorizationHeader({ appName: this.consumerAppName, accountId, userId });
|
|
120
|
+
const response = await this.fetchPermissions(authToken, scopedActions);
|
|
121
|
+
return GraphApi.mapResponse(scopedActions, response);
|
|
122
|
+
}
|
|
123
|
+
static ensureGraphReason(reason, context) {
|
|
124
|
+
if (!reason || typeof reason !== 'object' || typeof reason.key !== 'string') {
|
|
125
|
+
throw new Error(`GraphApi: unexpected reason format for ${context.resourceType}/${context.resourceId}/${context.action}`);
|
|
126
|
+
}
|
|
127
|
+
return reason;
|
|
120
128
|
}
|
|
121
129
|
}
|
|
122
130
|
|
|
123
|
-
exports.
|
|
131
|
+
exports.GraphApi = GraphApi;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ScopedAction, ScopedActionResponseObject } from '../types/scoped-actions-contracts';
|
|
2
|
+
import { PlatformProfile } from '../attributions-service';
|
|
3
|
+
/**
|
|
4
|
+
* Client for handling Platform API authorization operations
|
|
5
|
+
*/
|
|
6
|
+
export declare class PlatformApi {
|
|
7
|
+
private readonly httpClient;
|
|
8
|
+
constructor();
|
|
9
|
+
/**
|
|
10
|
+
* Builds the request payload for Platform API calls
|
|
11
|
+
*/
|
|
12
|
+
private static buildRequestPayload;
|
|
13
|
+
/**
|
|
14
|
+
* Fetches authorization data from the Platform API
|
|
15
|
+
*/
|
|
16
|
+
private fetchPermissions;
|
|
17
|
+
/**
|
|
18
|
+
* Maps Platform API response to the expected format
|
|
19
|
+
*/
|
|
20
|
+
private static mapResponse;
|
|
21
|
+
/**
|
|
22
|
+
* Performs a complete authorization check using the Platform API
|
|
23
|
+
*/
|
|
24
|
+
checkPermissions(profile: PlatformProfile, internalAuthToken: string, userId: number, scopedActions: ScopedAction[]): Promise<ScopedActionResponseObject[]>;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=platform-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-api.d.ts","sourceRoot":"","sources":["../../src/clients/platform-api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;AAE7F,OAAO,EAA0B,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAelF;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;;IAUxC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAOlC;;OAEG;YACW,gBAAgB;IAqC9B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;IAkB1B;;OAEG;IACG,gBAAgB,CACpB,OAAO,EAAE,eAAe,EACxB,iBAAiB,EAAE,MAAM,EACzB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;CAKzC"}
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
|
|
3
3
|
const tridentBackendApi = require('@mondaydotcomorg/trident-backend-api');
|
|
4
|
-
const mondayFetchApi = require('@mondaydotcomorg/monday-fetch-api');
|
|
5
4
|
const authorizationInternalService = require('../authorization-internal-service.js');
|
|
6
5
|
const attributionsService = require('../attributions-service.js');
|
|
7
6
|
const utils_authorization_utils = require('../utils/authorization.utils.js');
|
|
8
|
-
const
|
|
7
|
+
const utils_apiErrorHandler = require('../utils/api-error-handler.js');
|
|
9
8
|
|
|
10
9
|
const PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH = '/internal_ms/authorization/can_actions_in_scopes';
|
|
11
10
|
/**
|
|
12
11
|
* Client for handling Platform API authorization operations
|
|
13
12
|
*/
|
|
14
|
-
class
|
|
13
|
+
class PlatformApi {
|
|
14
|
+
httpClient;
|
|
15
|
+
constructor() {
|
|
16
|
+
const httpClient = tridentBackendApi.Api.getPart('httpClient');
|
|
17
|
+
if (!httpClient) {
|
|
18
|
+
throw new Error('PlatformApi: http client is not initialized');
|
|
19
|
+
}
|
|
20
|
+
this.httpClient = httpClient;
|
|
21
|
+
}
|
|
15
22
|
/**
|
|
16
23
|
* Builds the request payload for Platform API calls
|
|
17
24
|
*/
|
|
@@ -24,11 +31,10 @@ class PlatformApiClient {
|
|
|
24
31
|
/**
|
|
25
32
|
* Fetches authorization data from the Platform API
|
|
26
33
|
*/
|
|
27
|
-
|
|
34
|
+
async fetchPermissions(profile, internalAuthToken, userId, scopedActionsPayload) {
|
|
28
35
|
const attributionHeaders = attributionsService.getAttributionsFromApi();
|
|
29
|
-
const httpClient = tridentBackendApi.Api.getPart('httpClient');
|
|
30
36
|
try {
|
|
31
|
-
const response = await httpClient.fetch({
|
|
37
|
+
const response = await this.httpClient.fetch({
|
|
32
38
|
url: {
|
|
33
39
|
appName: 'platform',
|
|
34
40
|
path: PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH,
|
|
@@ -48,14 +54,8 @@ class PlatformApiClient {
|
|
|
48
54
|
return response;
|
|
49
55
|
}
|
|
50
56
|
catch (err) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (scopedActionsPayload.length > 0) {
|
|
54
|
-
const { resourceType } = utils_authorization_utils.scopeToResource(utils_authorization_utils.toCamelCase(scopedActionsPayload[0].scope));
|
|
55
|
-
prometheusService.incrementAuthorizationError(resourceType, scopedActionsPayload[0].action, err.status, 'platform');
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
throw err;
|
|
57
|
+
// handleApiError never returns (throws)
|
|
58
|
+
return utils_apiErrorHandler.handleApiError(err, 'platform', 'canActionInScopeMultiple');
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
@@ -63,8 +63,8 @@ class PlatformApiClient {
|
|
|
63
63
|
*/
|
|
64
64
|
static mapResponse(response) {
|
|
65
65
|
if (!response) {
|
|
66
|
-
authorizationInternalService.logger.error({ tag: 'platform-api
|
|
67
|
-
throw new Error('
|
|
66
|
+
authorizationInternalService.logger.error({ tag: 'platform-api', response }, 'PlatformApi: missing response');
|
|
67
|
+
throw new Error('PlatformApi: missing response');
|
|
68
68
|
}
|
|
69
69
|
return response.result.map(responseObject => {
|
|
70
70
|
const { scopedAction, permit } = responseObject;
|
|
@@ -79,11 +79,11 @@ class PlatformApiClient {
|
|
|
79
79
|
/**
|
|
80
80
|
* Performs a complete authorization check using the Platform API
|
|
81
81
|
*/
|
|
82
|
-
|
|
83
|
-
const scopedActionsPayload =
|
|
82
|
+
async checkPermissions(profile, internalAuthToken, userId, scopedActions) {
|
|
83
|
+
const scopedActionsPayload = PlatformApi.buildRequestPayload(scopedActions);
|
|
84
84
|
const platformResponse = await this.fetchPermissions(profile, internalAuthToken, userId, scopedActionsPayload);
|
|
85
|
-
return
|
|
85
|
+
return PlatformApi.mapResponse(platformResponse);
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
exports.
|
|
89
|
+
exports.PlatformApi = PlatformApi;
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { RecursivePartial } from '@mondaydotcomorg/monday-fetch-api';
|
|
2
2
|
import { FetcherConfig } from '@mondaydotcomorg/trident-backend-api';
|
|
3
3
|
export declare const APP_NAME = "authorization";
|
|
4
|
+
export declare const GRAPH_APP_NAME = "authorization-graph";
|
|
4
5
|
export declare const ERROR_MESSAGES: {
|
|
5
6
|
readonly HTTP_CLIENT_NOT_INITIALIZED: "MondayAuthorization: HTTP client is not initialized";
|
|
6
7
|
readonly REQUEST_FAILED: (method: string, status: number, reason: string) => string;
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAErE,eAAO,MAAM,QAAQ,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAErE,eAAO,MAAM,QAAQ,kBAAkB,CAAC;AACxC,eAAO,MAAM,cAAc,wBAAwB,CAAC;AAEpD,eAAO,MAAM,cAAc;;sCAEA,MAAM,UAAU,MAAM,UAAU,MAAM;CAEvD,CAAC;AAEX,eAAO,MAAM,qBAAqB,EAAE,gBAAgB,CAAC,aAAa,CAUjE,CAAC"}
|
package/dist/constants.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
|
|
3
3
|
const APP_NAME = 'authorization';
|
|
4
|
+
const GRAPH_APP_NAME = 'authorization-graph';
|
|
4
5
|
const ERROR_MESSAGES = {
|
|
5
6
|
HTTP_CLIENT_NOT_INITIALIZED: 'MondayAuthorization: HTTP client is not initialized',
|
|
6
7
|
REQUEST_FAILED: (method, status, reason) => `MondayAuthorization: [${method}] request failed with status ${status} with reason: ${reason}`,
|
|
@@ -20,3 +21,4 @@ const DEFAULT_FETCH_OPTIONS = {
|
|
|
20
21
|
exports.APP_NAME = APP_NAME;
|
|
21
22
|
exports.DEFAULT_FETCH_OPTIONS = DEFAULT_FETCH_OPTIONS;
|
|
22
23
|
exports.ERROR_MESSAGES = ERROR_MESSAGES;
|
|
24
|
+
exports.GRAPH_APP_NAME = GRAPH_APP_NAME;
|
|
@@ -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;
|
|
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');
|
|
@@ -10,7 +10,7 @@ export declare class AuthorizationInternalService {
|
|
|
10
10
|
static markAuthorized(request: BaseRequest): void;
|
|
11
11
|
static failIfNotCoveredByAuthorization(request: BaseRequest): void;
|
|
12
12
|
static throwOnHttpErrorIfNeeded(response: Awaited<ReturnType<typeof fetch>>, placement: string): void;
|
|
13
|
-
static throwOnHttpError(status: number, placement: string):
|
|
13
|
+
static throwOnHttpError(status: number, placement: string): never;
|
|
14
14
|
static generateInternalAuthToken(accountId: number, userId: number): string;
|
|
15
15
|
static setRequestFetchOptions(customMondayFetchOptions: MondayFetchOptions): void;
|
|
16
16
|
static getRequestFetchOptions(): MondayFetchOptions;
|