opal-security 3.2.3 → 4.0.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 (150) hide show
  1. package/README.md +46 -61
  2. package/bin/dev +5 -5
  3. package/bin/run +2 -4
  4. package/build/commands/aws/identity.js +16 -0
  5. package/build/commands/clear-auth-config.d.ts +6 -0
  6. package/build/commands/clear-auth-config.js +22 -0
  7. package/{lib → build}/commands/groups/get.js +14 -16
  8. package/{lib → build}/commands/iam-roles/start.js +28 -30
  9. package/build/commands/kube-roles/start.js +71 -0
  10. package/{lib → build}/commands/login.d.ts +1 -0
  11. package/build/commands/login.js +379 -0
  12. package/build/commands/logout.js +22 -0
  13. package/{lib → build}/commands/postgres-instances/start.js +25 -27
  14. package/{lib → build}/commands/request/create.js +34 -36
  15. package/{lib → build}/commands/request/get.js +22 -24
  16. package/{lib → build}/commands/request/list.js +17 -19
  17. package/{lib → build}/commands/resources/get.js +15 -18
  18. package/build/commands/set-auth-config.d.ts +11 -0
  19. package/build/commands/set-auth-config.js +59 -0
  20. package/build/commands/set-custom-header.js +35 -0
  21. package/{lib → build}/commands/set-token.js +15 -17
  22. package/{lib → build}/commands/set-url.js +26 -28
  23. package/{lib → build}/commands/ssh/copyFrom.js +22 -24
  24. package/{lib → build}/commands/ssh/copyTo.js +22 -24
  25. package/{lib → build}/commands/ssh/start.js +30 -33
  26. package/build/commands/whoami.js +27 -0
  27. package/{lib → build}/graphql/fragment-masking.d.ts +1 -1
  28. package/{lib → build}/graphql/fragment-masking.js +3 -8
  29. package/{lib → build}/graphql/gql.d.ts +1 -1
  30. package/{lib → build}/graphql/gql.js +2 -5
  31. package/{lib → build}/graphql/graphql.js +256 -261
  32. package/build/graphql/index.d.ts +2 -0
  33. package/build/graphql/index.js +2 -0
  34. package/{lib → build}/handler.d.ts +1 -1
  35. package/build/handler.js +36 -0
  36. package/build/index.js +1 -0
  37. package/{lib → build}/labels.d.ts +1 -1
  38. package/build/labels.js +37 -0
  39. package/{lib → build}/lib/apollo.d.ts +2 -2
  40. package/{lib → build}/lib/apollo.js +62 -69
  41. package/build/lib/auth-success-template.d.ts +3 -0
  42. package/build/lib/auth-success-template.js +149 -0
  43. package/{lib → build}/lib/aws.js +2 -7
  44. package/{lib → build}/lib/cmd.d.ts +4 -4
  45. package/{lib → build}/lib/cmd.js +16 -20
  46. package/build/lib/config.js +46 -0
  47. package/{lib → build}/lib/credentials/index.d.ts +3 -2
  48. package/build/lib/credentials/index.js +85 -0
  49. package/{lib → build}/lib/credentials/keychain.js +4 -10
  50. package/{lib → build}/lib/credentials/localEncryption.js +12 -17
  51. package/{lib → build}/lib/flags.js +7 -10
  52. package/build/lib/local-auth-server.d.ts +5 -0
  53. package/build/lib/local-auth-server.js +69 -0
  54. package/build/lib/request/api/index.d.ts +6 -0
  55. package/build/lib/request/api/index.js +8 -0
  56. package/{lib → build}/lib/request/api/mutations/create-request.d.ts +2 -2
  57. package/{lib → build}/lib/request/api/mutations/create-request.js +3 -6
  58. package/{lib → build}/lib/request/api/queries/apps.d.ts +1 -1
  59. package/{lib → build}/lib/request/api/queries/apps.js +3 -6
  60. package/{lib → build}/lib/request/api/queries/assets.d.ts +2 -2
  61. package/{lib → build}/lib/request/api/queries/assets.js +7 -11
  62. package/{lib → build}/lib/request/api/queries/request-defaults.d.ts +2 -2
  63. package/{lib → build}/lib/request/api/queries/request-defaults.js +3 -6
  64. package/{lib → build}/lib/request/api/queries/requests.d.ts +3 -3
  65. package/{lib → build}/lib/request/api/queries/requests.js +10 -16
  66. package/{lib → build}/lib/request/api/queries/roles.d.ts +1 -1
  67. package/{lib → build}/lib/request/api/queries/roles.js +14 -18
  68. package/{lib → build}/lib/request/displays.d.ts +2 -2
  69. package/{lib → build}/lib/request/displays.js +27 -37
  70. package/{lib → build}/lib/request/prompts/apps-prompt.d.ts +1 -1
  71. package/build/lib/request/prompts/apps-prompt.js +33 -0
  72. package/{lib → build}/lib/request/prompts/asset-prompt.d.ts +1 -1
  73. package/build/lib/request/prompts/asset-prompt.js +61 -0
  74. package/{lib → build}/lib/request/prompts/duration-prompt.d.ts +1 -1
  75. package/{lib → build}/lib/request/prompts/duration-prompt.js +6 -10
  76. package/build/lib/request/prompts/index.d.ts +7 -0
  77. package/build/lib/request/prompts/index.js +8 -0
  78. package/{lib → build}/lib/request/prompts/reason-prompt.d.ts +1 -1
  79. package/{lib → build}/lib/request/prompts/reason-prompt.js +3 -6
  80. package/{lib → build}/lib/request/prompts/role-prompt.d.ts +1 -1
  81. package/build/lib/request/prompts/role-prompt.js +33 -0
  82. package/{lib → build}/lib/request/prompts/validate-prompt.d.ts +1 -1
  83. package/{lib → build}/lib/request/prompts/validate-prompt.js +9 -13
  84. package/{lib → build}/lib/request/request-utils.d.ts +2 -2
  85. package/{lib → build}/lib/request/request-utils.js +50 -62
  86. package/{lib → build}/lib/request/types.d.ts +1 -1
  87. package/build/lib/request/types.js +12 -0
  88. package/{lib → build}/lib/resources.d.ts +1 -1
  89. package/{lib → build}/lib/resources.js +18 -23
  90. package/{lib → build}/lib/sessions.d.ts +1 -1
  91. package/{lib → build}/lib/sessions.js +57 -32
  92. package/{lib → build}/lib/ssh.d.ts +1 -1
  93. package/{lib → build}/lib/ssh.js +6 -11
  94. package/{lib → build}/lib/util.js +7 -14
  95. package/{lib → build}/types.js +98 -101
  96. package/oclif.manifest.json +77 -98
  97. package/package.json +24 -14
  98. package/lib/commands/aws/identity.js +0 -18
  99. package/lib/commands/clear-auth-provider.d.ts +0 -9
  100. package/lib/commands/clear-auth-provider.js +0 -28
  101. package/lib/commands/curl-example.d.ts +0 -8
  102. package/lib/commands/curl-example.js +0 -34
  103. package/lib/commands/kube-roles/start.js +0 -73
  104. package/lib/commands/login.js +0 -286
  105. package/lib/commands/logout.js +0 -23
  106. package/lib/commands/set-auth-provider.d.ts +0 -11
  107. package/lib/commands/set-auth-provider.js +0 -44
  108. package/lib/commands/set-custom-header.js +0 -37
  109. package/lib/commands/whoami.js +0 -34
  110. package/lib/graphql/index.d.ts +0 -2
  111. package/lib/graphql/index.js +0 -5
  112. package/lib/handler.js +0 -41
  113. package/lib/index.js +0 -5
  114. package/lib/labels.js +0 -40
  115. package/lib/lib/config.js +0 -54
  116. package/lib/lib/credentials/index.js +0 -67
  117. package/lib/lib/request/api/index.d.ts +0 -6
  118. package/lib/lib/request/api/index.js +0 -20
  119. package/lib/lib/request/prompts/apps-prompt.js +0 -35
  120. package/lib/lib/request/prompts/asset-prompt.js +0 -81
  121. package/lib/lib/request/prompts/index.d.ts +0 -8
  122. package/lib/lib/request/prompts/index.js +0 -20
  123. package/lib/lib/request/prompts/role-prompt.js +0 -44
  124. package/lib/lib/request/types.js +0 -15
  125. /package/{lib → build}/commands/aws/identity.d.ts +0 -0
  126. /package/{lib → build}/commands/groups/get.d.ts +0 -0
  127. /package/{lib → build}/commands/iam-roles/start.d.ts +0 -0
  128. /package/{lib → build}/commands/kube-roles/start.d.ts +0 -0
  129. /package/{lib → build}/commands/logout.d.ts +0 -0
  130. /package/{lib → build}/commands/postgres-instances/start.d.ts +0 -0
  131. /package/{lib → build}/commands/request/create.d.ts +0 -0
  132. /package/{lib → build}/commands/request/get.d.ts +0 -0
  133. /package/{lib → build}/commands/request/list.d.ts +0 -0
  134. /package/{lib → build}/commands/resources/get.d.ts +0 -0
  135. /package/{lib → build}/commands/set-custom-header.d.ts +0 -0
  136. /package/{lib → build}/commands/set-token.d.ts +0 -0
  137. /package/{lib → build}/commands/set-url.d.ts +0 -0
  138. /package/{lib → build}/commands/ssh/copyFrom.d.ts +0 -0
  139. /package/{lib → build}/commands/ssh/copyTo.d.ts +0 -0
  140. /package/{lib → build}/commands/ssh/start.d.ts +0 -0
  141. /package/{lib → build}/commands/whoami.d.ts +0 -0
  142. /package/{lib → build}/graphql/graphql.d.ts +0 -0
  143. /package/{lib → build}/index.d.ts +0 -0
  144. /package/{lib → build}/lib/aws.d.ts +0 -0
  145. /package/{lib → build}/lib/config.d.ts +0 -0
  146. /package/{lib → build}/lib/credentials/keychain.d.ts +0 -0
  147. /package/{lib → build}/lib/credentials/localEncryption.d.ts +0 -0
  148. /package/{lib → build}/lib/flags.d.ts +0 -0
  149. /package/{lib → build}/lib/util.d.ts +0 -0
  150. /package/{lib → build}/types.d.ts +0 -0
@@ -0,0 +1,46 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ export const urlKey = "url";
4
+ export const defaultUrl = "https://app.opal.dev";
5
+ export const allowSelfSignedCertsKey = "allowSelfSignedCerts";
6
+ export const defaultAllowSelfSignedCerts = false;
7
+ export const customHttpHeaderKey = "customHttpHeader";
8
+ export const getOrCreateConfigData = (configDir) => {
9
+ if (!fs.existsSync(configDir)) {
10
+ fs.mkdirSync(configDir, { recursive: true });
11
+ }
12
+ const configFilePath = path.join(configDir, "config.json");
13
+ if (!fs.existsSync(configFilePath)) {
14
+ fs.writeFileSync(configFilePath, JSON.stringify({
15
+ [urlKey]: defaultUrl,
16
+ [allowSelfSignedCertsKey]: defaultAllowSelfSignedCerts,
17
+ }));
18
+ }
19
+ let configData = {};
20
+ try {
21
+ const configDataRaw = fs.readFileSync(configFilePath);
22
+ configData = JSON.parse(configDataRaw === null || configDataRaw === void 0 ? void 0 : configDataRaw.toString());
23
+ }
24
+ catch (error) {
25
+ if (error &&
26
+ typeof error === "object" &&
27
+ "code" in error &&
28
+ error.code !== "ENOENT") {
29
+ throw error;
30
+ }
31
+ }
32
+ return configData;
33
+ };
34
+ export const writeConfigData = (configDir, newConfigData) => {
35
+ fs.writeFileSync(path.join(configDir, "config.json"), JSON.stringify(newConfigData), {
36
+ mode: 0o0600,
37
+ });
38
+ };
39
+ export const isProduction = (configDir) => {
40
+ const configData = getOrCreateConfigData(configDir);
41
+ // Custom URLs are considered production since it includes on-prem
42
+ return (configData[urlKey] !== "https://dev.opal.dev" &&
43
+ configData[urlKey] !== "https://demo.opal.dev" &&
44
+ configData[urlKey] !== "https://staging.opal.dev" &&
45
+ !configData[urlKey].match(/https?:\/\/localhost/));
46
+ };
@@ -2,7 +2,7 @@ import type { Command } from "@oclif/core";
2
2
  interface OpalCredentials {
3
3
  email?: string;
4
4
  organizationID?: string;
5
- clientIDCandidate?: string;
5
+ clientID?: string;
6
6
  secret?: string;
7
7
  secretType?: SecretType;
8
8
  organizationName?: string;
@@ -11,7 +11,8 @@ export declare enum SecretType {
11
11
  Cookie = "COOKIE",
12
12
  ApiToken = "API_TOKEN"
13
13
  }
14
- export declare const setOpalCredentials: (command: Command, email: string | undefined, organizationID: string, clientIDCandidate: string | undefined | null, secret: string, secretType: SecretType, organizationName?: string) => Promise<void>;
14
+ export declare const setOpalCredentials: (command: Command, email: string | undefined, organizationID: string | undefined, clientID: string | undefined, secret: string, secretType?: SecretType, organizationName?: string) => Promise<void>;
15
15
  export declare const getOpalCredentials: (command: Command, includeAuthSecret?: boolean) => Promise<OpalCredentials>;
16
16
  export declare const removeOpalCredentials: (command: Command) => Promise<void>;
17
+ export declare const removeAuthSecret: (command: Command) => Promise<void>;
17
18
  export {};
@@ -0,0 +1,85 @@
1
+ import { getOrCreateConfigData, writeConfigData } from "../config.js";
2
+ import { deleteSecretFromKeychain, getSecretFromKeychain, setSecretInKeychain, } from "./keychain.js";
3
+ import { getSecretFromConfig, setSecretInConfig } from "./localEncryption.js";
4
+ export var SecretType;
5
+ (function (SecretType) {
6
+ SecretType["Cookie"] = "COOKIE";
7
+ SecretType["ApiToken"] = "API_TOKEN";
8
+ })(SecretType || (SecretType = {}));
9
+ export const setOpalCredentials = async (command, email, organizationID, clientID, secret, secretType, organizationName) => {
10
+ const givenEmail = email || "email-unset";
11
+ const configData = getOrCreateConfigData(command.config.configDir);
12
+ configData.creds = {
13
+ email,
14
+ organizationID,
15
+ organizationName,
16
+ secretType,
17
+ };
18
+ writeConfigData(command.config.configDir, configData);
19
+ await writeSecret(command, configData, givenEmail, { clientID, secret });
20
+ };
21
+ export const getOpalCredentials = async (command, includeAuthSecret = true) => {
22
+ var _a, _b;
23
+ const creds = (_b = (_a = getOrCreateConfigData(command.config.configDir)) === null || _a === void 0 ? void 0 : _a.creds) !== null && _b !== void 0 ? _b : {};
24
+ if (!includeAuthSecret) {
25
+ return creds;
26
+ }
27
+ let secretStr = null;
28
+ if (process.platform === "darwin") {
29
+ secretStr = await getSecretFromKeychain((creds === null || creds === void 0 ? void 0 : creds.email) || "email-unset");
30
+ }
31
+ else {
32
+ secretStr = await getSecretFromConfig(creds);
33
+ }
34
+ if (secretStr) {
35
+ try {
36
+ const parsed = JSON.parse(secretStr);
37
+ creds.secret = parsed.secret;
38
+ creds.clientID = parsed.clientID;
39
+ }
40
+ catch (error) {
41
+ // Fallback for old format where only the secret was stored as a plain string
42
+ creds.secret = secretStr;
43
+ }
44
+ // This is a fallback for users with stored credentials from before we converted to session auth with the CLITokenExchange mutation
45
+ // It will allow them to continue authenticating with an access token in an Authorization header, which will work until we remove support for that
46
+ if (!creds.secretType) {
47
+ creds.secretType = SecretType.ApiToken;
48
+ }
49
+ }
50
+ return creds;
51
+ };
52
+ // This removes *everything* in the creds object, and wipes out anything stored in the keychain
53
+ export const removeOpalCredentials = async (command) => {
54
+ var _a;
55
+ const configData = getOrCreateConfigData(command.config.configDir);
56
+ const email = ((_a = configData === null || configData === void 0 ? void 0 : configData.creds) === null || _a === void 0 ? void 0 : _a.email) || "email-unset";
57
+ // On linux, the access token is stored encrypted in configData.creds, so this effectively removes it
58
+ configData.creds = {};
59
+ writeConfigData(command.config.configDir, configData);
60
+ // but on OSX, we need an extra step to delete the token from the keychain
61
+ if (process.platform === "darwin") {
62
+ await deleteSecretFromKeychain(email);
63
+ }
64
+ };
65
+ // This just removes the auth secret, if it exists
66
+ export const removeAuthSecret = async (command) => {
67
+ const configData = getOrCreateConfigData(command.config.configDir);
68
+ const creds = await getOpalCredentials(command, true);
69
+ if (creds.email) {
70
+ const secretCreds = {};
71
+ if (creds.clientID) {
72
+ secretCreds.clientID = creds.clientID;
73
+ }
74
+ await writeSecret(command, configData, creds.email, secretCreds);
75
+ }
76
+ };
77
+ const writeSecret = async (command, configData, email, secretCreds) => {
78
+ const secretStr = JSON.stringify(secretCreds);
79
+ if (process.platform === "darwin") {
80
+ await setSecretInKeychain(email, secretStr);
81
+ }
82
+ else {
83
+ await setSecretInConfig(command, configData, secretStr);
84
+ }
85
+ };
@@ -1,10 +1,7 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.deleteSecretFromKeychain = exports.getSecretFromKeychain = exports.setSecretInKeychain = void 0;
4
- const keychain = require("keychain");
1
+ import keychain from "keychain";
5
2
  const OPAL_KEYCHAIN_SERVICE = "opal-cli";
6
3
  // On OSX, we can easily work with the system Keychain to store the access token.
7
- const setSecretInKeychain = async (email, secret) => {
4
+ export const setSecretInKeychain = async (email, secret) => {
8
5
  return new Promise((resolve, reject) => {
9
6
  keychain.setPassword({ account: email, service: OPAL_KEYCHAIN_SERVICE, password: secret }, (err) => {
10
7
  if (err) {
@@ -16,8 +13,7 @@ const setSecretInKeychain = async (email, secret) => {
16
13
  });
17
14
  });
18
15
  };
19
- exports.setSecretInKeychain = setSecretInKeychain;
20
- const getSecretFromKeychain = async (email) => {
16
+ export const getSecretFromKeychain = async (email) => {
21
17
  return new Promise((resolve, reject) => {
22
18
  keychain.getPassword({ account: email, service: OPAL_KEYCHAIN_SERVICE }, (err, password) => {
23
19
  if (err && (err === null || err === void 0 ? void 0 : err.type) !== "PasswordNotFoundError") {
@@ -29,8 +25,7 @@ const getSecretFromKeychain = async (email) => {
29
25
  });
30
26
  });
31
27
  };
32
- exports.getSecretFromKeychain = getSecretFromKeychain;
33
- const deleteSecretFromKeychain = async (email) => {
28
+ export const deleteSecretFromKeychain = async (email) => {
34
29
  return new Promise((resolve) => {
35
30
  keychain.deletePassword({ service: OPAL_KEYCHAIN_SERVICE, account: email }, () => {
36
31
  // we might get errors here if the password doesn't exist, which we want to swallow
@@ -38,4 +33,3 @@ const deleteSecretFromKeychain = async (email) => {
38
33
  });
39
34
  });
40
35
  };
41
- exports.deleteSecretFromKeychain = deleteSecretFromKeychain;
@@ -1,10 +1,7 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getSecretFromConfig = exports.setSecretInConfig = void 0;
4
- const node_crypto_1 = require("node:crypto");
5
- const argon2 = require("argon2");
6
- const inquirer = require("inquirer");
7
- const config_1 = require("../config");
1
+ import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
2
+ import * as argon2 from "argon2";
3
+ import inquirer from "inquirer";
4
+ import { writeConfigData } from "../config.js";
8
5
  const ENCRYPTION_ALGORITHM = "aes-256-gcm";
9
6
  /**
10
7
  * On linux, windows, and WSL, we can't easily work with the system keychain
@@ -28,18 +25,18 @@ const promptForPassword = async (msg) => {
28
25
  ]);
29
26
  return customKey;
30
27
  };
31
- const setSecretInConfig = async (command, configData, secret) => {
28
+ export const setSecretInConfig = async (command, configData, secret) => {
32
29
  if (!password) {
33
30
  password = await promptForPassword("Enter a password to encrypt your credentials: ");
34
31
  }
35
- const salt = (0, node_crypto_1.randomBytes)(24);
32
+ const salt = randomBytes(24);
36
33
  const key = await argon2.hash(password, {
37
34
  hashLength: 32,
38
35
  raw: true,
39
36
  salt: salt,
40
37
  });
41
- const iv = (0, node_crypto_1.randomBytes)(12);
42
- const cipher = (0, node_crypto_1.createCipheriv)(ENCRYPTION_ALGORITHM, key, iv);
38
+ const iv = randomBytes(12);
39
+ const cipher = createCipheriv(ENCRYPTION_ALGORITHM, key, iv);
43
40
  let secretEncrypted = cipher.update(secret, "utf8", "base64");
44
41
  secretEncrypted += cipher.final("base64");
45
42
  // In addition to storing the encrypted text, we need to store the argon2 salt, and AES authTag + IV so we can decrypt
@@ -49,10 +46,9 @@ const setSecretInConfig = async (command, configData, secret) => {
49
46
  salt: salt.toString("base64"),
50
47
  iv: iv.toString("base64"),
51
48
  };
52
- (0, config_1.writeConfigData)(command.config.configDir, configData);
49
+ writeConfigData(command.config.configDir, configData);
53
50
  };
54
- exports.setSecretInConfig = setSecretInConfig;
55
- const getSecretFromConfig = async (credsConfig) => {
51
+ export const getSecretFromConfig = async (credsConfig) => {
56
52
  let secret = "";
57
53
  if (credsConfig === null || credsConfig === void 0 ? void 0 : credsConfig.accessTokenDetails) {
58
54
  if (!password) {
@@ -66,12 +62,12 @@ const getSecretFromConfig = async (credsConfig) => {
66
62
  salt: salt,
67
63
  });
68
64
  try {
69
- const decipher = (0, node_crypto_1.createDecipheriv)(ENCRYPTION_ALGORITHM, key, iv);
65
+ const decipher = createDecipheriv(ENCRYPTION_ALGORITHM, key, iv);
70
66
  decipher.setAuthTag(Buffer.from(credsConfig.accessTokenDetails.authTag, "base64"));
71
67
  secret = decipher.update(credsConfig.accessTokenDetails.encryptedText, "base64", "utf8");
72
68
  secret += decipher.final("utf8");
73
69
  }
74
- catch (error) {
70
+ catch (_a) {
75
71
  console.error("ERROR: Failed to decrypt local credentials.\n" +
76
72
  " Check that you entered the correct password, or re-authenticate with `opal login`");
77
73
  process.exit(1);
@@ -81,4 +77,3 @@ const getSecretFromConfig = async (credsConfig) => {
81
77
  }
82
78
  return secret;
83
79
  };
84
- exports.getSecretFromConfig = getSecretFromConfig;
@@ -1,25 +1,22 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SHARED_FLAGS = void 0;
4
- const core_1 = require("@oclif/core");
5
- exports.SHARED_FLAGS = {
6
- help: core_1.Flags.help({ char: "h" }),
7
- id: core_1.Flags.string({
1
+ import { Flags } from "@oclif/core";
2
+ export const SHARED_FLAGS = {
3
+ help: Flags.help({ char: "h" }),
4
+ id: Flags.string({
8
5
  multiple: false,
9
6
  char: "i",
10
7
  description: "The Opal ID of the asset. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
11
8
  }),
12
- accessLevelRemoteId: core_1.Flags.string({
9
+ accessLevelRemoteId: Flags.string({
13
10
  multiple: false,
14
11
  char: "a",
15
12
  description: "The remote ID of the access level with which to access the resource.",
16
13
  }),
17
- sessionId: core_1.Flags.string({
14
+ sessionId: Flags.string({
18
15
  multiple: false,
19
16
  char: "s",
20
17
  description: "The Opal ID of the session to connect to. Uses an existing session that was created via the web flow.",
21
18
  }),
22
- refresh: core_1.Flags.boolean({
19
+ refresh: Flags.boolean({
23
20
  char: "r",
24
21
  description: "Starts a new session even if one already exists. Useful if a session is about to expire.",
25
22
  }),
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Starts a local HTTP server on port 8080 to handle OAuth callback.
3
+ * Returns a promise that resolves with the full callback URL when authentication succeeds.
4
+ */
5
+ export declare function startLocalServer(): Promise<string>;
@@ -0,0 +1,69 @@
1
+ import * as http from "node:http";
2
+ import { authErrorHtml, authMissingCodeHtml, authSuccessHtml, } from "./auth-success-template.js";
3
+ /**
4
+ * Starts a local HTTP server on port 8080 to handle OAuth callback.
5
+ * Returns a promise that resolves with the full callback URL when authentication succeeds.
6
+ */
7
+ export function startLocalServer() {
8
+ return new Promise((resolve, reject) => {
9
+ const server = http.createServer(async (req, res) => {
10
+ try {
11
+ const url = new URL(req.url || "", "http://127.0.0.1:8080");
12
+ if (url.pathname === "/callback") {
13
+ const error = url.searchParams.get("error");
14
+ if (error) {
15
+ res.writeHead(400, { "Content-Type": "text/html" });
16
+ res.end(authErrorHtml(error));
17
+ server.closeAllConnections();
18
+ server.close(() => {
19
+ reject(new Error(`Authentication failed: ${error}`));
20
+ });
21
+ return;
22
+ }
23
+ if (req.url) {
24
+ res.writeHead(200, { "Content-Type": "text/html" });
25
+ res.end(authSuccessHtml);
26
+ const fullUrl = `http://127.0.0.1:8080${req.url}`;
27
+ server.closeAllConnections();
28
+ server.close(() => {
29
+ resolve(fullUrl);
30
+ });
31
+ }
32
+ else {
33
+ res.writeHead(400, { "Content-Type": "text/html" });
34
+ res.end(authMissingCodeHtml);
35
+ server.closeAllConnections();
36
+ server.close(() => {
37
+ reject(new Error("Missing authorization code"));
38
+ });
39
+ }
40
+ }
41
+ else {
42
+ res.writeHead(404);
43
+ res.end();
44
+ }
45
+ }
46
+ catch (err) {
47
+ res.writeHead(400);
48
+ res.end();
49
+ server.closeAllConnections();
50
+ server.close(() => {
51
+ reject(err);
52
+ });
53
+ }
54
+ });
55
+ server.listen(8080, "127.0.0.1", () => {
56
+ console.log("Local server started on http://127.0.0.1:8080");
57
+ });
58
+ server.on("error", (err) => {
59
+ reject(err);
60
+ });
61
+ // Timeout after 5 minutes
62
+ setTimeout(() => {
63
+ server.closeAllConnections();
64
+ server.close(() => {
65
+ reject(new Error("Authentication timeout"));
66
+ });
67
+ }, 5 * 60 * 1000);
68
+ });
69
+ }
@@ -0,0 +1,6 @@
1
+ export { queryRequestableApps } from "./queries/apps.js";
2
+ export { queryRequestableAssets, queryCatalogItems } from "./queries/assets.js";
3
+ export { queryAssetRoles, queryAssociatedItems } from "./queries/roles.js";
4
+ export { queryRequestDefaults } from "./queries/request-defaults.js";
5
+ export { queryRequest, queryRequests } from "./queries/requests.js";
6
+ export { createRequest } from "./mutations/create-request.js";
@@ -0,0 +1,8 @@
1
+ // Query exports
2
+ export { queryRequestableApps } from "./queries/apps.js";
3
+ export { queryRequestableAssets, queryCatalogItems } from "./queries/assets.js";
4
+ export { queryAssetRoles, queryAssociatedItems } from "./queries/roles.js";
5
+ export { queryRequestDefaults } from "./queries/request-defaults.js";
6
+ export { queryRequest, queryRequests } from "./queries/requests.js";
7
+ // Mutation exports
8
+ export { createRequest } from "./mutations/create-request.js";
@@ -1,8 +1,8 @@
1
1
  import type { ApolloClient } from "@apollo/client";
2
2
  import type { Command } from "@oclif/core";
3
- import type { RequestedGroupInput, RequestedResourceInput } from "../../../../graphql/graphql";
3
+ import type { RequestedGroupInput, RequestedResourceInput } from "../../../../graphql/graphql.js";
4
4
  export declare function createRequest(cmd: Command, client: ApolloClient, requestedResources: RequestedResourceInput[], requestedGroups: RequestedGroupInput[], reason: string, durationInMinutes?: number): Promise<{
5
5
  __typename?: "Request";
6
6
  id: string;
7
- status: import("../../../../graphql/graphql").RequestStatus;
7
+ status: import("../../../../graphql/graphql.js").RequestStatus;
8
8
  } | undefined>;
@@ -1,8 +1,5 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createRequest = createRequest;
4
- const graphql_1 = require("../../../../graphql");
5
- const CREATE_REQUEST_MUTATION = (0, graphql_1.graphql)(`
1
+ import { graphql } from "../../../../graphql/index.js";
2
+ const CREATE_REQUEST_MUTATION = graphql(`
6
3
  mutation CreateRequest(
7
4
  $requestedResources: [RequestedResourceInput!]!
8
5
  $requestedGroups: [RequestedGroupInput!]!
@@ -86,7 +83,7 @@ const CREATE_REQUEST_MUTATION = (0, graphql_1.graphql)(`
86
83
  }
87
84
  }
88
85
  `);
89
- async function createRequest(cmd, client, requestedResources, requestedGroups, reason, durationInMinutes) {
86
+ export async function createRequest(cmd, client, requestedResources, requestedGroups, reason, durationInMinutes) {
90
87
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
91
88
  try {
92
89
  const resp = await client.mutate({
@@ -1,4 +1,4 @@
1
1
  import type { ApolloClient } from "@apollo/client";
2
2
  import type { Command } from "@oclif/core";
3
- import type { PromptChoice } from "../../types";
3
+ import type { PromptChoice } from "../../types.js";
4
4
  export declare function queryRequestableApps(cmd: Command, client: ApolloClient, input: string | undefined): Promise<PromptChoice[] | undefined>;
@@ -1,9 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.queryRequestableApps = queryRequestableApps;
4
- const graphql_1 = require("../../../../graphql");
1
+ import { graphql } from "../../../../graphql/index.js";
5
2
  // TODO: add pagination ability from CLI. (Load more...) option
6
- const GET_REQUESTABLE_APPS_QUERY = (0, graphql_1.graphql)(`
3
+ const GET_REQUESTABLE_APPS_QUERY = graphql(`
7
4
  query GetRequestableAppsQuery($searchQuery: String) {
8
5
  appsV2(
9
6
  filters: {
@@ -32,7 +29,7 @@ const GET_REQUESTABLE_APPS_QUERY = (0, graphql_1.graphql)(`
32
29
  }
33
30
  }
34
31
  `);
35
- async function queryRequestableApps(cmd, client, input) {
32
+ export async function queryRequestableApps(cmd, client, input) {
36
33
  var _a, _b;
37
34
  try {
38
35
  const resp = await client.query({
@@ -1,6 +1,6 @@
1
1
  import type { ApolloClient } from "@apollo/client";
2
2
  import type { Command } from "@oclif/core";
3
- import type { GetCatalogItemQuery } from "../../../../graphql/graphql";
4
- import { type PromptChoice } from "../../types";
3
+ import type { GetCatalogItemQuery } from "../../../../graphql/graphql.js";
4
+ import { type PromptChoice } from "../../types.js";
5
5
  export declare function queryRequestableAssets(cmd: Command, client: ApolloClient, appId: string, input: string | undefined): Promise<PromptChoice[] | undefined>;
6
6
  export declare function queryCatalogItems(cmd: Command, client: ApolloClient, assetId: string): Promise<ApolloClient.QueryResult<GetCatalogItemQuery>>;
@@ -1,10 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.queryRequestableAssets = queryRequestableAssets;
4
- exports.queryCatalogItems = queryCatalogItems;
5
- const graphql_1 = require("../../../../graphql");
6
- const types_1 = require("../../types");
7
- const GET_ASSETS_QUERY = (0, graphql_1.graphql)(`
1
+ import { graphql } from "../../../../graphql/index.js";
2
+ import { entityTypeFromString } from "../../types.js";
3
+ const GET_ASSETS_QUERY = graphql(`
8
4
  query PaginatedEntityDropdown(
9
5
  $id: UUID!
10
6
  $searchQuery: String
@@ -40,7 +36,7 @@ const GET_ASSETS_QUERY = (0, graphql_1.graphql)(`
40
36
  }
41
37
  }
42
38
  `);
43
- async function queryRequestableAssets(cmd, client, appId, input) {
39
+ export async function queryRequestableAssets(cmd, client, appId, input) {
44
40
  var _a, _b, _c, _d, _e, _f, _g;
45
41
  try {
46
42
  const resp = await client.query({
@@ -65,7 +61,7 @@ async function queryRequestableAssets(cmd, client, appId, input) {
65
61
  value: {
66
62
  name: name || "",
67
63
  id: id || "",
68
- type: (0, types_1.entityTypeFromString)(((_g = item.resource) === null || _g === void 0 ? void 0 : _g.__typename) || ((_h = item.group) === null || _h === void 0 ? void 0 : _h.__typename)),
64
+ type: entityTypeFromString(((_g = item.resource) === null || _g === void 0 ? void 0 : _g.__typename) || ((_h = item.group) === null || _h === void 0 ? void 0 : _h.__typename)),
69
65
  },
70
66
  };
71
67
  });
@@ -82,7 +78,7 @@ async function queryRequestableAssets(cmd, client, appId, input) {
82
78
  }
83
79
  }
84
80
  }
85
- const CATALOG_ITEM = (0, graphql_1.graphql)(`
81
+ const CATALOG_ITEM = graphql(`
86
82
  query GetCatalogItem($uuid: UUID!) {
87
83
  catalogItem(id: $uuid) {
88
84
  __typename
@@ -120,7 +116,7 @@ const CATALOG_ITEM = (0, graphql_1.graphql)(`
120
116
  }
121
117
  }
122
118
  `);
123
- async function queryCatalogItems(cmd, client, assetId) {
119
+ export async function queryCatalogItems(cmd, client, assetId) {
124
120
  try {
125
121
  return await client.query({
126
122
  query: CATALOG_ITEM,
@@ -1,5 +1,5 @@
1
1
  import type { ApolloClient } from "@apollo/client";
2
2
  import type { Command } from "@oclif/core";
3
- import type { RequestConfigurationGroupInput, RequestConfigurationResourceInput } from "../../../../graphql/graphql";
4
- import type { RequestDefaults } from "../../types";
3
+ import type { RequestConfigurationGroupInput, RequestConfigurationResourceInput } from "../../../../graphql/graphql.js";
4
+ import type { RequestDefaults } from "../../types.js";
5
5
  export declare function queryRequestDefaults(cmd: Command, client: ApolloClient, requestedResources: RequestConfigurationResourceInput[], requestedGroups: RequestConfigurationGroupInput[]): Promise<RequestDefaults | undefined>;
@@ -1,8 +1,5 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.queryRequestDefaults = queryRequestDefaults;
4
- const graphql_1 = require("../../../../graphql");
5
- const REQUEST_DEFAULTS_QUERY = (0, graphql_1.graphql)(`
1
+ import { graphql } from "../../../../graphql/index.js";
2
+ const REQUEST_DEFAULTS_QUERY = graphql(`
6
3
  query RequestDefaults(
7
4
  $requestedResources: [RequestConfigurationResourceInput!]!
8
5
  $requestedGroups: [RequestConfigurationGroupInput!]!
@@ -31,7 +28,7 @@ const REQUEST_DEFAULTS_QUERY = (0, graphql_1.graphql)(`
31
28
  }
32
29
  }
33
30
  }`);
34
- async function queryRequestDefaults(cmd, client, requestedResources, requestedGroups) {
31
+ export async function queryRequestDefaults(cmd, client, requestedResources, requestedGroups) {
35
32
  var _a;
36
33
  try {
37
34
  const resp = await client.query({
@@ -1,4 +1,4 @@
1
1
  import type { ApolloClient } from "@apollo/client";
2
- export declare const queryRequest: (client: ApolloClient, requestId: string) => Promise<ApolloClient.QueryResult<import("../../../../graphql/graphql").GetRequestQuery>>;
3
- export declare const queryRequests: (client: ApolloClient, pageSize: number, showPendingOnly: boolean) => Promise<ApolloClient.QueryResult<import("../../../../graphql/graphql").GetRequestsQuery>>;
4
- export declare const queryBundle: (client: ApolloClient, bundleId: string) => Promise<ApolloClient.QueryResult<import("../../../../graphql/graphql").GetBundleQuery>>;
2
+ export declare const queryRequest: (client: ApolloClient, requestId: string) => Promise<ApolloClient.QueryResult<import("../../../../graphql/graphql.js").GetRequestQuery>>;
3
+ export declare const queryRequests: (client: ApolloClient, pageSize: number, showPendingOnly: boolean) => Promise<ApolloClient.QueryResult<import("../../../../graphql/graphql.js").GetRequestsQuery>>;
4
+ export declare const queryBundle: (client: ApolloClient, bundleId: string) => Promise<ApolloClient.QueryResult<import("../../../../graphql/graphql.js").GetBundleQuery>>;
@@ -1,8 +1,5 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.queryBundle = exports.queryRequests = exports.queryRequest = void 0;
4
- const graphql_1 = require("../../../../graphql");
5
- const RESOURCE_FRAGMENT = (0, graphql_1.graphql)(`
1
+ import { graphql } from "../../../../graphql/index.js";
2
+ const RESOURCE_FRAGMENT = graphql(`
6
3
  fragment ResourceFields on Resource {
7
4
  displayName
8
5
  id
@@ -13,7 +10,7 @@ const RESOURCE_FRAGMENT = (0, graphql_1.graphql)(`
13
10
  }
14
11
  }
15
12
  `);
16
- const GROUP_FRAGMENT = (0, graphql_1.graphql)(`
13
+ const GROUP_FRAGMENT = graphql(`
17
14
  fragment GroupFields on Group {
18
15
  name
19
16
  id
@@ -24,7 +21,7 @@ const GROUP_FRAGMENT = (0, graphql_1.graphql)(`
24
21
  }
25
22
  }
26
23
  `);
27
- const REQUEST_FIELDS_FRAGMENT = (0, graphql_1.graphql)(`
24
+ const REQUEST_FIELDS_FRAGMENT = graphql(`
28
25
  fragment RequestFields on Request {
29
26
  id
30
27
  createdAt
@@ -57,7 +54,7 @@ const REQUEST_FIELDS_FRAGMENT = (0, graphql_1.graphql)(`
57
54
  }
58
55
  }
59
56
  `);
60
- const GET_REQUEST = (0, graphql_1.graphql)(`
57
+ const GET_REQUEST = graphql(`
61
58
  query GetRequest(
62
59
  $id: RequestId!
63
60
  ) {
@@ -74,7 +71,7 @@ const GET_REQUEST = (0, graphql_1.graphql)(`
74
71
  }
75
72
  }
76
73
  `);
77
- const queryRequest = async (client, requestId) => {
74
+ export const queryRequest = async (client, requestId) => {
78
75
  const resp = await client.query({
79
76
  query: GET_REQUEST,
80
77
  variables: {
@@ -84,9 +81,8 @@ const queryRequest = async (client, requestId) => {
84
81
  });
85
82
  return resp;
86
83
  };
87
- exports.queryRequest = queryRequest;
88
84
  // TODO: Add date filters, search query,
89
- const GET_OUTGOING_REQUESTS = (0, graphql_1.graphql)(`
85
+ const GET_OUTGOING_REQUESTS = graphql(`
90
86
  query GetRequests($showPendingOnly: Boolean!, $pageSize: Int) {
91
87
  requests(input: {
92
88
  requestType: OUTGOING
@@ -106,7 +102,7 @@ const GET_OUTGOING_REQUESTS = (0, graphql_1.graphql)(`
106
102
 
107
103
  }
108
104
  }`);
109
- const queryRequests = async (client, pageSize, showPendingOnly) => {
105
+ export const queryRequests = async (client, pageSize, showPendingOnly) => {
110
106
  const resp = await client.query({
111
107
  query: GET_OUTGOING_REQUESTS,
112
108
  variables: {
@@ -117,8 +113,7 @@ const queryRequests = async (client, pageSize, showPendingOnly) => {
117
113
  });
118
114
  return resp;
119
115
  };
120
- exports.queryRequests = queryRequests;
121
- const GET_BUNDLE = (0, graphql_1.graphql)(`query GetBundle($id: BundleId!) {
116
+ const GET_BUNDLE = graphql(`query GetBundle($id: BundleId!) {
122
117
  bundle(input: { id: $id }) {
123
118
  __typename
124
119
  ... on BundleResult {
@@ -150,7 +145,7 @@ const GET_BUNDLE = (0, graphql_1.graphql)(`query GetBundle($id: BundleId!) {
150
145
  }
151
146
  }
152
147
  }`);
153
- const queryBundle = async (client, bundleId) => {
148
+ export const queryBundle = async (client, bundleId) => {
154
149
  const resp = await client.query({
155
150
  query: GET_BUNDLE,
156
151
  variables: {
@@ -160,4 +155,3 @@ const queryBundle = async (client, bundleId) => {
160
155
  });
161
156
  return resp;
162
157
  };
163
- exports.queryBundle = queryBundle;
@@ -1,5 +1,5 @@
1
1
  import type { ApolloClient } from "@apollo/client";
2
2
  import type { Command } from "@oclif/core";
3
- import type { PromptChoice } from "../../types";
3
+ import type { PromptChoice } from "../../types.js";
4
4
  export declare function queryAssetRoles(cmd: Command, client: ApolloClient, assetType: string, assetId: string): Promise<PromptChoice[] | undefined>;
5
5
  export declare function queryAssociatedItems(cmd: Command, client: ApolloClient, id: string, input: string | undefined): Promise<PromptChoice[] | undefined>;