opal-security 2.1.0 → 2.1.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.
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const command_1 = require("@oclif/command");
4
4
  const credentials_1 = require("../lib/credentials");
5
+ const flags_1 = require("../lib/flags");
5
6
  class Logout extends command_1.Command {
6
7
  async run() {
7
8
  try {
@@ -17,6 +18,6 @@ exports.default = Logout;
17
18
  Logout.description = 'Clears locally stored Opal server authentication credentials.';
18
19
  Logout.examples = ['$ opal logout'];
19
20
  Logout.flags = {
20
- help: command_1.flags.help({ char: 'h' }),
21
+ help: flags_1.SHARED_FLAGS.help,
21
22
  };
22
23
  Logout.args = [];
@@ -7,6 +7,8 @@ export default class StartPostgresInstanceSession extends Command {
7
7
  id: flags.IOptionFlag<string | undefined>;
8
8
  accessLevelRemoteId: flags.IOptionFlag<string | undefined>;
9
9
  sessionId: flags.IOptionFlag<string | undefined>;
10
+ refresh: import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
11
+ action: flags.IOptionFlag<string | undefined>;
10
12
  };
11
13
  run(): Promise<void>;
12
14
  }
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const command_1 = require("@oclif/command");
4
+ const inquirer = require("inquirer");
4
5
  const cmd_1 = require("../../lib/cmd");
5
6
  const apollo_1 = require("../../lib/apollo");
6
- const inquirer = require("inquirer");
7
7
  const resources_1 = require("../../lib/resources");
8
- const common_1 = require("../../lib/common");
8
+ const util_1 = require("../../lib/util");
9
9
  const sessions_1 = require("../../lib/sessions");
10
+ const flags_1 = require("../../lib/flags");
10
11
  const RdsSessionMetadataFragment = `
11
12
  ... on AwsIamFederatedRdsSession {
12
13
  dbUser
@@ -15,15 +16,33 @@ const RdsSessionMetadataFragment = `
15
16
  dbPort
16
17
  dbName
17
18
  }`;
19
+ const methodChoices = [
20
+ {
21
+ name: 'Open external database app',
22
+ value: 'open',
23
+ },
24
+ {
25
+ name: 'Start psql session in shell',
26
+ value: 'psql',
27
+ },
28
+ {
29
+ name: 'View connection configuration details',
30
+ value: 'view',
31
+ },
32
+ ];
18
33
  class StartPostgresInstanceSession extends command_1.Command {
19
34
  async run() {
20
35
  cmd_1.setMostRecentCommand(this);
21
36
  const { flags } = this.parse(StartPostgresInstanceSession);
37
+ if (flags.sessionId && flags.refresh) {
38
+ return apollo_1.handleError(this, 'Cannot use both --sessionId and --refresh');
39
+ }
22
40
  let instanceId = flags.id;
23
41
  let instanceName = null;
24
42
  const sessionId = flags.sessionId;
43
+ let action = flags.action;
25
44
  if (!instanceId) {
26
- const selectedInstance = await resources_1.promptUserForResource(this, 'AWS_RDS_POSTGRES_INSTANCE', 'Select an RDS Postgres instance to login to');
45
+ const selectedInstance = await resources_1.promptUserForResource(this, 'AWS_RDS_POSTGRES_INSTANCE', 'Select an RDS Postgres instance to connect to');
27
46
  if (!selectedInstance) {
28
47
  return;
29
48
  }
@@ -34,7 +53,7 @@ class StartPostgresInstanceSession extends command_1.Command {
34
53
  if (!accessLevel) {
35
54
  return;
36
55
  }
37
- const session = await sessions_1.getOrCreateSession(this, instanceId, accessLevel, sessionId, RdsSessionMetadataFragment);
56
+ const session = await sessions_1.getOrCreateSession(this, instanceId, accessLevel, sessionId, RdsSessionMetadataFragment, flags.refresh);
38
57
  const metadata = session.metadata;
39
58
  switch (metadata === null || metadata === void 0 ? void 0 : metadata.__typename) {
40
59
  case 'AwsIamFederatedRdsSession': {
@@ -43,33 +62,23 @@ class StartPostgresInstanceSession extends command_1.Command {
43
62
  // However, once connected, RDS sessions can be used for up to 12h.
44
63
  // Since there's many options for how the user can use RDS credentials, it's unclear which expiration
45
64
  // we want to show the user.
46
- const externalAppLaunchName = 'Launch external database app';
47
- const psqlSessionLaunchName = 'Launch shell with psql session';
48
- const viewDetailsName = 'View connection configuration';
49
- const selectedLaunchInfo = await inquirer.prompt([{
50
- name: 'launch',
51
- message: 'Select how to access the database',
52
- type: 'list',
53
- choices: [
54
- {
55
- name: externalAppLaunchName,
56
- },
57
- {
58
- name: psqlSessionLaunchName,
59
- },
60
- {
61
- name: viewDetailsName,
62
- },
63
- ],
64
- }]);
65
+ if (!action) {
66
+ const selectedMethodInfo = await inquirer.prompt([{
67
+ name: 'method',
68
+ message: 'Select how to access the database',
69
+ type: 'list',
70
+ choices: methodChoices,
71
+ }]);
72
+ action = selectedMethodInfo.method;
73
+ }
65
74
  const dbUrl = `postgresql://${metadata.dbUser}:${encodeURIComponent(metadata.dbPassword)}@${metadata.dbHostname}:${metadata.dbPort}/${metadata.dbName}`;
66
- switch (selectedLaunchInfo.launch) {
67
- case externalAppLaunchName: {
75
+ switch (action) {
76
+ case 'open': {
68
77
  const startSessionCmd = `open ${dbUrl}`;
69
78
  cmd_1.runCommandExec(startSessionCmd, `Opened external app for ${instanceName ? `"${instanceName}" instance` : 'instance'}`, `Failed to open external app for ${instanceName ? `"${instanceName}" instance` : 'instance'}`);
70
79
  break;
71
80
  }
72
- case viewDetailsName: {
81
+ case 'view': {
73
82
  const contentParts = [
74
83
  `[Connection URL]\n${dbUrl}`,
75
84
  `[Hostname]\n${metadata.dbHostname}`,
@@ -79,10 +88,10 @@ class StartPostgresInstanceSession extends command_1.Command {
79
88
  `[Database]\n${metadata.dbName}`,
80
89
  ];
81
90
  const content = contentParts.join('\n\n');
82
- common_1.displayContent(content);
91
+ util_1.displayContent(content);
83
92
  break;
84
93
  }
85
- case psqlSessionLaunchName: {
94
+ case 'psql': {
86
95
  const startSessionCmd = `psql ${dbUrl}`;
87
96
  cmd_1.startInteractiveShell(startSessionCmd, `shell with psql session for ${instanceName ? `"${instanceName}" instance` : 'instance'}`);
88
97
  break;
@@ -96,24 +105,23 @@ class StartPostgresInstanceSession extends command_1.Command {
96
105
  }
97
106
  }
98
107
  exports.default = StartPostgresInstanceSession;
99
- StartPostgresInstanceSession.description = 'Starts a session to query a Postgres database.';
108
+ StartPostgresInstanceSession.description = 'Starts a session to connect to a Postgres database.';
100
109
  StartPostgresInstanceSession.examples = [
101
110
  'opal postgres-instances:start',
102
111
  'opal postgres-instances:start --id 51f7176b-0464-4a6f-8369-e951e187b398',
103
- 'opal postgres-instances:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --accessLevelRemoteId "fullaccess"',
112
+ 'opal postgres-instances:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --accessLevelRemoteId fullaccess',
113
+ 'opal postgres-instances:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --accessLevelRemoteId fullaccess --action view',
104
114
  ];
105
115
  StartPostgresInstanceSession.flags = {
106
- help: command_1.flags.help({ char: 'h' }),
107
- id: command_1.flags.string({
108
- multiple: false,
109
- description: 'The ID of the Opal instance resource.',
110
- }),
111
- accessLevelRemoteId: command_1.flags.string({
112
- multiple: false,
113
- description: 'The remote ID of the access level with which to access the database.',
114
- }),
115
- sessionId: command_1.flags.string({
116
+ help: flags_1.SHARED_FLAGS.help,
117
+ id: flags_1.SHARED_FLAGS.id,
118
+ accessLevelRemoteId: flags_1.SHARED_FLAGS.accessLevelRemoteId,
119
+ sessionId: flags_1.SHARED_FLAGS.sessionId,
120
+ refresh: flags_1.SHARED_FLAGS.refresh,
121
+ action: command_1.flags.string({
116
122
  multiple: false,
117
- description: 'SessionId of a session that has already been created via the web flow.',
123
+ description: 'Method of connecting to the database.\n' +
124
+ methodChoices.map(c => `- ${c.value}: ${c.name}`).join('\n'),
125
+ options: methodChoices.map(c => c.value),
118
126
  }),
119
127
  };
@@ -1,11 +1,11 @@
1
- import { Command, flags } from '@oclif/command';
1
+ import { Command } from '@oclif/command';
2
2
  export declare const GetResourceDocument = "\nquery GetResource($id: ResourceId!) {\n resource(input: {id: $id}) {\n __typename\n ... on ResourceResult {\n resource {\n name\n id\n description\n resourceType\n connection {\n name\n id\n connectionType\n }\n parentResource {\n name\n id\n resourceType\n }\n resourceUsers {\n user {\n fullName\n email\n id\n }\n }\n }\n }\n ... on ResourceNotFoundError {\n message\n }\n }\n}";
3
3
  export default class GetResource extends Command {
4
4
  static description: string;
5
5
  static examples: string[];
6
6
  static flags: {
7
7
  help: import("@oclif/parser/lib/flags").IBooleanFlag<void>;
8
- id: flags.IOptionFlag<string>;
8
+ id: import("@oclif/command/lib/flags").IOptionFlag<string | undefined>;
9
9
  };
10
10
  run(): Promise<void>;
11
11
  }
@@ -5,6 +5,7 @@ const command_1 = require("@oclif/command");
5
5
  const handler_1 = require("../../handler");
6
6
  const cmd_1 = require("../../lib/cmd");
7
7
  const apollo_1 = require("../../lib/apollo");
8
+ const flags_1 = require("../../lib/flags");
8
9
  exports.GetResourceDocument = `
9
10
  query GetResource($id: ResourceId!) {
10
11
  resource(input: {id: $id}) {
@@ -58,9 +59,6 @@ exports.default = GetResource;
58
59
  GetResource.description = 'Get resource info for a particular resource.';
59
60
  GetResource.examples = ['opal resources:get --id 54052a3e-5375-4392-aeaf-0c6c44c131d4'];
60
61
  GetResource.flags = {
61
- help: command_1.flags.help({ char: 'h' }),
62
- id: command_1.flags.string({
63
- multiple: false,
64
- required: true,
65
- }),
62
+ help: flags_1.SHARED_FLAGS.help,
63
+ id: flags_1.SHARED_FLAGS.id,
66
64
  };
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const command_1 = require("@oclif/command");
4
4
  const apollo_1 = require("../lib/apollo");
5
5
  const config_1 = require("../lib/config");
6
+ const flags_1 = require("../lib/flags");
6
7
  class SetCustomHeader extends command_1.Command {
7
8
  async run() {
8
9
  try {
@@ -26,7 +27,7 @@ exports.default = SetCustomHeader;
26
27
  SetCustomHeader.description = 'Sets a custom HTTP header to connect to the Opal server.';
27
28
  SetCustomHeader.examples = ['$ opal set-custom-header --header \'cf-access-token: $TOKEN\''];
28
29
  SetCustomHeader.flags = {
29
- help: command_1.flags.help({ char: 'h' }),
30
+ help: flags_1.SHARED_FLAGS.help,
30
31
  header: command_1.flags.string({
31
32
  multiple: false,
32
33
  }),
@@ -8,6 +8,7 @@ const credentials_1 = require("../lib/credentials");
8
8
  const handler_1 = require("../handler");
9
9
  const credentials_2 = require("../lib/credentials");
10
10
  const login_1 = require("./login");
11
+ const flags_1 = require("../lib/flags");
11
12
  class SetToken extends command_1.Command {
12
13
  async run() {
13
14
  var _a, _b, _c;
@@ -53,6 +54,6 @@ exports.default = SetToken;
53
54
  SetToken.description = 'Sets an API token to authenticate with the Opal server - alternative auth flow for headless environments.';
54
55
  SetToken.examples = ['$ opal set-token'];
55
56
  SetToken.flags = {
56
- help: command_1.flags.help({ char: 'h' }),
57
+ help: flags_1.SHARED_FLAGS.help,
57
58
  };
58
59
  SetToken.args = [];
@@ -4,6 +4,7 @@ const command_1 = require("@oclif/command");
4
4
  const apollo_1 = require("../lib/apollo");
5
5
  const config_1 = require("../lib/config");
6
6
  const credentials_1 = require("../lib/credentials");
7
+ const flags_1 = require("../lib/flags");
7
8
  class SetUrl extends command_1.Command {
8
9
  async run() {
9
10
  try {
@@ -62,13 +63,14 @@ exports.default = SetUrl;
62
63
  SetUrl.description = `Sets the url of the Opal server. Defaults to ${config_1.defaultUrl}.`;
63
64
  SetUrl.examples = ['$ opal set-url'];
64
65
  SetUrl.flags = {
65
- help: command_1.flags.help({ char: 'h' }),
66
+ help: flags_1.SHARED_FLAGS.help,
66
67
  allowSelfSignedCerts: command_1.flags.boolean(),
67
- // Legacy flags
68
+ // Deprecated
68
69
  custom: command_1.flags.string({
69
70
  multiple: false,
70
71
  hidden: true,
71
72
  }),
73
+ // Used only internally
72
74
  prod: command_1.flags.boolean({ hidden: true }),
73
75
  demo: command_1.flags.boolean({ hidden: true }),
74
76
  dev: command_1.flags.boolean({ hidden: true }),
@@ -7,6 +7,7 @@ const ssh_1 = require("../../lib/ssh");
7
7
  const resources_1 = require("../../lib/resources");
8
8
  const sessions_1 = require("../../lib/sessions");
9
9
  const start_1 = require("./start");
10
+ const flags_1 = require("../../lib/flags");
10
11
  class StartSCPSession extends command_1.Command {
11
12
  async run() {
12
13
  cmd_1.setMostRecentCommand(this);
@@ -53,30 +54,24 @@ StartSCPSession.examples = [
53
54
  'opal ssh:copyFrom --src instance/dir --dest my/dir --id 51f7176b-0464-4a6f-8369-e951e187b398',
54
55
  ];
55
56
  StartSCPSession.flags = {
56
- help: command_1.flags.help({ char: 'h' }),
57
+ help: flags_1.SHARED_FLAGS.help,
57
58
  src: command_1.flags.string({
58
59
  multiple: false,
59
60
  required: true,
60
- description: 'The path of the directory or file you would like to copy over SCP. Note we only support one file or directory at a time.',
61
+ description: 'The directory or file you would like to copy over SCP. Note we only support one file or directory at a time.',
61
62
  }),
62
63
  dest: command_1.flags.string({
63
64
  multiple: false,
64
65
  required: false,
65
66
  default: '.',
66
- description: 'Pick which directory you want your files to be copied to.',
67
+ description: 'The directory you want your files to be copied to.',
67
68
  }),
68
69
  user: command_1.flags.string({
69
70
  multiple: false,
70
71
  required: false,
71
72
  default: 'ssm-user',
72
- description: 'Pick which user you want to run SCP over. Keep in mind not all users will have access to each other\'s home directory.',
73
- }),
74
- id: command_1.flags.string({
75
- multiple: false,
76
- description: 'The ID of the Opal instance resource.',
77
- }),
78
- sessionId: command_1.flags.string({
79
- multiple: false,
80
- description: 'SessionId of a session that has already been created via the web flow.',
73
+ description: 'The user you want to run SCP over. Keep in mind not all users will have access to each other\'s home directory.',
81
74
  }),
75
+ id: flags_1.SHARED_FLAGS.id,
76
+ sessionId: flags_1.SHARED_FLAGS.sessionId,
82
77
  };
@@ -7,6 +7,7 @@ const ssh_1 = require("../../lib/ssh");
7
7
  const resources_1 = require("../../lib/resources");
8
8
  const sessions_1 = require("../../lib/sessions");
9
9
  const start_1 = require("./start");
10
+ const flags_1 = require("../../lib/flags");
10
11
  class StartSCPSession extends command_1.Command {
11
12
  async run() {
12
13
  cmd_1.setMostRecentCommand(this);
@@ -53,30 +54,24 @@ StartSCPSession.examples = [
53
54
  'opal ssh:copyTo --src my/dir --dest instance/dir --id 51f7176b-0464-4a6f-8369-e951e187b398',
54
55
  ];
55
56
  StartSCPSession.flags = {
56
- help: command_1.flags.help({ char: 'h' }),
57
+ help: flags_1.SHARED_FLAGS.help,
57
58
  src: command_1.flags.string({
58
59
  multiple: false,
59
60
  required: true,
60
- description: 'The path of the directory or file you would like to copy over SCP. Note we only support one file or directory at a time.',
61
+ description: 'The directory or file you would like to copy over SCP. Note we only support one file or directory at a time.',
61
62
  }),
62
63
  dest: command_1.flags.string({
63
64
  multiple: false,
64
65
  required: false,
65
66
  default: '.',
66
- description: 'Pick which directory you want your files to be copied to.',
67
+ description: 'The directory you want your files to be copied to.',
67
68
  }),
68
69
  user: command_1.flags.string({
69
70
  multiple: false,
70
71
  required: false,
71
72
  default: 'ssm-user',
72
- description: 'Pick which user you want to run SCP over. Keep in mind not all users will have access to each other\'s home directory.',
73
- }),
74
- id: command_1.flags.string({
75
- multiple: false,
76
- description: 'The ID of the Opal instance resource.',
77
- }),
78
- sessionId: command_1.flags.string({
79
- multiple: false,
80
- description: 'SessionId of a session that has already been created via the web flow.',
73
+ description: 'The user you want to run SCP over. Keep in mind not all users will have access to each other\'s home directory.',
81
74
  }),
75
+ id: flags_1.SHARED_FLAGS.id,
76
+ sessionId: flags_1.SHARED_FLAGS.sessionId,
82
77
  };
@@ -1,12 +1,13 @@
1
- import { Command, flags } from '@oclif/command';
1
+ import { Command } from '@oclif/command';
2
2
  export declare const Ec2SessionMetadataFragment = "\n... on AwsIamFederatedSSMSession {\n awsAccessKeyId\n awsSecretAccessKey\n awsSessionToken\n awsLoginUrl\n federatedArn\n ec2InstanceId\n ec2Region\n}";
3
3
  export default class StartSSHSession extends Command {
4
4
  static description: string;
5
5
  static examples: string[];
6
6
  static flags: {
7
7
  help: import("@oclif/parser/lib/flags").IBooleanFlag<void>;
8
- id: flags.IOptionFlag<string | undefined>;
9
- sessionId: flags.IOptionFlag<string | undefined>;
8
+ id: import("@oclif/command/lib/flags").IOptionFlag<string | undefined>;
9
+ sessionId: import("@oclif/command/lib/flags").IOptionFlag<string | undefined>;
10
+ refresh: import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
10
11
  };
11
12
  run(): Promise<void>;
12
13
  }
@@ -10,6 +10,7 @@ const get_1 = require("../../commands/resources/get");
10
10
  const aws_1 = require("../../lib/aws");
11
11
  const resources_1 = require("../../lib/resources");
12
12
  const sessions_1 = require("../../lib/sessions");
13
+ const flags_1 = require("../../lib/flags");
13
14
  exports.Ec2SessionMetadataFragment = `
14
15
  ... on AwsIamFederatedSSMSession {
15
16
  awsAccessKeyId
@@ -24,6 +25,9 @@ class StartSSHSession extends command_1.Command {
24
25
  async run() {
25
26
  cmd_1.setMostRecentCommand(this);
26
27
  const { flags } = this.parse(StartSSHSession);
28
+ if (flags.sessionId && flags.refresh) {
29
+ return apollo_1.handleError(this, 'Cannot use both --sessionId and --refresh');
30
+ }
27
31
  const pluginExists = await ssh_1.assertSessionManagerPluginExists();
28
32
  if (!pluginExists) {
29
33
  return;
@@ -56,7 +60,7 @@ class StartSSHSession extends command_1.Command {
56
60
  instanceName =
57
61
  (resp === null || resp === void 0 ? void 0 : resp.data.resource.resource.name) || 'ssh-instance';
58
62
  }
59
- const session = await sessions_1.getOrCreateSession(this, instanceId, resources_1.DEFAULT_ACCESS_LEVEL, sessionId, exports.Ec2SessionMetadataFragment);
63
+ const session = await sessions_1.getOrCreateSession(this, instanceId, resources_1.DEFAULT_ACCESS_LEVEL, sessionId, exports.Ec2SessionMetadataFragment, flags.refresh);
60
64
  const metadata = session.metadata;
61
65
  switch (metadata === null || metadata === void 0 ? void 0 : metadata.__typename) {
62
66
  case 'AwsIamFederatedSSMSession': {
@@ -82,19 +86,14 @@ StartSSHSession.examples = [
82
86
  'opal ssh:start --id 51f7176b-0464-4a6f-8369-e951e187b398',
83
87
  ];
84
88
  StartSSHSession.flags = {
85
- help: command_1.flags.help({ char: 'h' }),
86
- id: command_1.flags.string({
87
- multiple: false,
88
- description: 'The ID of the Opal instance resource.',
89
- }),
89
+ help: flags_1.SHARED_FLAGS.help,
90
+ id: flags_1.SHARED_FLAGS.id,
90
91
  // TODO: Unfortunately allowing SSM over SSH disables logging
91
92
  // user: flags.string({
92
93
  // multiple: false,
93
94
  // required: false,
94
95
  // default: "ssm-user",
95
96
  // }),
96
- sessionId: command_1.flags.string({
97
- multiple: false,
98
- description: 'SessionId of a session that has already been created via the web flow.',
99
- }),
97
+ sessionId: flags_1.SHARED_FLAGS.sessionId,
98
+ refresh: flags_1.SHARED_FLAGS.refresh,
100
99
  };
@@ -1,6 +1,6 @@
1
1
  import { ApolloClient, NormalizedCacheObject } from '@apollo/client/core';
2
2
  import { Command } from '@oclif/command';
3
3
  export declare let client: ApolloClient<NormalizedCacheObject> | null;
4
- export declare const initClient: (command: Command) => Promise<void>;
5
4
  export declare const printResponse: (command: Command, resp: any) => void;
6
5
  export declare const handleError: (command: Command, err: any, resp?: any) => void;
6
+ export declare const initClient: (command: Command) => Promise<void>;
package/lib/lib/apollo.js CHANGED
@@ -1,22 +1,55 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.handleError = exports.printResponse = exports.initClient = exports.client = void 0;
3
+ exports.initClient = exports.handleError = exports.printResponse = exports.client = void 0;
4
4
  const core_1 = require("@apollo/client/core");
5
5
  const context_1 = require("@apollo/client/link/context");
6
6
  const error_1 = require("@apollo/client/link/error");
7
7
  const prettyjson_1 = require("prettyjson");
8
+ const semver_1 = require("semver");
9
+ const chalk_1 = require("chalk");
10
+ const moment = require("moment");
8
11
  const config_1 = require("../lib/config");
9
12
  const credentials_1 = require("../lib/credentials");
10
13
  const login_1 = require("../commands/login");
11
- const semver_1 = require("semver");
12
- const chalk_1 = require("chalk");
13
14
  const cmd_1 = require("../lib/cmd");
14
- const moment = require("moment");
15
15
  const fetch = require('node-fetch');
16
16
  const https = require('https');
17
17
  const http = require('http');
18
18
  exports.client = null;
19
19
  let alreadyNotifiedRecommendedVersion = false;
20
+ exports.printResponse = (command, resp) => {
21
+ const filteredJson = JSON.parse(JSON.stringify(resp.data, (k, v) => {
22
+ if (k === '__typename' || v === null || (Array.isArray(v) && v.length === 0)) {
23
+ return undefined;
24
+ }
25
+ return v;
26
+ }));
27
+ command.log(prettyjson_1.render(filteredJson));
28
+ };
29
+ exports.handleError = (command, err, resp) => {
30
+ if (err && typeof err === 'object' && ('networkError' in err && 'statusCode' in err.networkError)) {
31
+ // Status code errors are already handled in the global Apollo handler, so we can just return here.
32
+ return;
33
+ }
34
+ let errorMsg;
35
+ if (!err) {
36
+ errorMsg = 'Unexpected response from server (see below). Please contact Opal support if this issue persists.';
37
+ }
38
+ else if (typeof err === 'object' && err.toString().includes('self signed certificate')) {
39
+ errorMsg = 'Request failed due to a self-signed certificate appearing in the certificate chain. Try setting your CLI to allow self-signed certs by running: "opal set-url --custom INSERT_URL_HERE --allowSelfSignedCerts"';
40
+ }
41
+ else {
42
+ errorMsg = `Error: ${err}`;
43
+ }
44
+ errorMsg = '❗ ' + errorMsg;
45
+ command.log(errorMsg);
46
+ if (resp) {
47
+ exports.printResponse(command, resp);
48
+ }
49
+ // OPAL-6579: Use process.exit to avoid UnhandledPromiseRejectionWarning
50
+ // eslint-disable-next-line no-process-exit,unicorn/no-process-exit
51
+ process.exit(1);
52
+ };
20
53
  exports.initClient = async (command) => {
21
54
  const configDir = command.config.configDir;
22
55
  const currentCLIVersion = command.config.version;
@@ -98,6 +131,11 @@ exports.initClient = async (command) => {
98
131
  // to the login screen again.
99
132
  return;
100
133
  }
134
+ if (operation.operationName === login_1.CLISignInMethodName) {
135
+ // We have special handling for this operation due to the fact that the backend version
136
+ // can be out of date and not include the new cliClientId field.
137
+ return;
138
+ }
101
139
  if (networkError && 'statusCode' in networkError) {
102
140
  let errorMessage = null;
103
141
  if ('result' in networkError) {
@@ -122,8 +160,7 @@ exports.initClient = async (command) => {
122
160
  break;
123
161
  }
124
162
  default:
125
- command.log(`❗ Error: received status code ${networkError.statusCode} from server${errorMessage ? ` with message "${errorMessage}"` : ''}`);
126
- process.exit(networkError.statusCode);
163
+ return exports.handleError(command, `Received status code ${networkError.statusCode} from server${errorMessage ? ` with message "${errorMessage}"` : ''}`);
127
164
  }
128
165
  }
129
166
  });
@@ -135,40 +172,3 @@ exports.initClient = async (command) => {
135
172
  cache: new core_1.InMemoryCache(),
136
173
  });
137
174
  };
138
- exports.printResponse = (command, resp) => {
139
- const filteredJson = JSON.parse(JSON.stringify(resp.data, (k, v) => {
140
- if (k === '__typename') {
141
- return undefined;
142
- }
143
- if (v === null || (Array.isArray(v) && v.length === 0)) {
144
- return undefined;
145
- }
146
- return v;
147
- }));
148
- command.log(prettyjson_1.render(filteredJson));
149
- };
150
- exports.handleError = (command, err, resp) => {
151
- if (err && typeof err === 'object' && ('networkError' in err && 'statusCode' in err.networkError)) {
152
- // Status code errors are already handled in the global Apollo handler, so we can just return here.
153
- return;
154
- }
155
- let errorMsg;
156
- if (!err) {
157
- errorMsg = 'Unexpected response from server (see below). Please contact Opal support if this issue persists.';
158
- }
159
- else if (typeof err === 'string') {
160
- errorMsg = err;
161
- }
162
- else if (typeof err === 'object' && err.toString().includes('self signed certificate')) {
163
- errorMsg = 'Request failed due to a self-signed certificate appearing in the certificate chain. Try setting your CLI to allow self-signed certs by running: "opal set-url --custom INSERT_URL_HERE --allowSelfSignedCerts"';
164
- }
165
- else {
166
- errorMsg = `Error: ${err}`;
167
- }
168
- errorMsg = '❗ ' + errorMsg;
169
- command.log(errorMsg);
170
- if (resp) {
171
- exports.printResponse(command, resp);
172
- }
173
- command.exit(1);
174
- };
@@ -3,6 +3,7 @@ export declare const cred: {
3
3
  removeCredentials(after: number): Promise<void>;
4
4
  readonly accountId: Promise<string | undefined>;
5
5
  readonly organizationID: Promise<string | undefined>;
6
+ readonly clientIdCandidate: Promise<string | undefined>;
6
7
  readonly email: Promise<string | undefined>;
7
8
  readonly accessToken: Promise<string | undefined>;
8
9
  };
@@ -32,6 +32,20 @@ exports.cred = {
32
32
  if (!parts || parts.length <= 1) {
33
33
  return undefined;
34
34
  }
35
+ return parts[1];
36
+ })();
37
+ },
38
+ get clientIdCandidate() {
39
+ return (async () => {
40
+ const keyContents = await keytar.findCredentials(exports.OPAL_CREDS_KEY);
41
+ if (!keyContents[0]) {
42
+ return undefined;
43
+ }
44
+ const { account } = keyContents[0];
45
+ const parts = account.split('|');
46
+ if (!parts || parts.length <= 2) {
47
+ return undefined;
48
+ }
35
49
  return parts.pop();
36
50
  })();
37
51
  },
@@ -0,0 +1,8 @@
1
+ import { flags } from '@oclif/command';
2
+ export declare const SHARED_FLAGS: {
3
+ help: import("@oclif/parser/lib/flags").IBooleanFlag<void>;
4
+ id: flags.IOptionFlag<string | undefined>;
5
+ accessLevelRemoteId: flags.IOptionFlag<string | undefined>;
6
+ sessionId: flags.IOptionFlag<string | undefined>;
7
+ refresh: import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
8
+ };
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SHARED_FLAGS = void 0;
4
+ const command_1 = require("@oclif/command");
5
+ exports.SHARED_FLAGS = {
6
+ help: command_1.flags.help({ char: 'h' }),
7
+ id: command_1.flags.string({
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]',
11
+ }),
12
+ accessLevelRemoteId: command_1.flags.string({
13
+ multiple: false,
14
+ char: 'a',
15
+ description: 'The remote ID of the access level with which to access the resource.',
16
+ }),
17
+ sessionId: command_1.flags.string({
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.',
21
+ }),
22
+ refresh: command_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.',
25
+ }),
26
+ };