opal-security 3.0.0 → 3.0.1-beta.4f1a7ce

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 (80) hide show
  1. package/README.md +59 -44
  2. package/bin/run +1 -1
  3. package/lib/commands/aws/identity.d.ts +1 -1
  4. package/lib/commands/aws/identity.js +2 -2
  5. package/lib/commands/clear-auth-provider.d.ts +1 -1
  6. package/lib/commands/clear-auth-provider.js +3 -3
  7. package/lib/commands/curl-example.d.ts +1 -1
  8. package/lib/commands/curl-example.js +2 -2
  9. package/lib/commands/iam-roles/start.d.ts +1 -1
  10. package/lib/commands/iam-roles/start.js +14 -14
  11. package/lib/commands/kube-roles/start.d.ts +1 -1
  12. package/lib/commands/kube-roles/start.js +10 -10
  13. package/lib/commands/login.d.ts +1 -1
  14. package/lib/commands/login.js +71 -63
  15. package/lib/commands/logout.d.ts +1 -1
  16. package/lib/commands/logout.js +3 -3
  17. package/lib/commands/postgres-instances/start.d.ts +1 -1
  18. package/lib/commands/postgres-instances/start.js +35 -34
  19. package/lib/commands/request/create.d.ts +6 -0
  20. package/lib/commands/request/create.js +37 -0
  21. package/lib/commands/request/get.d.ts +6 -0
  22. package/lib/commands/request/get.js +13 -0
  23. package/lib/commands/request/list.d.ts +7 -0
  24. package/lib/commands/request/list.js +14 -0
  25. package/lib/commands/resources/get.d.ts +1 -1
  26. package/lib/commands/resources/get.js +11 -4
  27. package/lib/commands/set-auth-provider.d.ts +1 -1
  28. package/lib/commands/set-auth-provider.js +6 -4
  29. package/lib/commands/set-custom-header.d.ts +1 -1
  30. package/lib/commands/set-custom-header.js +5 -3
  31. package/lib/commands/set-token.d.ts +1 -1
  32. package/lib/commands/set-token.js +26 -19
  33. package/lib/commands/set-url.d.ts +1 -1
  34. package/lib/commands/set-url.js +13 -12
  35. package/lib/commands/ssh/copyFrom.d.ts +1 -1
  36. package/lib/commands/ssh/copyFrom.js +13 -13
  37. package/lib/commands/ssh/copyTo.d.ts +1 -1
  38. package/lib/commands/ssh/copyTo.js +13 -13
  39. package/lib/commands/ssh/start.d.ts +1 -1
  40. package/lib/commands/ssh/start.js +14 -15
  41. package/lib/graphql/fragment-masking.d.ts +19 -0
  42. package/lib/graphql/fragment-masking.js +21 -0
  43. package/lib/graphql/gql.d.ts +46 -0
  44. package/lib/graphql/gql.js +14 -0
  45. package/lib/graphql/graphql.d.ts +11476 -0
  46. package/lib/graphql/graphql.js +1819 -0
  47. package/lib/graphql/index.d.ts +2 -0
  48. package/lib/graphql/index.js +5 -0
  49. package/lib/handler.d.ts +5 -5
  50. package/lib/handler.js +7 -7
  51. package/lib/index.d.ts +1 -1
  52. package/lib/lib/apollo.d.ts +3 -2
  53. package/lib/lib/apollo.js +59 -46
  54. package/lib/lib/aws.js +15 -12
  55. package/lib/lib/cmd.d.ts +4 -6
  56. package/lib/lib/cmd.js +11 -11
  57. package/lib/lib/config.js +14 -14
  58. package/lib/lib/credentials/index.d.ts +1 -1
  59. package/lib/lib/credentials/index.js +6 -6
  60. package/lib/lib/credentials/keychain.js +5 -5
  61. package/lib/lib/credentials/localEncryption.d.ts +2 -2
  62. package/lib/lib/credentials/localEncryption.js +33 -24
  63. package/lib/lib/flags.js +9 -9
  64. package/lib/lib/requests.d.ts +22 -0
  65. package/lib/lib/requests.js +274 -0
  66. package/lib/lib/resources.d.ts +2 -2
  67. package/lib/lib/resources.js +29 -23
  68. package/lib/lib/sessions.d.ts +2 -2
  69. package/lib/lib/sessions.js +18 -17
  70. package/lib/lib/ssh.d.ts +1 -1
  71. package/lib/lib/ssh.js +8 -8
  72. package/lib/lib/util.d.ts +0 -1
  73. package/lib/lib/util.js +13 -13
  74. package/lib/types.d.ts +1787 -1787
  75. package/lib/utils/displays.d.ts +5 -0
  76. package/lib/utils/displays.js +65 -0
  77. package/lib/utils/utils.d.ts +1 -0
  78. package/lib/utils/utils.js +18 -0
  79. package/oclif.manifest.json +70 -3
  80. package/package.json +25 -29
@@ -1,11 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getSecretFromConfig = exports.setSecretInConfig = void 0;
4
- const inquirer = require("inquirer");
4
+ const node_crypto_1 = require("node:crypto");
5
5
  const argon2 = require("argon2");
6
- const crypto_1 = require("crypto");
6
+ const inquirer = require("inquirer");
7
7
  const config_1 = require("../config");
8
- const ENCRYPTION_ALGORITHM = 'aes-256-gcm';
8
+ const ENCRYPTION_ALGORITHM = "aes-256-gcm";
9
9
  /**
10
10
  * On linux, windows, and WSL, we can't easily work with the system keychain
11
11
  * So instead, we store the token encrypted in an `accessTokenDetails` block in the CLI's config file
@@ -20,9 +20,9 @@ let password;
20
20
  const promptForPassword = async (msg) => {
21
21
  const { customKey } = await inquirer.prompt([
22
22
  {
23
- name: 'customKey',
23
+ name: "customKey",
24
24
  message: msg,
25
- type: 'password',
25
+ type: "password",
26
26
  validate: (key) => key.length > 0,
27
27
  },
28
28
  ]);
@@ -30,44 +30,53 @@ const promptForPassword = async (msg) => {
30
30
  };
31
31
  const setSecretInConfig = async (command, configData, secret) => {
32
32
  if (!password) {
33
- password = await promptForPassword('Enter a password to encrypt your credentials: ');
33
+ password = await promptForPassword("Enter a password to encrypt your credentials: ");
34
34
  }
35
- const salt = (0, crypto_1.randomBytes)(24);
36
- const key = await argon2.hash(password, { hashLength: 32, raw: true, salt: salt });
37
- const iv = (0, crypto_1.randomBytes)(12);
38
- const cipher = (0, crypto_1.createCipheriv)(ENCRYPTION_ALGORITHM, key, iv);
39
- let secretEncrypted = cipher.update(secret, 'utf8', 'base64');
40
- secretEncrypted += cipher.final('base64');
35
+ const salt = (0, node_crypto_1.randomBytes)(24);
36
+ const key = await argon2.hash(password, {
37
+ hashLength: 32,
38
+ raw: true,
39
+ salt: salt,
40
+ });
41
+ const iv = (0, node_crypto_1.randomBytes)(12);
42
+ const cipher = (0, node_crypto_1.createCipheriv)(ENCRYPTION_ALGORITHM, key, iv);
43
+ let secretEncrypted = cipher.update(secret, "utf8", "base64");
44
+ secretEncrypted += cipher.final("base64");
41
45
  // In addition to storing the encrypted text, we need to store the argon2 salt, and AES authTag + IV so we can decrypt
42
46
  configData.creds.accessTokenDetails = {
43
47
  encryptedText: secretEncrypted,
44
- authTag: cipher.getAuthTag().toString('base64'),
45
- salt: salt.toString('base64'),
46
- iv: iv.toString('base64')
48
+ authTag: cipher.getAuthTag().toString("base64"),
49
+ salt: salt.toString("base64"),
50
+ iv: iv.toString("base64"),
47
51
  };
48
52
  (0, config_1.writeConfigData)(command.config.configDir, configData);
49
53
  };
50
54
  exports.setSecretInConfig = setSecretInConfig;
51
55
  const getSecretFromConfig = async (credsConfig) => {
52
- let secret;
56
+ let secret = "";
53
57
  if (credsConfig === null || credsConfig === void 0 ? void 0 : credsConfig.accessTokenDetails) {
54
58
  if (!password) {
55
- password = await promptForPassword('Enter the password used to encrypt your credentials: ');
59
+ password = await promptForPassword("Enter the password used to encrypt your credentials: ");
56
60
  }
57
- const salt = Buffer.from(credsConfig.accessTokenDetails.salt, 'base64');
58
- const iv = Buffer.from(credsConfig.accessTokenDetails.iv, 'base64');
59
- const key = await argon2.hash(password, { hashLength: 32, raw: true, salt: salt });
61
+ const salt = Buffer.from(credsConfig.accessTokenDetails.salt, "base64");
62
+ const iv = Buffer.from(credsConfig.accessTokenDetails.iv, "base64");
63
+ const key = await argon2.hash(password, {
64
+ hashLength: 32,
65
+ raw: true,
66
+ salt: salt,
67
+ });
60
68
  try {
61
- const decipher = (0, crypto_1.createDecipheriv)(ENCRYPTION_ALGORITHM, key, iv);
62
- decipher.setAuthTag(Buffer.from(credsConfig.accessTokenDetails.authTag, 'base64'));
63
- secret = decipher.update(credsConfig.accessTokenDetails.encryptedText, 'base64', 'utf8');
64
- secret += decipher.final('utf8');
69
+ const decipher = (0, node_crypto_1.createDecipheriv)(ENCRYPTION_ALGORITHM, key, iv);
70
+ decipher.setAuthTag(Buffer.from(credsConfig.accessTokenDetails.authTag, "base64"));
71
+ secret = decipher.update(credsConfig.accessTokenDetails.encryptedText, "base64", "utf8");
72
+ secret += decipher.final("utf8");
65
73
  }
66
74
  catch (error) {
67
75
  console.error("ERROR: Failed to decrypt local credentials.\n" +
68
76
  " Check that you entered the correct password, or re-authenticate with `opal login`");
69
77
  process.exit(1);
70
78
  }
79
+ // biome-ignore lint/performance/noDelete: add tests for this function and remove this eventually
71
80
  delete credsConfig.accessTokenDetails;
72
81
  }
73
82
  return secret;
package/lib/lib/flags.js CHANGED
@@ -3,24 +3,24 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SHARED_FLAGS = void 0;
4
4
  const core_1 = require("@oclif/core");
5
5
  exports.SHARED_FLAGS = {
6
- help: core_1.Flags.help({ char: 'h' }),
6
+ help: core_1.Flags.help({ char: "h" }),
7
7
  id: core_1.Flags.string({
8
8
  multiple: false,
9
- char: 'i',
10
- description: 'The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]',
9
+ char: "i",
10
+ description: "The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
11
11
  }),
12
12
  accessLevelRemoteId: core_1.Flags.string({
13
13
  multiple: false,
14
- char: 'a',
15
- description: 'The remote ID of the access level with which to access the resource.',
14
+ char: "a",
15
+ description: "The remote ID of the access level with which to access the resource.",
16
16
  }),
17
17
  sessionId: core_1.Flags.string({
18
18
  multiple: false,
19
- char: 's',
20
- description: 'The Opal ID of the session to connect to. Uses an existing session that was created via the web flow.',
19
+ char: "s",
20
+ description: "The Opal ID of the session to connect to. Uses an existing session that was created via the web flow.",
21
21
  }),
22
22
  refresh: core_1.Flags.boolean({
23
- char: 'r',
24
- description: 'Starts a new session even if one already exists. Useful if a session is about to expire.',
23
+ char: "r",
24
+ description: "Starts a new session even if one already exists. Useful if a session is about to expire.",
25
25
  }),
26
26
  };
@@ -0,0 +1,22 @@
1
+ import type { NormalizedCacheObject } from "@apollo/client/core";
2
+ import type { ApolloClient } from "@apollo/client/core/ApolloClient";
3
+ import type { Command } from "@oclif/core/lib/command";
4
+ export interface AppNode {
5
+ appName: string;
6
+ assets: Map<string, AssetNode>;
7
+ }
8
+ export interface AssetNode {
9
+ assetName: string;
10
+ roles?: Map<string, RoleNode>;
11
+ }
12
+ export interface RoleNode {
13
+ roleName: string;
14
+ }
15
+ export type RequestMap = Map<string, AppNode>;
16
+ export declare function selectRequestableItems(cmd: Command, client: ApolloClient<NormalizedCacheObject>, requestMap: RequestMap): Promise<void>;
17
+ export declare function chooseAssets(cmd: Command, client: ApolloClient<NormalizedCacheObject>, appId: string, requestMap: RequestMap): Promise<void>;
18
+ export declare function chooseRoles(appId: string, assetId: string, requestMap: RequestMap): Promise<void>;
19
+ export declare function doneSelectingAssets(): Promise<boolean>;
20
+ export declare function promptForReason(): Promise<any>;
21
+ export declare function promptForExpiration(): Promise<any>;
22
+ export declare function submitFinalRequest(cmd: Command): Promise<void>;
@@ -0,0 +1,274 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.selectRequestableItems = selectRequestableItems;
4
+ exports.chooseAssets = chooseAssets;
5
+ exports.chooseRoles = chooseRoles;
6
+ exports.doneSelectingAssets = doneSelectingAssets;
7
+ exports.promptForReason = promptForReason;
8
+ exports.promptForExpiration = promptForExpiration;
9
+ exports.submitFinalRequest = submitFinalRequest;
10
+ const inquirer = require("inquirer");
11
+ const graphql_1 = require("../graphql");
12
+ inquirer.registerPrompt("autocomplete", require("inquirer-autocomplete-prompt"));
13
+ // Queries and Mutations
14
+ const GET_REQUESTABLE_APPS_QUERY = (0, graphql_1.graphql)(`
15
+ query GetRequestableAppsQuery($searchQuery: String) {
16
+ appsV2(
17
+ filters: {
18
+ access: REQUESTABLE
19
+ searchQuery: $searchQuery
20
+ }
21
+ ) @connection(key: "paginated-app-dropdown") {
22
+ edges {
23
+ node {
24
+ id
25
+ displayName
26
+ ... on Connection {
27
+ connectionType
28
+ }
29
+ ... on Resource {
30
+ resourceType
31
+ }
32
+ }
33
+ }
34
+ pageInfo {
35
+ hasNextPage
36
+ hasPreviousPage
37
+ startCursor
38
+ endCursor
39
+ }
40
+ }
41
+ }
42
+ `);
43
+ const GET_ASSETS_QUERY = (0, graphql_1.graphql)(`
44
+ query PaginatedEntityDropdown(
45
+ $id: UUID!
46
+ $searchQuery: String
47
+ ) {
48
+ app(id: $id) {
49
+ __typename
50
+ ... on App {
51
+ id
52
+ items(
53
+ input: {
54
+ access: REQUESTABLE
55
+ searchQuery: $searchQuery
56
+ includeOnlyRequestable: true
57
+ }
58
+ ) {
59
+ items {
60
+ key
61
+ resource {
62
+ id
63
+ name
64
+ }
65
+ group {
66
+ id
67
+ name
68
+ }
69
+ }
70
+ cursor
71
+ }
72
+ }
73
+ }
74
+ }
75
+ `);
76
+ async function queryRequestableApps(cmd, client, input) {
77
+ var _a, _b;
78
+ try {
79
+ const resp = await client.query({
80
+ query: GET_REQUESTABLE_APPS_QUERY,
81
+ variables: {
82
+ searchQuery: input || "",
83
+ },
84
+ fetchPolicy: "network-only", // to avoid caching
85
+ });
86
+ 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) => {
87
+ let type = undefined;
88
+ if (edge.node.__typename === "Resource") {
89
+ type = edge.node.resourceType;
90
+ }
91
+ if (edge.node.__typename === "Connection") {
92
+ type = edge.node.connectionType;
93
+ }
94
+ const label = `${edge.node.displayName} (${type})`;
95
+ return {
96
+ name: label,
97
+ value: {
98
+ id: edge.node.id,
99
+ name: label,
100
+ },
101
+ };
102
+ });
103
+ }
104
+ catch (error) {
105
+ if (error instanceof Error || typeof error === "string") {
106
+ cmd.error(error);
107
+ }
108
+ }
109
+ }
110
+ async function queryRequestableAssets(cmd, client, appId, input) {
111
+ var _a, _b, _c, _d;
112
+ try {
113
+ const resp = await client.query({
114
+ query: GET_ASSETS_QUERY,
115
+ variables: {
116
+ id: appId || "",
117
+ searchQuery: input || "",
118
+ },
119
+ fetchPolicy: "network-only", // to avoid caching
120
+ });
121
+ // no fall through doesn't consider process.exit();
122
+ let x;
123
+ switch (resp.data.app.__typename) {
124
+ case "App":
125
+ 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) => {
126
+ var _a, _b, _c, _d, _e, _f;
127
+ const name = ((_a = item.resource) === null || _a === void 0 ? void 0 : _a.name) || ((_b = item.group) === null || _b === void 0 ? void 0 : _b.name);
128
+ const id = ((_c = item.resource) === null || _c === void 0 ? void 0 : _c.id) || ((_d = item.group) === null || _d === void 0 ? void 0 : _d.id);
129
+ const type = ((_e = item.resource) === null || _e === void 0 ? void 0 : _e.__typename) || ((_f = item.group) === null || _f === void 0 ? void 0 : _f.__typename);
130
+ const label = `${name} (${type})`;
131
+ return {
132
+ name: label,
133
+ value: {
134
+ name: label,
135
+ id: id,
136
+ },
137
+ };
138
+ });
139
+ case "AppNotFoundError":
140
+ x = cmd.error("App not found");
141
+ break;
142
+ default:
143
+ cmd.error("Unknown error occurred.");
144
+ }
145
+ }
146
+ catch (error) {
147
+ if (error instanceof Error || typeof error === "string") {
148
+ cmd.error(error);
149
+ }
150
+ }
151
+ }
152
+ // Helper functions
153
+ async function selectRequestableItems(cmd, client, requestMap) {
154
+ const { App } = await inquirer.prompt([
155
+ {
156
+ name: "App",
157
+ message: "Select an app:",
158
+ type: "autocomplete",
159
+ source: async (answers, input) => {
160
+ var _a;
161
+ return (_a = (await queryRequestableApps(cmd, client, input))) !== null && _a !== void 0 ? _a : [];
162
+ },
163
+ pageSize: 15,
164
+ },
165
+ ]);
166
+ // Set the app in the requestMap and call choose assets step
167
+ if (!requestMap.has(App.id)) {
168
+ requestMap.set(App.id, {
169
+ appName: App.name,
170
+ assets: new Map(),
171
+ });
172
+ }
173
+ await chooseAssets(cmd, client, App.id, requestMap);
174
+ }
175
+ async function chooseAssets(cmd, client, appId, requestMap) {
176
+ var _a;
177
+ const { Assets } = await inquirer.prompt({
178
+ name: "Assets",
179
+ type: "checkbox",
180
+ pageSize: 15,
181
+ message: "Select one or more items:",
182
+ choices: (_a = (await queryRequestableAssets(cmd, client, appId, undefined))) !== null && _a !== void 0 ? _a : [],
183
+ validate: (answer) => {
184
+ if (answer.length < 1) {
185
+ return "You must select at least one item.";
186
+ }
187
+ return true;
188
+ },
189
+ });
190
+ const entry = requestMap.get(appId);
191
+ for (const asset of Assets) {
192
+ if (entry === undefined) {
193
+ throw new Error(`App ${appId} not found in requestMap`);
194
+ }
195
+ if (!entry.assets.has(asset.id)) {
196
+ entry.assets.set(asset.id, {
197
+ assetName: asset.name,
198
+ roles: new Map(),
199
+ });
200
+ }
201
+ await chooseRoles(appId, asset.id, requestMap);
202
+ }
203
+ }
204
+ async function chooseRoles(appId, assetId, requestMap) {
205
+ var _a;
206
+ const { roles } = await inquirer.prompt({
207
+ name: "roles",
208
+ type: "checkbox",
209
+ message: `Select one or more roles for ${assetId}:`,
210
+ choices: ["push", "pull", "triage", "admin"],
211
+ });
212
+ const entry = requestMap.get(appId);
213
+ const assetEntry = entry === null || entry === void 0 ? void 0 : entry.assets.get(assetId);
214
+ if (entry === undefined || assetEntry === undefined) {
215
+ throw new Error(`App ${appId} or Asset ${assetId} not found in requestMap`);
216
+ }
217
+ for (const role of roles) {
218
+ (_a = assetEntry.roles) === null || _a === void 0 ? void 0 : _a.set(role, {
219
+ roleName: role,
220
+ });
221
+ }
222
+ }
223
+ async function doneSelectingAssets() {
224
+ const submitMessage = "✅ Yes, proceed with request";
225
+ const addMoreMessage = "❌ No, add more items";
226
+ const { submitOrAdd } = await inquirer.prompt([
227
+ {
228
+ name: "submitOrAdd",
229
+ message: "Is this all you want to request?",
230
+ type: "list",
231
+ choices: [submitMessage, addMoreMessage],
232
+ },
233
+ ]);
234
+ return submitOrAdd === submitMessage;
235
+ }
236
+ async function promptForReason() {
237
+ return await inquirer.prompt([
238
+ {
239
+ name: "reason",
240
+ message: "I need access to this because...",
241
+ type: "input",
242
+ },
243
+ ]);
244
+ }
245
+ async function promptForExpiration() {
246
+ return await inquirer.prompt([
247
+ {
248
+ name: "expiration",
249
+ message: "When should access expire?",
250
+ type: "list",
251
+ choices: ["1 hour", "1 day", "7 days", "30 days", "1 year", "Indefinite"],
252
+ },
253
+ ]);
254
+ }
255
+ async function submitFinalRequest(cmd) {
256
+ const submitMessage = "✅ Yes, submit request";
257
+ const cancelMessage = "❌ No, cancel request";
258
+ const { submit } = await inquirer.prompt([
259
+ {
260
+ name: "submit",
261
+ message: "Submit request?",
262
+ type: "list",
263
+ choices: [submitMessage, cancelMessage],
264
+ },
265
+ ]);
266
+ if (submit === submitMessage) {
267
+ const requestLink = "https://dev.opal.dev/requests/sent/05ca5d5f-ea60-4cdb-84e1-7e3c575b2b72"; //TODO: Replace with actual request link
268
+ cmd.log("\n🎉 Your Access Request has been submitted! Request ID: 1234");
269
+ cmd.log(`🔍 View request status here: ${requestLink}`);
270
+ }
271
+ else {
272
+ cmd.log("🚫 Access Request has been cancelled.");
273
+ }
274
+ }
@@ -1,5 +1,5 @@
1
- import { Command } from '@oclif/core';
2
- import { ResourceAccessLevel, ResourceAccessLevelInput } from '../types';
1
+ import type { Command } from "@oclif/core";
2
+ import type { ResourceAccessLevel, ResourceAccessLevelInput } from "../types";
3
3
  export type ResourceInfo = {
4
4
  id: string;
5
5
  name: string;
@@ -5,16 +5,15 @@ const inquirer = require("inquirer");
5
5
  const handler_1 = require("../handler");
6
6
  const apollo_1 = require("./apollo");
7
7
  exports.DEFAULT_ACCESS_LEVEL = {
8
- accessLevelName: '',
9
- accessLevelRemoteId: '',
8
+ accessLevelName: "",
9
+ accessLevelRemoteId: "",
10
10
  };
11
11
  // Returns a filtered array of items that match the input
12
12
  const filterChoices = (input, choices) => {
13
- input = input || '';
14
- if (input === '') {
13
+ if (!input) {
15
14
  return choices;
16
15
  }
17
- return choices.filter(choice => choice.name.toLowerCase().includes(input.toLowerCase()));
16
+ return choices.filter((choice) => choice.name.toLowerCase().includes(input.toLowerCase()));
18
17
  };
19
18
  exports.filterChoices = filterChoices;
20
19
  const ListResourcesDocumentTemplate = `
@@ -37,8 +36,8 @@ query ListResources {
37
36
  }
38
37
  }`;
39
38
  const promptUserForResource = async (command, resourceType, message) => {
40
- const listResourcesDocument = ListResourcesDocumentTemplate.replace('RESOURCE_TYPE', resourceType);
41
- const { resp, error } = await (0, handler_1.runQuery)({
39
+ const listResourcesDocument = ListResourcesDocumentTemplate.replace("RESOURCE_TYPE", resourceType);
40
+ const { resp, error } = await (0, handler_1.runQueryDeprecated)({
42
41
  command: command,
43
42
  query: listResourcesDocument,
44
43
  variables: {},
@@ -60,19 +59,22 @@ const promptUserForResource = async (command, resourceType, message) => {
60
59
  };
61
60
  });
62
61
  if (resourceInfos.length === 0) {
63
- return (0, apollo_1.handleError)(command, 'You don\'t have access to any resources of this type. Please go to Opal to request access.');
62
+ return (0, apollo_1.handleError)(command, "You don't have access to any resources of this type. Please go to Opal to request access.");
64
63
  }
65
64
  const resourceInfoByName = {};
66
- resourceInfos.forEach(resourceInfo => {
65
+ // biome-ignore lint/complexity/noForEach: fix it when you get the chance
66
+ resourceInfos.forEach((resourceInfo) => {
67
67
  resourceInfoByName[resourceInfo.name] = resourceInfo;
68
68
  });
69
- inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt'));
70
- const selectedResourceInfo = await inquirer.prompt([{
71
- name: 'resource',
69
+ inquirer.registerPrompt("autocomplete", require("inquirer-autocomplete-prompt"));
70
+ const selectedResourceInfo = await inquirer.prompt([
71
+ {
72
+ name: "resource",
72
73
  message: message,
73
- type: 'autocomplete',
74
+ type: "autocomplete",
74
75
  source: (answers, input) => (0, exports.filterChoices)(input, resourceInfos),
75
- }]);
76
+ },
77
+ ]);
76
78
  return resourceInfoByName[selectedResourceInfo.resource];
77
79
  };
78
80
  exports.promptUserForResource = promptUserForResource;
@@ -90,7 +92,7 @@ query ListAccessLevelsForResource($resourceId: ResourceId!) {
90
92
  }`;
91
93
  const promptUserForAccessLevels = async (command, resourceId, instanceType, accessLevelRemoteId) => {
92
94
  var _a, _b, _c;
93
- const { resp, error } = await (0, handler_1.runQuery)({
95
+ const { resp, error } = await (0, handler_1.runQueryDeprecated)({
94
96
  command: command,
95
97
  query: ListAccessLevelsForResource,
96
98
  variables: { resourceId },
@@ -103,11 +105,12 @@ const promptUserForAccessLevels = async (command, resourceId, instanceType, acce
103
105
  name: resp.accessLevelName,
104
106
  }));
105
107
  if (!accessLevelInfos) {
106
- return (0, apollo_1.handleError)(command, 'This resource requires an access level, but none have been set up in Opal. Please contact your Opal admin.');
108
+ return (0, apollo_1.handleError)(command, "This resource requires an access level, but none have been set up in Opal. Please contact your Opal admin.");
107
109
  }
108
110
  const accessLevelInfoByName = {};
109
111
  const accessLevelInfoByRemoteId = {};
110
- accessLevelInfos.forEach(accessLevelInfo => {
112
+ // biome-ignore lint/complexity/noForEach: please fix this
113
+ accessLevelInfos.forEach((accessLevelInfo) => {
111
114
  accessLevelInfoByName[accessLevelInfo.name] = accessLevelInfo;
112
115
  accessLevelInfoByRemoteId[accessLevelInfo.id] = accessLevelInfo;
113
116
  });
@@ -117,14 +120,17 @@ const promptUserForAccessLevels = async (command, resourceId, instanceType, acce
117
120
  }
118
121
  // Prompt user to pick access levels available to them
119
122
  if (!selectedAccessLevel) {
120
- inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt'));
121
- const selectedAccessLevelInfo = await inquirer.prompt([{
122
- name: 'accessLevel',
123
+ inquirer.registerPrompt("autocomplete", require("inquirer-autocomplete-prompt"));
124
+ const selectedAccessLevelInfo = await inquirer.prompt([
125
+ {
126
+ name: "accessLevel",
123
127
  message: `Select an access level to the ${instanceType}`,
124
- type: 'autocomplete',
128
+ type: "autocomplete",
125
129
  source: (answers, input) => (0, exports.filterChoices)(input, accessLevelInfos),
126
- }]);
127
- selectedAccessLevel = accessLevelInfoByName[selectedAccessLevelInfo.accessLevel];
130
+ },
131
+ ]);
132
+ selectedAccessLevel =
133
+ accessLevelInfoByName[selectedAccessLevelInfo.accessLevel];
128
134
  }
129
135
  return {
130
136
  accessLevelName: selectedAccessLevel.name,
@@ -1,4 +1,4 @@
1
- import { Command } from '@oclif/core';
2
- import { ResourceAccessLevelInput } from '../types';
1
+ import type { Command } from "@oclif/core";
2
+ import type { ResourceAccessLevelInput } from "../types";
3
3
  export declare const getOrCreateSession: (command: Command, resourceId: string, accessLevel: ResourceAccessLevelInput, sessionId: string | undefined, metadataFragment: string, wantNewSession?: boolean) => Promise<any>;
4
4
  export declare const getSessionExpirationMessage: (session: any) => string;
@@ -1,11 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getSessionExpirationMessage = exports.getOrCreateSession = void 0;
4
+ const moment = require("moment");
4
5
  const open = require("open");
5
- const config_1 = require("../lib/config");
6
6
  const handler_1 = require("../handler");
7
- const moment = require("moment");
8
7
  const apollo_1 = require("../lib/apollo");
8
+ const config_1 = require("../lib/config");
9
9
  const util_1 = require("./util");
10
10
  const CreateSessionDocument = `
11
11
  mutation CreateSession($id: ResourceId!, $accessLevel: ResourceAccessLevelInput!, $sessionId: SessionId) {
@@ -59,9 +59,9 @@ query ListSessions($id: ResourceId!) {
59
59
  }
60
60
  `;
61
61
  const getSession = async (command, resourceId, accessLevelRemoteId, sessionId, metadataFragment, minCreatedAt) => {
62
- const { resp, error } = await (0, handler_1.runQuery)({
62
+ const { resp, error } = await (0, handler_1.runQueryDeprecated)({
63
63
  command: command,
64
- query: ListSessionsDocument.replace('METADATA_FRAGMENT', metadataFragment),
64
+ query: ListSessionsDocument.replace("METADATA_FRAGMENT", metadataFragment),
65
65
  variables: {
66
66
  id: resourceId,
67
67
  },
@@ -70,8 +70,9 @@ const getSession = async (command, resourceId, accessLevelRemoteId, sessionId, m
70
70
  return (0, apollo_1.handleError)(command, error);
71
71
  }
72
72
  switch (resp === null || resp === void 0 ? void 0 : resp.data.sessions.__typename) {
73
- case 'SessionsResult': {
73
+ case "SessionsResult": {
74
74
  const sessions = resp.data.sessions.sessions;
75
+ // biome-ignore lint/suspicious/noImplicitAnyLet: please fix how we do queries in this cli
75
76
  let selectedSession;
76
77
  for (const session of sessions) {
77
78
  if (sessionId && session.id !== sessionId) {
@@ -84,7 +85,8 @@ const getSession = async (command, resourceId, accessLevelRemoteId, sessionId, m
84
85
  // This lets us wait until we get a session that's newly created
85
86
  continue;
86
87
  }
87
- if (!selectedSession || moment(session.endTime).diff(selectedSession.endTime) > 0) {
88
+ if (!selectedSession ||
89
+ moment(session.endTime).diff(selectedSession.endTime) > 0) {
88
90
  // Select the session with the latest end time
89
91
  selectedSession = session;
90
92
  }
@@ -105,13 +107,12 @@ const openBrowserAndPollForSession = async (command, message, resourceId, access
105
107
  const configData = (0, config_1.getOrCreateConfigData)(command.config.configDir);
106
108
  const url = configData[config_1.urlKey];
107
109
  setTimeout(() => {
108
- open(url + `/resources/${resourceId}?showModal=true&refresh=true`);
110
+ open(`${url}/resources/${resourceId}?showModal=true&refresh=true`);
109
111
  }, 2000); // Wait before opening the browser to give the user time to read the message
112
+ // biome-ignore lint/suspicious/noImplicitAnyLet: please fix typing for queries
110
113
  let session;
111
114
  while (!session) {
112
- // eslint-disable-next-line no-await-in-loop
113
115
  await (0, util_1.sleep)(2000);
114
- // eslint-disable-next-line no-await-in-loop
115
116
  session = await getSession(command, resourceId, accessLevelRemoteId, sessionId, metadataFragment, minCreatedAt);
116
117
  }
117
118
  return session;
@@ -119,7 +120,7 @@ const openBrowserAndPollForSession = async (command, message, resourceId, access
119
120
  const createSession = async (command, resourceId, accessLevel, sessionId, metadataFragment, wantNewSession) => {
120
121
  const { resp, error } = await (0, handler_1.runMutation)({
121
122
  command: command,
122
- query: CreateSessionDocument.replace('METADATA_FRAGMENT', metadataFragment),
123
+ query: CreateSessionDocument.replace("METADATA_FRAGMENT", metadataFragment),
123
124
  variables: {
124
125
  id: resourceId,
125
126
  accessLevel: accessLevel,
@@ -130,14 +131,14 @@ const createSession = async (command, resourceId, accessLevel, sessionId, metada
130
131
  return (0, apollo_1.handleError)(command, error);
131
132
  }
132
133
  switch (resp === null || resp === void 0 ? void 0 : resp.data.createSession.__typename) {
133
- case 'CreateSessionResult': {
134
+ case "CreateSessionResult": {
134
135
  return resp.data.createSession.session;
135
136
  }
136
- case 'MfaInvalidError': {
137
- return openBrowserAndPollForSession(command, '❗ MFA validation needed. Please connect via browser. Opening browser and awaiting validation...', resourceId, accessLevel.accessLevelRemoteId, sessionId, metadataFragment, wantNewSession);
137
+ case "MfaInvalidError": {
138
+ return openBrowserAndPollForSession(command, "❗ MFA validation needed. Please connect via browser. Opening browser and awaiting validation...", resourceId, accessLevel.accessLevelRemoteId, sessionId, metadataFragment, wantNewSession);
138
139
  }
139
- case 'OidcIDTokenNotFoundError': {
140
- return openBrowserAndPollForSession(command, '❗ OIDC authentication needed. Please connect via browser. Opening browser and awaiting authentication...', resourceId, accessLevel.accessLevelRemoteId, sessionId, metadataFragment, wantNewSession);
140
+ case "OidcIDTokenNotFoundError": {
141
+ return openBrowserAndPollForSession(command, "❗ OIDC authentication needed. Please connect via browser. Opening browser and awaiting authentication...", resourceId, accessLevel.accessLevelRemoteId, sessionId, metadataFragment, wantNewSession);
141
142
  }
142
143
  default:
143
144
  return (0, apollo_1.handleError)(command, error, resp);
@@ -152,14 +153,14 @@ const getOrCreateSession = async (command, resourceId, accessLevel, sessionId, m
152
153
  }
153
154
  }
154
155
  if (sessionId) {
155
- return (0, apollo_1.handleError)(command, 'Session not found for given id: ' + sessionId);
156
+ return (0, apollo_1.handleError)(command, `Session not found for given id: ${sessionId}`);
156
157
  }
157
158
  // Create new session
158
159
  return createSession(command, resourceId, accessLevel, sessionId, metadataFragment, wantNewSession);
159
160
  };
160
161
  exports.getOrCreateSession = getOrCreateSession;
161
162
  const getSessionExpirationMessage = (session) => {
162
- const diff = moment(session.endTime).diff(moment(), 'minutes');
163
+ const diff = moment(session.endTime).diff(moment(), "minutes");
163
164
  const hours = Math.floor(diff / 60);
164
165
  const minutes = diff % 60;
165
166
  return `${hours}h ${minutes}m`;