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.
- package/README.md +91 -48
- package/lib/commands/aws/identity.js +2 -1
- package/lib/commands/curl-example.js +2 -1
- package/lib/commands/iam-roles/start.d.ts +1 -0
- package/lib/commands/iam-roles/start.js +9 -10
- package/lib/commands/kube-roles/start.d.ts +5 -4
- package/lib/commands/kube-roles/start.js +10 -14
- package/lib/commands/login.d.ts +1 -0
- package/lib/commands/login.js +63 -16
- package/lib/commands/logout.js +2 -1
- package/lib/commands/postgres-instances/start.d.ts +2 -0
- package/lib/commands/postgres-instances/start.js +49 -41
- package/lib/commands/resources/get.d.ts +2 -2
- package/lib/commands/resources/get.js +3 -5
- package/lib/commands/set-custom-header.js +2 -1
- package/lib/commands/set-token.js +2 -1
- package/lib/commands/set-url.js +4 -2
- package/lib/commands/ssh/copyFrom.js +7 -12
- package/lib/commands/ssh/copyTo.js +7 -12
- package/lib/commands/ssh/start.d.ts +4 -3
- package/lib/commands/ssh/start.js +9 -10
- package/lib/lib/apollo.d.ts +1 -1
- package/lib/lib/apollo.js +43 -43
- package/lib/lib/credentials.d.ts +1 -0
- package/lib/lib/credentials.js +14 -0
- package/lib/lib/flags.d.ts +8 -0
- package/lib/lib/flags.js +26 -0
- package/lib/lib/resources.js +3 -3
- package/lib/lib/sessions.d.ts +1 -1
- package/lib/lib/sessions.js +28 -17
- package/lib/types.d.ts +1 -0
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- /package/lib/lib/{common.d.ts → util.d.ts} +0 -0
- /package/lib/lib/{common.js → util.js} +0 -0
package/lib/commands/logout.js
CHANGED
|
@@ -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:
|
|
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
|
|
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
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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 (
|
|
67
|
-
case
|
|
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
|
|
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
|
-
|
|
91
|
+
util_1.displayContent(content);
|
|
83
92
|
break;
|
|
84
93
|
}
|
|
85
|
-
case
|
|
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
|
|
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
|
|
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:
|
|
107
|
-
id:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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: '
|
|
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
|
|
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:
|
|
62
|
-
id:
|
|
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:
|
|
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:
|
|
57
|
+
help: flags_1.SHARED_FLAGS.help,
|
|
57
58
|
};
|
|
58
59
|
SetToken.args = [];
|
package/lib/commands/set-url.js
CHANGED
|
@@ -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:
|
|
66
|
+
help: flags_1.SHARED_FLAGS.help,
|
|
66
67
|
allowSelfSignedCerts: command_1.flags.boolean(),
|
|
67
|
-
//
|
|
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:
|
|
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
|
|
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: '
|
|
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: '
|
|
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:
|
|
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
|
|
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: '
|
|
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: '
|
|
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
|
|
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:
|
|
86
|
-
id:
|
|
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:
|
|
97
|
-
|
|
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
|
};
|
package/lib/lib/apollo.d.ts
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
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
|
-
};
|
package/lib/lib/credentials.d.ts
CHANGED
|
@@ -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
|
};
|
package/lib/lib/credentials.js
CHANGED
|
@@ -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
|
+
};
|
package/lib/lib/flags.js
ADDED
|
@@ -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
|
+
};
|