opal-security 3.2.1 → 3.2.2

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 (56) hide show
  1. package/README.md +28 -25
  2. package/lib/commands/login.js +8 -1
  3. package/lib/commands/request/create.d.ts +2 -0
  4. package/lib/commands/request/create.js +41 -20
  5. package/lib/commands/request/get.js +5 -57
  6. package/lib/commands/request/list.js +3 -60
  7. package/lib/graphql/gql.d.ts +35 -15
  8. package/lib/graphql/gql.js +9 -5
  9. package/lib/graphql/graphql.d.ts +286 -228
  10. package/lib/graphql/graphql.js +1674 -1095
  11. package/lib/labels.d.ts +3 -0
  12. package/lib/labels.js +37 -0
  13. package/lib/lib/request/api/index.d.ts +6 -0
  14. package/lib/lib/request/api/index.js +20 -0
  15. package/lib/lib/request/api/mutations/create-request.d.ts +8 -0
  16. package/lib/lib/request/api/mutations/create-request.js +159 -0
  17. package/lib/lib/request/api/queries/apps.d.ts +4 -0
  18. package/lib/lib/request/api/queries/apps.js +73 -0
  19. package/lib/lib/request/api/queries/assets.d.ts +6 -0
  20. package/lib/lib/request/api/queries/assets.js +136 -0
  21. package/lib/lib/request/api/queries/request-defaults.d.ts +5 -0
  22. package/lib/lib/request/api/queries/request-defaults.js +51 -0
  23. package/lib/lib/request/api/queries/requests.d.ts +4 -0
  24. package/lib/lib/request/api/queries/requests.js +163 -0
  25. package/lib/lib/request/api/queries/roles.d.ts +5 -0
  26. package/lib/lib/request/api/queries/roles.js +239 -0
  27. package/lib/{utils → lib/request}/displays.d.ts +4 -2
  28. package/lib/{utils → lib/request}/displays.js +41 -19
  29. package/lib/lib/request/prompts/apps-prompt.d.ts +4 -0
  30. package/lib/lib/request/prompts/apps-prompt.js +35 -0
  31. package/lib/lib/request/prompts/asset-prompt.d.ts +5 -0
  32. package/lib/lib/request/prompts/asset-prompt.js +81 -0
  33. package/lib/lib/request/prompts/duration-prompt.d.ts +2 -0
  34. package/lib/lib/request/prompts/duration-prompt.js +122 -0
  35. package/lib/lib/request/prompts/index.d.ts +8 -0
  36. package/lib/lib/request/prompts/index.js +20 -0
  37. package/lib/lib/request/prompts/reason-prompt.d.ts +2 -0
  38. package/lib/lib/request/prompts/reason-prompt.js +20 -0
  39. package/lib/lib/request/prompts/role-prompt.d.ts +4 -0
  40. package/lib/lib/request/prompts/role-prompt.js +44 -0
  41. package/lib/lib/request/prompts/validate-prompt.d.ts +4 -0
  42. package/lib/lib/request/prompts/validate-prompt.js +29 -0
  43. package/lib/lib/request/request-utils.d.ts +15 -0
  44. package/lib/lib/request/request-utils.js +467 -0
  45. package/lib/lib/request/types.d.ts +55 -0
  46. package/lib/lib/request/types.js +15 -0
  47. package/lib/lib/util.d.ts +1 -0
  48. package/lib/lib/util.js +16 -0
  49. package/lib/types.d.ts +19 -3
  50. package/lib/types.js +18 -2
  51. package/oclif.manifest.json +54 -38
  52. package/package.json +1 -1
  53. package/lib/lib/requests.d.ts +0 -54
  54. package/lib/lib/requests.js +0 -1160
  55. package/lib/utils/utils.d.ts +0 -1
  56. package/lib/utils/utils.js +0 -18
@@ -1,1160 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DISPLAY_LABELS = void 0;
4
- exports.initEmptyRequestMetadata = initEmptyRequestMetadata;
5
- exports.selectRequestableItems = selectRequestableItems;
6
- exports.doneSelectingAssets = doneSelectingAssets;
7
- exports.setRequestDefaults = setRequestDefaults;
8
- exports.promptForReason = promptForReason;
9
- exports.promptForExpiration = promptForExpiration;
10
- exports.promptRequestSubmission = promptRequestSubmission;
11
- exports.submitFinalRequest = submitFinalRequest;
12
- exports.getRequestLink = getRequestLink;
13
- exports.bypassRequestSelection = bypassRequestSelection;
14
- exports.bypassDuration = bypassDuration;
15
- const chalk_1 = require("chalk");
16
- const graphql_1 = require("../graphql");
17
- const graphql_2 = require("../graphql/graphql");
18
- const displays_1 = require("../utils/displays");
19
- const config_1 = require("./config");
20
- const { AutoComplete, Select, prompt, Form } = require("enquirer");
21
- function entityTypeFromString(str) {
22
- const capStr = str === null || str === void 0 ? void 0 : str.toLocaleUpperCase();
23
- if (capStr === "RESOURCE") {
24
- return graphql_2.EntityType.Resource;
25
- }
26
- if (capStr === "GROUP") {
27
- return graphql_2.EntityType.Group;
28
- }
29
- // if type unknown, default to resource
30
- return graphql_2.EntityType.Resource;
31
- }
32
- exports.DISPLAY_LABELS = {
33
- [graphql_2.EntityType.Resource]: "Resource",
34
- [graphql_2.EntityType.Group]: "Group",
35
- };
36
- function initEmptyRequestMetadata() {
37
- // Initialize with empty defaults
38
- const requestDefaults = {
39
- durationOptions: [],
40
- recommendedDurationInMinutes: undefined,
41
- defaultDurationInMinutes: undefined,
42
- maxDurationInMinutes: undefined,
43
- requireSupportTicket: false,
44
- reasonOptional: false,
45
- requesterIsAdmin: false,
46
- };
47
- // Initialize with empty map
48
- const requestMap = {};
49
- return {
50
- requestMap,
51
- requestDefaults,
52
- durationLabel: "",
53
- durationInMinutes: 0,
54
- reason: "",
55
- };
56
- }
57
- // Queries and Mutations
58
- // TODO: add pagination ability from CLI. (Load more...) option
59
- const GET_REQUESTABLE_APPS_QUERY = (0, graphql_1.graphql)(`
60
- query GetRequestableAppsQuery($searchQuery: String) {
61
- appsV2(
62
- filters: {
63
- access: REQUESTABLE
64
- searchQuery: $searchQuery
65
- }
66
- ) @connection(key: "paginated-app-dropdown") {
67
- edges {
68
- node {
69
- id
70
- displayName
71
- ... on Connection {
72
- connectionType
73
- }
74
- ... on Resource {
75
- resourceType
76
- }
77
- }
78
- }
79
- pageInfo {
80
- hasNextPage
81
- hasPreviousPage
82
- startCursor
83
- endCursor
84
- }
85
- }
86
- }
87
- `);
88
- async function queryRequestableApps(cmd, client, input) {
89
- var _a, _b;
90
- try {
91
- const resp = await client.query({
92
- query: GET_REQUESTABLE_APPS_QUERY,
93
- variables: {
94
- searchQuery: input || "",
95
- },
96
- fetchPolicy: "network-only", // to avoid caching
97
- });
98
- return (_b = (_a = resp === null || resp === void 0 ? void 0 : resp.data) === null || _a === void 0 ? void 0 : _a.appsV2) === null || _b === void 0 ? void 0 : _b.edges.map((edge) => {
99
- let type = undefined;
100
- switch (edge.node.__typename) {
101
- case "Resource":
102
- type = edge.node.resourceType;
103
- break;
104
- case "Connection":
105
- type = edge.node.connectionType;
106
- break;
107
- default:
108
- type = edge.node.__typename;
109
- }
110
- return {
111
- message: `${edge.node.displayName} [${type}]`,
112
- value: {
113
- id: edge.node.id,
114
- name: edge.node.displayName,
115
- type: type,
116
- toString: () => edge.node.displayName,
117
- },
118
- };
119
- });
120
- }
121
- catch (error) {
122
- if (error instanceof Error || typeof error === "string") {
123
- cmd.error(error);
124
- }
125
- }
126
- }
127
- const GET_ASSETS_QUERY = (0, graphql_1.graphql)(`
128
- query PaginatedEntityDropdown(
129
- $id: UUID!
130
- $searchQuery: String
131
- ) {
132
- app(id: $id) {
133
- __typename
134
- ... on App {
135
- id
136
- items(
137
- input: {
138
- access: REQUESTABLE
139
- searchQuery: $searchQuery
140
- includeOnlyRequestable: true
141
- }
142
- ) {
143
- items {
144
- key
145
- resource {
146
- id
147
- name
148
- }
149
- group {
150
- id
151
- name
152
- }
153
- }
154
- cursor
155
- }
156
- }
157
- ... on AppNotFoundError {
158
- message
159
- }
160
- }
161
- }
162
- `);
163
- async function queryRequestableAssets(cmd, client, appId, input) {
164
- var _a, _b, _c, _d, _e, _f;
165
- try {
166
- const resp = await client.query({
167
- query: GET_ASSETS_QUERY,
168
- variables: {
169
- id: appId || "",
170
- searchQuery: input || "",
171
- },
172
- fetchPolicy: "network-only", // to avoid caching
173
- });
174
- // no fall through doesn't consider process.exit();
175
- let x;
176
- switch (resp.data.app.__typename) {
177
- case "App":
178
- return (_d = (_c = (_b = (_a = resp.data) === null || _a === void 0 ? void 0 : _a.app) === null || _b === void 0 ? void 0 : _b.items) === null || _c === void 0 ? void 0 : _c.items) === null || _d === void 0 ? void 0 : _d.map((item) => {
179
- var _a, _b, _c, _d, _e, _f, _g, _h;
180
- const name = ((_a = item.resource) === null || _a === void 0 ? void 0 : _a.name) || ((_b = item.group) === null || _b === void 0 ? void 0 : _b.name);
181
- const id = ((_c = item.resource) === null || _c === void 0 ? void 0 : _c.id) || ((_d = item.group) === null || _d === void 0 ? void 0 : _d.id);
182
- const type = ((_e = item.resource) === null || _e === void 0 ? void 0 : _e.__typename) || ((_f = item.group) === null || _f === void 0 ? void 0 : _f.__typename);
183
- return {
184
- message: `${name} [${type}]`,
185
- value: {
186
- name: name || "",
187
- id: id || "",
188
- type: entityTypeFromString(((_g = item.resource) === null || _g === void 0 ? void 0 : _g.__typename) || ((_h = item.group) === null || _h === void 0 ? void 0 : _h.__typename)),
189
- },
190
- };
191
- });
192
- case "AppNotFoundError":
193
- x = cmd.error((_f = (_e = resp.data) === null || _e === void 0 ? void 0 : _e.app) === null || _f === void 0 ? void 0 : _f.message);
194
- break;
195
- default:
196
- cmd.error(resp.error || "Unknown error occurred.");
197
- }
198
- }
199
- catch (error) {
200
- if (error instanceof Error || typeof error === "string") {
201
- cmd.error(error);
202
- }
203
- }
204
- }
205
- const RESOURCE_ROLES_QUERY = (0, graphql_1.graphql)(`
206
- query ResourceAccessLevels($resourceId: ResourceId!) {
207
- accessLevels(input: {
208
- resourceId: $resourceId,
209
- onlyMine: false,
210
- }) {
211
- __typename
212
- ... on ResourceAccessLevelsResult {
213
- accessLevels {
214
- ... on ResourceAccessLevel {
215
- accessLevelName
216
- accessLevelRemoteId
217
- }
218
- }
219
- }
220
- ... on ResourceNotFoundError {
221
- message
222
- }
223
- }
224
- }
225
- `);
226
- const GROUP_ROLES_QUERY = (0, graphql_1.graphql)(`
227
- query GroupAccessLevels($groupId: GroupId!) {
228
- groupAccessLevels(
229
- input: { groupId: $groupId }
230
- ) {
231
- ... on GroupAccessLevelsResult {
232
- groupId
233
- accessLevels {
234
- ... on GroupAccessLevel {
235
- accessLevelName
236
- accessLevelRemoteId
237
- }
238
- }
239
- }
240
- }
241
- }
242
- `);
243
- async function queryAssetRoles(cmd, client, assetType, assetId) {
244
- var _a, _b, _c, _d, _e, _f, _g, _h;
245
- try {
246
- switch (assetType) {
247
- case graphql_2.EntityType.Resource: {
248
- const resp = await client.query({
249
- query: RESOURCE_ROLES_QUERY,
250
- variables: {
251
- resourceId: assetId,
252
- },
253
- fetchPolicy: "network-only", // to avoid caching
254
- });
255
- // no fall through doesn't consider process.exit();
256
- let x;
257
- switch (resp.data.accessLevels.__typename) {
258
- case "ResourceAccessLevelsResult":
259
- return (_c = (_b = (_a = resp.data) === null || _a === void 0 ? void 0 : _a.accessLevels) === null || _b === void 0 ? void 0 : _b.accessLevels) === null || _c === void 0 ? void 0 : _c.map((role) => {
260
- return {
261
- message: role.accessLevelName || "",
262
- value: {
263
- name: role.accessLevelName || "",
264
- id: role.accessLevelRemoteId || "",
265
- },
266
- };
267
- });
268
- case "ResourceNotFoundError":
269
- x = cmd.error((_e = (_d = resp.data) === null || _d === void 0 ? void 0 : _d.accessLevels) === null || _e === void 0 ? void 0 : _e.message);
270
- break;
271
- default:
272
- cmd.error(resp.error || "Unknown error occurred.");
273
- }
274
- return;
275
- }
276
- case graphql_2.EntityType.Group: {
277
- const resp = await client.query({
278
- query: GROUP_ROLES_QUERY,
279
- variables: {
280
- groupId: assetId,
281
- },
282
- fetchPolicy: "network-only", // to avoid caching
283
- });
284
- // no fall through doesn't consider process.exit();
285
- let x;
286
- switch (resp.data.groupAccessLevels.__typename) {
287
- case "GroupAccessLevelsResult":
288
- return (_h = (_g = (_f = resp.data) === null || _f === void 0 ? void 0 : _f.groupAccessLevels) === null || _g === void 0 ? void 0 : _g.accessLevels) === null || _h === void 0 ? void 0 : _h.map((role) => {
289
- return {
290
- message: role.accessLevelName,
291
- value: {
292
- name: role.accessLevelName,
293
- id: role.accessLevelRemoteId,
294
- },
295
- };
296
- });
297
- default:
298
- x = cmd.error(resp.error || "Unknown error occurred.");
299
- }
300
- return;
301
- }
302
- }
303
- }
304
- catch (error) {
305
- if (error instanceof Error || typeof error === "string") {
306
- cmd.error(error);
307
- }
308
- }
309
- }
310
- const REQUEST_DEFAULTS_QUERY = (0, graphql_1.graphql)(`
311
- query RequestDefaults(
312
- $requestedResources: [RequestConfigurationResourceInput!]!
313
- $requestedGroups: [RequestConfigurationGroupInput!]!
314
- ) {
315
- requestDefaults(input: {
316
- requestedResources: $requestedResources,
317
- requestedGroups: $requestedGroups,
318
- }
319
- ) {
320
- ... on RequestDefaults {
321
- durationOptions {
322
- durationInMinutes
323
- label
324
- }
325
- recommendedDurationInMinutes
326
- defaultDurationInMinutes
327
- maxDurationInMinutes
328
- requireSupportTicket
329
- reasonOptional
330
- requesterIsAdmin
331
- }
332
- }
333
- }`);
334
- async function queryRequestDefaults(cmd, client, requestedResources, requestedGroups) {
335
- try {
336
- const resp = await client.query({
337
- query: REQUEST_DEFAULTS_QUERY,
338
- variables: {
339
- requestedResources: requestedResources,
340
- requestedGroups: requestedGroups,
341
- },
342
- fetchPolicy: "network-only", // to avoid caching
343
- });
344
- return resp.data.requestDefaults;
345
- }
346
- catch (error) {
347
- if (error instanceof Error || typeof error === "string") {
348
- cmd.error(error);
349
- }
350
- }
351
- }
352
- const CREATE_REQUEST_MUTATION = (0, graphql_1.graphql)(`
353
- mutation CreateRequest(
354
- $requestedResources: [RequestedResourceInput!]!
355
- $requestedGroups: [RequestedGroupInput!]!
356
- $reason: String!
357
- $durationInMinutes: Int
358
- ) {
359
- createRequest(
360
- input: {
361
- requestedResources: $requestedResources
362
- requestedGroups: $requestedGroups
363
- reason: $reason
364
- durationInMinutes: $durationInMinutes
365
- }
366
- ) {
367
- ... on CreateRequestResult {
368
- request {
369
- id
370
- status
371
- }
372
- }
373
- ... on RequestDurationTooLargeError {
374
- message
375
- }
376
- ... on RequestRequiresUserAuthTokenForConnectionError {
377
- message
378
- }
379
- ... on NoReviewersSetForOwnerError {
380
- message
381
- ownerId
382
- }
383
- ... on NoReviewersSetForResourceError {
384
- message
385
- resourceId
386
- }
387
- ... on NoReviewersSetForGroupError {
388
- message
389
- groupId
390
- }
391
- ... on NoManagerSetForRequestingUserError {
392
- message
393
- }
394
- ... on MfaInvalidError {
395
- message
396
- }
397
- ... on BulkRequestTooLargeError {
398
- message
399
- }
400
- ... on ItemCannotBeRequestedError {
401
- message
402
- }
403
- ... on UserCannotRequestAccessForTargetGroupError {
404
- message
405
- groupId
406
- userId
407
- }
408
- ... on GroupNestingNotAllowedError {
409
- message
410
- fromGroupId
411
- toGroupId
412
- }
413
- ... on TargetUserHasNestedAccessError {
414
- message
415
- groupIds
416
- }
417
- ... on RequestReasonMissingError {
418
- message
419
- }
420
- ... on RequestFieldValueMissingError {
421
- message
422
- fieldName
423
- }
424
- ... on LinkedGroupNotRequestableError {
425
- message
426
- sourceGroupId
427
- groupBindingId
428
- }
429
- ... on RequestReasonBelowMinLengthError {
430
- message
431
- }
432
-
433
- }
434
- }
435
- `);
436
- async function createRequest(cmd, client, requestedResources, requestedGroups, reason, durationInMinutes) {
437
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
438
- try {
439
- const resp = await client.mutate({
440
- mutation: CREATE_REQUEST_MUTATION,
441
- variables: {
442
- requestedResources: requestedResources,
443
- requestedGroups: requestedGroups,
444
- reason: reason,
445
- durationInMinutes: durationInMinutes,
446
- },
447
- });
448
- switch ((_a = resp.data) === null || _a === void 0 ? void 0 : _a.createRequest.__typename) {
449
- case "CreateRequestResult":
450
- return (_b = resp.data) === null || _b === void 0 ? void 0 : _b.createRequest.request;
451
- case "RequestDurationTooLargeError":
452
- cmd.log((_c = resp.data) === null || _c === void 0 ? void 0 : _c.createRequest.message);
453
- break;
454
- case "RequestRequiresUserAuthTokenForConnectionError":
455
- cmd.log((_d = resp.data) === null || _d === void 0 ? void 0 : _d.createRequest.message);
456
- break;
457
- case "NoReviewersSetForOwnerError":
458
- cmd.log((_e = resp.data) === null || _e === void 0 ? void 0 : _e.createRequest.message);
459
- break;
460
- case "NoReviewersSetForResourceError":
461
- cmd.log((_f = resp.data) === null || _f === void 0 ? void 0 : _f.createRequest.message);
462
- break;
463
- case "NoReviewersSetForGroupError":
464
- cmd.log((_g = resp.data) === null || _g === void 0 ? void 0 : _g.createRequest.message);
465
- break;
466
- case "NoManagerSetForRequestingUserError":
467
- cmd.log((_h = resp.data) === null || _h === void 0 ? void 0 : _h.createRequest.message);
468
- break;
469
- case "MfaInvalidError":
470
- cmd.log((_j = resp.data) === null || _j === void 0 ? void 0 : _j.createRequest.message);
471
- break;
472
- case "BulkRequestTooLargeError":
473
- cmd.log((_k = resp.data) === null || _k === void 0 ? void 0 : _k.createRequest.message);
474
- break;
475
- case "ItemCannotBeRequestedError":
476
- cmd.log((_l = resp.data) === null || _l === void 0 ? void 0 : _l.createRequest.message);
477
- break;
478
- case "UserCannotRequestAccessForTargetGroupError":
479
- cmd.log((_m = resp.data) === null || _m === void 0 ? void 0 : _m.createRequest.message);
480
- break;
481
- case "GroupNestingNotAllowedError":
482
- cmd.log((_o = resp.data) === null || _o === void 0 ? void 0 : _o.createRequest.message);
483
- break;
484
- case "TargetUserHasNestedAccessError":
485
- cmd.log((_p = resp.data) === null || _p === void 0 ? void 0 : _p.createRequest.message);
486
- break;
487
- case "RequestReasonMissingError":
488
- cmd.log((_q = resp.data) === null || _q === void 0 ? void 0 : _q.createRequest.message);
489
- break;
490
- case "RequestFieldValueMissingError":
491
- cmd.log((_r = resp.data) === null || _r === void 0 ? void 0 : _r.createRequest.message);
492
- break;
493
- case "LinkedGroupNotRequestableError":
494
- cmd.log((_s = resp.data) === null || _s === void 0 ? void 0 : _s.createRequest.message);
495
- break;
496
- case "RequestReasonBelowMinLengthError":
497
- cmd.log((_t = resp.data) === null || _t === void 0 ? void 0 : _t.createRequest.message);
498
- break;
499
- }
500
- }
501
- catch (error) {
502
- if (error instanceof Error || typeof error === "string") {
503
- cmd.error(error);
504
- }
505
- }
506
- }
507
- const CATALOG_ITEM = (0, graphql_1.graphql)(`
508
- query GetCatalogItem($uuid: UUID!) {
509
- catalogItem(id: $uuid) {
510
- __typename
511
- ... on Connection {
512
- id
513
- displayName
514
- }
515
- ... on Resource {
516
- id
517
- displayName
518
- connection {
519
- id
520
- displayName
521
- }
522
- accessLevels{
523
- accessLevelName
524
- accessLevelRemoteId
525
- }
526
- }
527
- ...on Group {
528
- id
529
- name
530
- connection {
531
- id
532
- displayName
533
- }
534
- accessLevels{
535
- accessLevelName
536
- accessLevelRemoteId
537
- }
538
- }
539
- ... on UserFacingError {
540
- message
541
- }
542
- }
543
- }
544
- `);
545
- const ASSOCIATED_ITEMS_QUERY = (0, graphql_1.graphql)(`
546
- query GetAssociatedItems($resourceId: ResourceId!, $searchQuery: String) {
547
- resource(input: {
548
- id: $resourceId
549
- }) {
550
- __typename
551
- ... on ResourceResult {
552
- __typename
553
- resource {
554
- associatedItems(
555
- first: 200
556
- filters: {
557
- searchQuery: {
558
- contains: $searchQuery
559
- }
560
- access: REQUESTABLE
561
- endUserVisible: true
562
- entityType: {
563
- in: [GROUP, RESOURCE]
564
- }
565
- }
566
- ) {
567
- edges {
568
- __typename
569
- ... on ResourceAssociatedItemEdge {
570
- alias
571
- node {
572
- __typename
573
- id
574
- name
575
- ... on Resource {
576
- accessLevels(
577
- filters: {
578
- skipRemoteAccessLevels: false # azure app roles are remote
579
- }
580
- ) {
581
- __typename
582
- accessLevelName
583
- accessLevelRemoteId
584
- }
585
- }
586
- }
587
- }
588
- }
589
- }
590
- }
591
- }
592
- ... on ResourceNotFoundError {
593
- message
594
- }
595
- }
596
- }
597
- `);
598
- async function queryAssociatedItems(cmd, client, id, input) {
599
- var _a, _b;
600
- try {
601
- const resp = await client.query({
602
- query: ASSOCIATED_ITEMS_QUERY,
603
- variables: {
604
- resourceId: id || "",
605
- searchQuery: input || "",
606
- },
607
- fetchPolicy: "network-only", // to avoid caching
608
- });
609
- switch (resp.data.resource.__typename) {
610
- case "ResourceResult": {
611
- const associatedItems = resp.data.resource.resource.associatedItems.edges.filter((edge) => edge.__typename === "ResourceAssociatedItemEdge");
612
- const initial = [];
613
- for (const edge of associatedItems) {
614
- initial.push(...appRolesFromEdge(edge));
615
- }
616
- return initial;
617
- }
618
- case "ResourceNotFoundError":
619
- cmd.log((_b = (_a = resp.data) === null || _a === void 0 ? void 0 : _a.resource) === null || _b === void 0 ? void 0 : _b.message);
620
- break;
621
- default:
622
- cmd.error(resp.error || "Unknown error occurred.");
623
- }
624
- }
625
- catch (error) {
626
- if (error instanceof Error || typeof error === "string") {
627
- cmd.error(error);
628
- }
629
- }
630
- }
631
- // Helper functions
632
- const selectInstructions = chalk_1.default.dim("[↑↓] Navigate · [Enter] Select · Type to filter");
633
- const multiSelectInstructions = chalk_1.default.dim("[↑↓] Navigate · [Space] Select · [Enter] Confirm · Type to filter");
634
- async function selectRequestableItems(cmd, client, requestMap) {
635
- const initial = (await queryRequestableApps(cmd, client, "")) || [];
636
- const appPrompt = new AutoComplete({
637
- name: "App",
638
- message: "Select an app",
639
- hint: selectInstructions,
640
- limit: 15,
641
- choices: initial,
642
- async suggest(input) {
643
- const filteredChoices = await queryRequestableApps(cmd, client, input || "");
644
- return filteredChoices || initial;
645
- },
646
- });
647
- const App = await appPrompt.run();
648
- // Set the app in the requestMap and call choose assets step
649
- if (!(App.id in requestMap)) {
650
- requestMap[App.id] = {
651
- appId: App.id,
652
- appName: App.name,
653
- assets: {},
654
- };
655
- }
656
- if (App.type === "OKTA_APP" || App.type === "AZURE_ENTERPRISE_APP") {
657
- await chooseOktaAzureRoles(cmd, client, App, requestMap);
658
- return;
659
- }
660
- await chooseAssets(cmd, client, App.id, requestMap);
661
- }
662
- async function chooseOktaAzureRoles(cmd, client, app, requestMap) {
663
- const associatedItems = (await queryAssociatedItems(cmd, client, app.id, "")) || [];
664
- const rolePrompt = new AutoComplete({
665
- name: "Roles",
666
- message: `Select a role for ${app.name}:`,
667
- hint: multiSelectInstructions,
668
- limit: 15,
669
- multiple: true,
670
- async choices(input) {
671
- if (!input)
672
- return associatedItems;
673
- const filteredChoices = await queryAssociatedItems(cmd, client, app.id, input);
674
- return filteredChoices || associatedItems;
675
- },
676
- validate: (answer) => {
677
- if (answer.length !== 1) {
678
- return "Only one role is allowed to be requested for on Okta or Azure apps.";
679
- }
680
- return true;
681
- },
682
- });
683
- const Roles = await rolePrompt.run();
684
- const entry = requestMap[app.id];
685
- for (const role of Roles) {
686
- if (!(role.id in entry.assets)) {
687
- entry.assets[role.id] = {
688
- assetId: role.id,
689
- assetName: role.name,
690
- type: entityTypeFromString(role.type),
691
- roles: {},
692
- };
693
- }
694
- }
695
- }
696
- function appRolesFromEdge(edge) {
697
- var _a, _b, _c, _d;
698
- switch (edge.node.__typename) {
699
- case "Resource": {
700
- if (edge.node.accessLevels && edge.node.accessLevels.length > 0) {
701
- return edge.node.accessLevels.map((accessLevel) => ({
702
- message: accessLevel.accessLevelName || "No Role (Direct access)",
703
- value: {
704
- id: edge.node.id + accessLevel.accessLevelRemoteId,
705
- name: accessLevel.accessLevelName,
706
- type: exports.DISPLAY_LABELS[graphql_2.EntityType.Resource],
707
- toString: () => accessLevel.accessLevelName,
708
- },
709
- }));
710
- }
711
- return [
712
- {
713
- message: (_a = edge.alias) !== null && _a !== void 0 ? _a : edge.node.name,
714
- value: {
715
- id: edge.node.id,
716
- name: (_b = edge.alias) !== null && _b !== void 0 ? _b : edge.node.name,
717
- type: exports.DISPLAY_LABELS[graphql_2.EntityType.Resource],
718
- toString: () => { var _a; return (_a = edge.alias) !== null && _a !== void 0 ? _a : edge.node.name; },
719
- },
720
- },
721
- ];
722
- }
723
- case "Group":
724
- return [
725
- {
726
- message: `${(_c = edge.alias) !== null && _c !== void 0 ? _c : edge.node.name} ${graphql_2.EntityType.Group}`,
727
- value: {
728
- id: edge.node.id,
729
- name: (_d = edge.alias) !== null && _d !== void 0 ? _d : edge.node.name,
730
- type: exports.DISPLAY_LABELS[graphql_2.EntityType.Group],
731
- toString: () => { var _a; return (_a = edge.alias) !== null && _a !== void 0 ? _a : edge.node.name; },
732
- },
733
- },
734
- ];
735
- }
736
- }
737
- async function chooseAssets(cmd, client, appId, requestMap) {
738
- const initial = (await queryRequestableAssets(cmd, client, appId, "")) || [];
739
- const assetPrompt = new AutoComplete({
740
- name: "Assets",
741
- message: "Select one or more assets:",
742
- hint: multiSelectInstructions,
743
- limit: 15,
744
- multiple: true,
745
- async choices(input) {
746
- if (!input) {
747
- return initial;
748
- }
749
- const filteredChoices = await queryRequestableAssets(cmd, client, appId, input);
750
- return filteredChoices || initial;
751
- },
752
- validate: (answer) => {
753
- if (answer.length < 1) {
754
- return "You must select at least one item.";
755
- }
756
- return true;
757
- },
758
- });
759
- const Assets = await assetPrompt.run();
760
- const entry = requestMap[appId];
761
- for (const asset of Assets) {
762
- if (entry === undefined) {
763
- throw new Error(`Error formatting app ${appId} in request`);
764
- }
765
- if (!(asset.id in entry.assets)) {
766
- entry.assets[asset.id] = {
767
- assetId: asset.id,
768
- assetName: asset.name,
769
- type: asset.type,
770
- roles: {},
771
- };
772
- }
773
- await chooseRoles(cmd, client, appId, asset.id, requestMap);
774
- }
775
- }
776
- async function chooseRoles(cmd, client, appId, assetId, requestMap) {
777
- var _a;
778
- const entry = requestMap[appId];
779
- const assetEntry = entry === null || entry === void 0 ? void 0 : entry.assets[assetId];
780
- if (entry === undefined || assetEntry === undefined) {
781
- throw new Error(`App ${appId} or Asset ${assetId} not found in requestMap`);
782
- }
783
- const assetRoles = (_a = (await queryAssetRoles(cmd, client, assetEntry.type, assetId))) !== null && _a !== void 0 ? _a : [];
784
- if (assetRoles !== undefined &&
785
- (assetRoles.length === 0 ||
786
- (assetRoles.length === 1 && assetRoles[0].value.name === ""))) {
787
- return;
788
- }
789
- const rolePrompt = new AutoComplete({
790
- name: "Roles",
791
- message: `Select one or more roles for ${assetEntry.assetName}:`,
792
- hint: multiSelectInstructions,
793
- limit: 15,
794
- multiple: true,
795
- choices: assetRoles,
796
- validate: (answer) => {
797
- if (answer.length < 1) {
798
- return "You must select at least one item.";
799
- }
800
- return true;
801
- },
802
- });
803
- const roles = await rolePrompt.run();
804
- if (!assetEntry.roles) {
805
- assetEntry.roles = {};
806
- }
807
- for (const role of roles) {
808
- assetEntry.roles[role.id] = {
809
- roleId: role.id,
810
- roleName: role.name,
811
- };
812
- }
813
- }
814
- async function doneSelectingAssets() {
815
- const submitMessage = "✅ Yes, proceed with request";
816
- const addMoreMessage = "❌ No, add more items";
817
- const prompt = new Select({
818
- name: "submitOrAdd",
819
- message: "Is this all you want to request?",
820
- choices: [submitMessage, addMoreMessage],
821
- });
822
- const submitOrAdd = await prompt.run();
823
- return submitOrAdd === submitMessage;
824
- }
825
- async function setRequestDefaults(cmd, client, metadata) {
826
- const requestMap = metadata.requestMap;
827
- const requestedResources = [];
828
- const requestedGroups = [];
829
- for (const appNode of Object.values(requestMap)) {
830
- for (const [assetId, assetNode] of Object.entries(appNode.assets)) {
831
- if (assetNode.roles !== undefined) {
832
- const mappedRoles = Object.entries(assetNode.roles).map(([roleId, _roleNode]) => {
833
- return roleId;
834
- });
835
- const roleIds = mappedRoles.length ? mappedRoles : [""];
836
- for (const roleId of roleIds) {
837
- switch (assetNode.type) {
838
- case graphql_2.EntityType.Resource: {
839
- requestedResources.push({
840
- resourceId: assetId,
841
- accessLevelRemoteId: roleId,
842
- });
843
- break;
844
- }
845
- case graphql_2.EntityType.Group: {
846
- requestedGroups.push({
847
- groupId: assetId,
848
- accessLevelRemoteId: roleId,
849
- });
850
- break;
851
- }
852
- }
853
- }
854
- }
855
- }
856
- }
857
- try {
858
- const requestDefaults = await queryRequestDefaults(cmd, client, requestedResources, requestedGroups);
859
- if (requestDefaults !== undefined) {
860
- metadata.requestDefaults.durationOptions =
861
- requestDefaults.durationOptions;
862
- metadata.requestDefaults.recommendedDurationInMinutes =
863
- requestDefaults.recommendedDurationInMinutes;
864
- metadata.requestDefaults.defaultDurationInMinutes =
865
- requestDefaults.defaultDurationInMinutes;
866
- metadata.requestDefaults.maxDurationInMinutes =
867
- requestDefaults.maxDurationInMinutes;
868
- metadata.requestDefaults.requireSupportTicket =
869
- requestDefaults.requireSupportTicket;
870
- metadata.requestDefaults.reasonOptional = requestDefaults.reasonOptional;
871
- metadata.requestDefaults.requesterIsAdmin =
872
- requestDefaults.requesterIsAdmin;
873
- }
874
- }
875
- catch (_a) {
876
- cmd.error("Error fetching request defaults.");
877
- }
878
- }
879
- async function promptForReason(metadata) {
880
- const { reason } = await prompt([
881
- {
882
- name: "reason",
883
- message: "Why do you need access?",
884
- type: "input",
885
- validate: (answer) => {
886
- if (!metadata.requestDefaults.reasonOptional && answer.length < 1) {
887
- return "A reason for requesting these assets is required.";
888
- }
889
- return true;
890
- },
891
- },
892
- ]);
893
- metadata.reason = reason;
894
- }
895
- async function promptForExpiration(metadata) {
896
- var _a, _b;
897
- const durations = ((_b = (_a = metadata.requestDefaults) === null || _a === void 0 ? void 0 : _a.durationOptions) === null || _b === void 0 ? void 0 : _b.map((option) => {
898
- var _a;
899
- let label = option.label;
900
- if (option.durationInMinutes ===
901
- ((_a = metadata.requestDefaults) === null || _a === void 0 ? void 0 : _a.maxDurationInMinutes)) {
902
- label = `${label} (MAX)`;
903
- }
904
- if (option.durationInMinutes ===
905
- metadata.requestDefaults.recommendedDurationInMinutes) {
906
- label = `${label} (RECOMMENDED)`;
907
- }
908
- return {
909
- message: label,
910
- value: {
911
- label: label,
912
- durationInMinutes: option.durationInMinutes,
913
- toString: () => label,
914
- },
915
- };
916
- })) || [];
917
- // Sort durations by minutes
918
- durations.sort((a, b) => a.value.durationInMinutes - b.value.durationInMinutes);
919
- const expirationSelect = new AutoComplete({
920
- name: "expiration",
921
- message: "When should access expire?",
922
- hint: "Type to filter",
923
- type: "list",
924
- choices: durations,
925
- pageSize: 15,
926
- });
927
- let selected = await expirationSelect.run();
928
- switch (selected.label) {
929
- case "Custom": {
930
- selected = await setCustomDuration(metadata);
931
- break;
932
- }
933
- case "Permanent": {
934
- selected.durationInMinutes = undefined;
935
- break;
936
- }
937
- }
938
- metadata.durationInMinutes = selected.durationInMinutes;
939
- metadata.durationLabel = selected.label;
940
- }
941
- function getDurationNumbers(duration) {
942
- const d = +duration.days || 0;
943
- const h = +duration.hours || 0;
944
- const m = +duration.minutes || 0;
945
- return { d, h, m };
946
- }
947
- function getDurationInMinutes(duration) {
948
- const { d, h, m } = getDurationNumbers(duration);
949
- const minutesInDay = 1440; // 24 hours * 60 minutes
950
- const minutesInHour = 60;
951
- return d * minutesInDay + h * minutesInHour + m;
952
- }
953
- function getDHMFromMinutes(minutes) {
954
- const label = [];
955
- const d = Math.floor(minutes / 1440);
956
- if (d > 0) {
957
- label.push(`${d}d`);
958
- }
959
- const remainingMinutes = minutes % 1440;
960
- const h = Math.floor(remainingMinutes / 60);
961
- if (h > 0) {
962
- label.push(`${h}h`);
963
- }
964
- const m = remainingMinutes % 60;
965
- if (m > 0) {
966
- label.push(`${m}m`);
967
- }
968
- return label.join(" ");
969
- }
970
- async function setCustomDuration(metadata) {
971
- const durationForm = new Form({
972
- name: "user",
973
- message: "Please set a custom access duration:",
974
- choices: [
975
- { name: "days", message: "Days", initial: "0" },
976
- { name: "hours", message: "Hours", initial: "0" },
977
- { name: "minutes", message: "Minutes", initial: "0" },
978
- ],
979
- validate: (answer) => {
980
- var _a, _b, _c;
981
- const { d, h, m } = getDurationNumbers(answer);
982
- const durationInMinutes = getDurationInMinutes(answer);
983
- if (d < 0 || h < 0 || m < 0 || d + h + m === 0 || (h > 23 && m > 59)) {
984
- return "Please enter a valid duration.";
985
- }
986
- if (((_a = metadata.requestDefaults) === null || _a === void 0 ? void 0 : _a.maxDurationInMinutes) &&
987
- durationInMinutes > ((_b = metadata.requestDefaults) === null || _b === void 0 ? void 0 : _b.maxDurationInMinutes)) {
988
- const maxDHM = getDHMFromMinutes((_c = metadata.requestDefaults) === null || _c === void 0 ? void 0 : _c.maxDurationInMinutes);
989
- return `The max duration for the selected assets is ${maxDHM}.`;
990
- }
991
- return true;
992
- },
993
- return: (answer) => {
994
- return getDurationInMinutes(answer);
995
- },
996
- });
997
- const durationResult = await durationForm.run();
998
- const { d, h, m } = getDurationNumbers(durationResult);
999
- const durationInMinutes = getDurationInMinutes(durationResult);
1000
- const durationLabel = getDHMFromMinutes(durationInMinutes);
1001
- return {
1002
- durationInMinutes: durationInMinutes,
1003
- label: durationLabel,
1004
- };
1005
- }
1006
- async function promptRequestSubmission(cmd, metadata) {
1007
- (0, displays_1.displayFinalRequestSummary)(cmd, metadata);
1008
- const submitMessage = "✅ Yes, submit request";
1009
- const cancelMessage = "❌ No, cancel request";
1010
- const prompt = new Select({
1011
- name: "submitOrCancel",
1012
- message: "Is this all you want to request?",
1013
- choices: [submitMessage, cancelMessage],
1014
- });
1015
- const submitOrCancel = await prompt.run();
1016
- return submitOrCancel === submitMessage;
1017
- }
1018
- async function submitFinalRequest(cmd, client, metadata) {
1019
- var _a, _b, _c, _d;
1020
- // Build requested assets lists for the mutation
1021
- const requestedResources = [];
1022
- const requestedGroups = [];
1023
- for (const appNode of Object.values(metadata.requestMap)) {
1024
- // This extraction is different than the one in setRequestDefaults.
1025
- // Both extract the requestedResources and requestedGroups,
1026
- // use different formats.
1027
- for (const [assetId, assetNode] of Object.entries(appNode.assets)) {
1028
- if (assetNode.roles) {
1029
- const mappedRoles = Object.entries(assetNode.roles).map(([roleId, _roleNode]) => {
1030
- return roleId;
1031
- });
1032
- const roleIds = mappedRoles.length > 0 ? mappedRoles : [""];
1033
- for (const roleId of roleIds) {
1034
- switch (assetNode.type) {
1035
- case graphql_2.EntityType.Resource: {
1036
- requestedResources.push({
1037
- resourceId: assetId,
1038
- accessLevel: {
1039
- accessLevelName: ((_b = (_a = assetNode.roles) === null || _a === void 0 ? void 0 : _a[roleId]) === null || _b === void 0 ? void 0 : _b.roleName) || "",
1040
- accessLevelRemoteId: roleId,
1041
- },
1042
- });
1043
- break;
1044
- }
1045
- case graphql_2.EntityType.Group: {
1046
- requestedGroups.push({
1047
- groupId: assetId,
1048
- accessLevel: {
1049
- accessLevelName: ((_d = (_c = assetNode.roles) === null || _c === void 0 ? void 0 : _c[roleId]) === null || _d === void 0 ? void 0 : _d.roleName) || "",
1050
- accessLevelRemoteId: roleId,
1051
- },
1052
- });
1053
- break;
1054
- }
1055
- }
1056
- }
1057
- }
1058
- }
1059
- }
1060
- const resp = await createRequest(cmd, client, requestedResources, requestedGroups, metadata.reason, metadata.durationInMinutes);
1061
- // Build link to request
1062
- if (resp === null || resp === void 0 ? void 0 : resp.id) {
1063
- cmd.log("\n🎉 Your Access Request has been submitted!\n");
1064
- cmd.log(`${chalk_1.default.bold("ID: ")} ${chalk_1.default.cyan(resp === null || resp === void 0 ? void 0 : resp.id)}`);
1065
- if (resp === null || resp === void 0 ? void 0 : resp.status) {
1066
- cmd.log((0, displays_1.getStyledStatus)(resp === null || resp === void 0 ? void 0 : resp.status));
1067
- }
1068
- const requestLink = getRequestLink(cmd, resp.id);
1069
- cmd.log(`${chalk_1.default.bold("Link:")} ${chalk_1.default.underline(requestLink)}\n`);
1070
- }
1071
- return;
1072
- }
1073
- function getRequestLink(cmd, id) {
1074
- const configData = (0, config_1.getOrCreateConfigData)(cmd.config.configDir);
1075
- return `${configData[config_1.urlKey]}/requests/sent/${id}`;
1076
- }
1077
- async function bypassRequestSelection(cmd, client, flagValue, metadata) {
1078
- var _a, _b;
1079
- try {
1080
- // Query Catalog Item endpoint to identify what the id belongs to (resource or group)
1081
- for (const val of flagValue) {
1082
- const delimiterIndex = val.indexOf(":");
1083
- const assetId = delimiterIndex === -1 ? val : val.substring(0, delimiterIndex);
1084
- const roleName = delimiterIndex === -1 ? "" : val.substring(delimiterIndex + 1);
1085
- const resp = await client.query({
1086
- query: CATALOG_ITEM,
1087
- variables: {
1088
- uuid: assetId || "",
1089
- },
1090
- fetchPolicy: "network-only", // to avoid caching
1091
- });
1092
- switch (resp.data.catalogItem.__typename) {
1093
- case "Group":
1094
- case "Resource": {
1095
- const item = resp.data.catalogItem;
1096
- const assetName = item.__typename === "Resource" ? item.displayName : item.name;
1097
- const requestableRoles = (item.accessLevels || [])
1098
- // TODO: Support okta azure apps ?.filter((role) => role.accessLevelName !== "") // This assumes length == 1
1099
- .map((role) => ({
1100
- id: role.accessLevelRemoteId,
1101
- name: role.accessLevelName,
1102
- }));
1103
- const appId = ((_a = item.connection) === null || _a === void 0 ? void 0 : _a.id) || "";
1104
- if (!(appId in metadata.requestMap)) {
1105
- metadata.requestMap[appId] = {
1106
- appName: ((_b = item.connection) === null || _b === void 0 ? void 0 : _b.displayName) || "",
1107
- appId: appId,
1108
- assets: {},
1109
- };
1110
- }
1111
- const assetEntry = metadata.requestMap[appId].assets[assetId];
1112
- if (!assetEntry) {
1113
- metadata.requestMap[appId].assets[assetId] = {
1114
- assetId: assetId,
1115
- assetName: assetName,
1116
- type: entityTypeFromString(item.__typename),
1117
- roles: {},
1118
- };
1119
- }
1120
- if (requestableRoles.length > 0 &&
1121
- !(requestableRoles.length === 1 && requestableRoles[0].name === "")) {
1122
- const selectedRole = requestableRoles.find((role) => role.name === roleName);
1123
- if (selectedRole !== undefined) {
1124
- if (!metadata.requestMap[appId].assets[assetId].roles) {
1125
- metadata.requestMap[appId].assets[assetId].roles = {};
1126
- }
1127
- metadata.requestMap[appId].assets[assetId].roles[selectedRole.id] = {
1128
- roleId: selectedRole.id,
1129
- roleName: selectedRole.name,
1130
- };
1131
- }
1132
- else {
1133
- cmd.error(`Access level specified does not match one of ${assetName}'s defined access levels: ${requestableRoles.map((role) => `"${role.name}"`)}`);
1134
- }
1135
- }
1136
- break;
1137
- }
1138
- default:
1139
- cmd.error("Invalid asset id was passed in using the --id flag.");
1140
- }
1141
- }
1142
- }
1143
- catch (error) {
1144
- if (error instanceof Error || typeof error === "string") {
1145
- cmd.error(error);
1146
- }
1147
- }
1148
- return;
1149
- }
1150
- function bypassDuration(cmd, duration, metadata) {
1151
- if (duration === 0) {
1152
- metadata.durationInMinutes = undefined;
1153
- return;
1154
- }
1155
- const maxDuration = metadata.requestDefaults.maxDurationInMinutes;
1156
- if (maxDuration && duration > maxDuration) {
1157
- cmd.error(`The requested duration exceeds the allowed limit of ${maxDuration}`);
1158
- }
1159
- metadata.durationInMinutes = duration;
1160
- }