opal-security 2.3.4 → 3.0.1-beta.4262451
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 +67 -38
- package/lib/commands/aws/identity.d.ts +1 -1
- package/lib/commands/aws/identity.js +2 -2
- package/lib/commands/{migrate-creds.d.ts → clear-auth-provider.d.ts} +3 -2
- package/lib/commands/clear-auth-provider.js +28 -0
- package/lib/commands/curl-example.d.ts +1 -1
- package/lib/commands/curl-example.js +10 -3
- package/lib/commands/iam-roles/start.d.ts +1 -1
- package/lib/commands/iam-roles/start.js +14 -14
- package/lib/commands/kube-roles/start.d.ts +1 -1
- package/lib/commands/kube-roles/start.js +10 -10
- package/lib/commands/login.d.ts +2 -1
- package/lib/commands/login.js +134 -74
- package/lib/commands/logout.d.ts +1 -1
- package/lib/commands/logout.js +3 -3
- package/lib/commands/postgres-instances/start.d.ts +1 -1
- package/lib/commands/postgres-instances/start.js +35 -34
- package/lib/commands/resources/get.d.ts +1 -1
- package/lib/commands/resources/get.js +6 -4
- package/lib/commands/set-auth-provider.d.ts +11 -0
- package/lib/commands/set-auth-provider.js +44 -0
- package/lib/commands/set-custom-header.d.ts +1 -1
- package/lib/commands/set-custom-header.js +5 -3
- package/lib/commands/set-token.d.ts +1 -1
- package/lib/commands/set-token.js +26 -19
- package/lib/commands/set-url.d.ts +1 -1
- package/lib/commands/set-url.js +13 -12
- package/lib/commands/ssh/copyFrom.d.ts +1 -1
- package/lib/commands/ssh/copyFrom.js +13 -13
- package/lib/commands/ssh/copyTo.d.ts +1 -1
- package/lib/commands/ssh/copyTo.js +13 -13
- package/lib/commands/ssh/start.d.ts +1 -1
- package/lib/commands/ssh/start.js +14 -15
- package/lib/graphql/fragment-masking.d.ts +19 -0
- package/lib/graphql/fragment-masking.js +21 -0
- package/lib/graphql/gql.d.ts +36 -0
- package/lib/graphql/gql.js +12 -0
- package/lib/graphql/graphql.d.ts +11413 -0
- package/lib/graphql/graphql.js +1491 -0
- package/lib/graphql/index.d.ts +2 -0
- package/lib/graphql/index.js +5 -0
- package/lib/handler.d.ts +5 -5
- package/lib/handler.js +7 -7
- package/lib/index.d.ts +1 -1
- package/lib/lib/apollo.d.ts +4 -2
- package/lib/lib/apollo.js +107 -55
- package/lib/lib/aws.js +15 -12
- package/lib/lib/cmd.d.ts +4 -6
- package/lib/lib/cmd.js +11 -11
- package/lib/lib/config.js +14 -15
- package/lib/lib/credentials/index.d.ts +9 -4
- package/lib/lib/credentials/index.js +26 -15
- package/lib/lib/credentials/keychain.d.ts +3 -3
- package/lib/lib/credentials/keychain.js +12 -12
- package/lib/lib/credentials/localEncryption.d.ts +3 -3
- package/lib/lib/credentials/localEncryption.js +40 -31
- package/lib/lib/flags.js +9 -9
- package/lib/lib/resources.d.ts +2 -2
- package/lib/lib/resources.js +29 -23
- package/lib/lib/sessions.d.ts +2 -2
- package/lib/lib/sessions.js +18 -17
- package/lib/lib/ssh.d.ts +1 -1
- package/lib/lib/ssh.js +8 -8
- package/lib/lib/util.d.ts +0 -1
- package/lib/lib/util.js +13 -13
- package/lib/types.d.ts +1787 -1787
- package/oclif.manifest.json +56 -7
- package/package.json +23 -29
- package/lib/commands/migrate-creds.js +0 -48
package/lib/commands/login.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CLIAuthSessionCheckDocument = exports.CLIAuthSessionCheckName = exports.CLISignInMethodName = void 0;
|
|
3
|
+
exports.CLITokenExchangeName = exports.CLIAuthSessionCheckDocument = exports.CLIAuthSessionCheckName = exports.CLISignInMethodName = void 0;
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
5
|
const open = require("open");
|
|
6
6
|
const openid_client_1 = require("openid-client");
|
|
7
|
-
const apollo_1 = require("../lib/apollo");
|
|
8
|
-
const credentials_1 = require("../lib/credentials");
|
|
9
7
|
const inquirer = require("inquirer");
|
|
10
8
|
const handler_1 = require("../handler");
|
|
9
|
+
const apollo_1 = require("../lib/apollo");
|
|
11
10
|
const config_1 = require("../lib/config");
|
|
12
|
-
const
|
|
11
|
+
const credentials_1 = require("../lib/credentials");
|
|
13
12
|
const flags_1 = require("../lib/flags");
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
13
|
+
const util_1 = require("../lib/util");
|
|
14
|
+
const ISSUER_PROD = "https://auth.opal.dev";
|
|
15
|
+
const ISSUER_DEV = "https://authdev.opal.dev";
|
|
16
|
+
const GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
17
|
+
const CLIENT_ID_PROD = "42rm6E5v7o67LBpRfjdT9KhnjrQHr9UF";
|
|
18
|
+
const CLIENT_ID_DEV = "XYV8qoAvZG7dHnhRp2g5XMJ1zX9fBP6s";
|
|
19
19
|
const CLISignInMethodDocumentLegacy = `
|
|
20
20
|
query CLISignInMethod($input: SignInMethodInput!) {
|
|
21
21
|
signInMethod(input: $input) {
|
|
@@ -28,7 +28,7 @@ query CLISignInMethod($input: SignInMethodInput!) {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
}`;
|
|
31
|
-
exports.CLISignInMethodName =
|
|
31
|
+
exports.CLISignInMethodName = "CLISignInMethod";
|
|
32
32
|
const CLISignInMethodDocument = `
|
|
33
33
|
query CLISignInMethod($input: SignInMethodInput!) {
|
|
34
34
|
signInMethod(input: $input) {
|
|
@@ -42,7 +42,7 @@ query CLISignInMethod($input: SignInMethodInput!) {
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
}`;
|
|
45
|
-
exports.CLIAuthSessionCheckName =
|
|
45
|
+
exports.CLIAuthSessionCheckName = "CLIAuthSessionCheck";
|
|
46
46
|
exports.CLIAuthSessionCheckDocument = `
|
|
47
47
|
query CLIAuthSessionCheck {
|
|
48
48
|
organizationSettings {
|
|
@@ -54,6 +54,30 @@ query CLIAuthSessionCheck {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
`;
|
|
57
|
+
const SignInDocument = `
|
|
58
|
+
mutation SignIn($input: SignInInput!) {
|
|
59
|
+
signIn(input: $input) {
|
|
60
|
+
__typename
|
|
61
|
+
... on SignInResult {
|
|
62
|
+
state
|
|
63
|
+
forceExtraStep
|
|
64
|
+
authURL
|
|
65
|
+
__typename
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
`;
|
|
70
|
+
exports.CLITokenExchangeName = "CLITokenExchange";
|
|
71
|
+
const CLITokenExchangeDocument = `
|
|
72
|
+
mutation CLITokenExchange($input: CLITokenExchangeInput!) {
|
|
73
|
+
cliTokenExchange(input: $input) {
|
|
74
|
+
__typename
|
|
75
|
+
... on CLITokenExchangeOutput {
|
|
76
|
+
sessionID
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
`;
|
|
57
81
|
class Login extends core_1.Command {
|
|
58
82
|
async run() {
|
|
59
83
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
@@ -63,75 +87,84 @@ class Login extends core_1.Command {
|
|
|
63
87
|
const configDir = this.config.configDir;
|
|
64
88
|
const configData = (0, config_1.getOrCreateConfigData)(configDir);
|
|
65
89
|
let email = flags.email;
|
|
66
|
-
let
|
|
67
|
-
let
|
|
90
|
+
let organizationId;
|
|
91
|
+
let clientIDCandidate;
|
|
68
92
|
const existingCreds = await (0, credentials_1.getOpalCredentials)(this, false);
|
|
69
93
|
// Only use the previous email + organizationID if email isn't explicitly specified.
|
|
70
94
|
if (!email) {
|
|
71
95
|
email = existingCreds.email;
|
|
72
|
-
|
|
73
|
-
|
|
96
|
+
organizationId = existingCreds.organizationID;
|
|
97
|
+
clientIDCandidate = existingCreds.clientIDCandidate;
|
|
74
98
|
}
|
|
75
99
|
await (0, credentials_1.removeOpalCredentials)(this);
|
|
76
|
-
this.log(
|
|
77
|
-
this.log(
|
|
78
|
-
this.log(
|
|
100
|
+
this.log("Welcome to Opal! ⚡\n");
|
|
101
|
+
this.log("Connecting to Opal server URL:", configData[config_1.urlKey]);
|
|
102
|
+
this.log("If this is incorrect, please run `opal set-url --help`\n");
|
|
79
103
|
if (email) {
|
|
80
|
-
this.log(
|
|
104
|
+
this.log(`Signing in as: ${email} - to use a different account, run \`opal login --email [EMAIL]\``);
|
|
81
105
|
}
|
|
82
106
|
else {
|
|
83
|
-
const { email: promptEmail } = await inquirer.prompt([
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
107
|
+
const { email: promptEmail } = await inquirer.prompt([
|
|
108
|
+
{
|
|
109
|
+
name: "email",
|
|
110
|
+
message: "Enter your email:",
|
|
111
|
+
type: "input",
|
|
112
|
+
validate: (email) => Boolean(email),
|
|
113
|
+
},
|
|
114
|
+
]);
|
|
89
115
|
email = promptEmail;
|
|
90
116
|
}
|
|
91
|
-
if (!
|
|
117
|
+
if (!organizationId) {
|
|
92
118
|
let signInOrganizationsLegacyResponse;
|
|
93
|
-
const { resp: signInOrganizationsResponse, error } = await (0, handler_1.
|
|
119
|
+
const { resp: signInOrganizationsResponse, error } = await (0, handler_1.runQueryDeprecated)({
|
|
94
120
|
command: this,
|
|
95
121
|
query: CLISignInMethodDocument,
|
|
96
122
|
variables: { input: { email } },
|
|
97
123
|
});
|
|
98
|
-
if (error
|
|
99
|
-
if (
|
|
100
|
-
|
|
124
|
+
if (error === null || error === void 0 ? void 0 : error.networkError) {
|
|
125
|
+
if ("statusCode" in error.networkError &&
|
|
126
|
+
error.networkError.statusCode === 422) {
|
|
127
|
+
const { resp, error: legacyError } = await (0, handler_1.runQueryDeprecated)({
|
|
101
128
|
command: this,
|
|
102
129
|
query: CLISignInMethodDocumentLegacy,
|
|
103
130
|
variables: { input: { email } },
|
|
104
131
|
});
|
|
105
132
|
signInOrganizationsLegacyResponse = resp;
|
|
106
133
|
if (legacyError) {
|
|
107
|
-
this.log(
|
|
108
|
-
return (0, apollo_1.handleError)(this,
|
|
134
|
+
this.log(""); // Intentional newline
|
|
135
|
+
return (0, apollo_1.handleError)(this, "Could not connect to Opal. Did you set the right URL? (`opal set-url --help`)");
|
|
109
136
|
}
|
|
110
137
|
}
|
|
111
138
|
else {
|
|
112
|
-
this.log(
|
|
113
|
-
return (0, apollo_1.handleError)(this,
|
|
139
|
+
this.log(""); // Intentional newline
|
|
140
|
+
return (0, apollo_1.handleError)(this, "Could not connect to Opal. Did you set the right URL? (`opal set-url --help`)");
|
|
114
141
|
}
|
|
115
142
|
}
|
|
116
|
-
const signInOrganizations =
|
|
117
|
-
|
|
143
|
+
const signInOrganizations = ((_a = signInOrganizationsResponse === null || signInOrganizationsResponse === void 0 ? void 0 : signInOrganizationsResponse.data.signInMethod) === null || _a === void 0 ? void 0 : _a.__typename) ===
|
|
144
|
+
"SignInMethodResult"
|
|
145
|
+
? signInOrganizationsResponse.data.signInMethod.signInOrganizations
|
|
146
|
+
: ((_b = signInOrganizationsLegacyResponse === null || signInOrganizationsLegacyResponse === void 0 ? void 0 : signInOrganizationsLegacyResponse.data.signInMethod) === null || _b === void 0 ? void 0 : _b.__typename) === "SignInMethodResult"
|
|
147
|
+
? (_c = signInOrganizationsLegacyResponse === null || signInOrganizationsLegacyResponse === void 0 ? void 0 : signInOrganizationsLegacyResponse.data.signInMethod) === null || _c === void 0 ? void 0 : _c.signInOrganizations
|
|
148
|
+
: undefined;
|
|
118
149
|
if (signInOrganizations && signInOrganizations.length > 0) {
|
|
119
150
|
if (signInOrganizations.length === 1) {
|
|
120
|
-
|
|
121
|
-
|
|
151
|
+
organizationId = signInOrganizations[0].organizationId;
|
|
152
|
+
clientIDCandidate = signInOrganizations[0].cliClientId;
|
|
122
153
|
}
|
|
123
154
|
else {
|
|
124
|
-
const responses = await inquirer.prompt([
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
155
|
+
const responses = await inquirer.prompt([
|
|
156
|
+
{
|
|
157
|
+
name: "signInOrganization",
|
|
158
|
+
message: "Select an organization:",
|
|
159
|
+
type: "list",
|
|
160
|
+
choices: signInOrganizations.map((signInOrganization) => ({
|
|
129
161
|
name: signInOrganization.organizationName,
|
|
130
162
|
value: signInOrganization,
|
|
131
163
|
})),
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
164
|
+
},
|
|
165
|
+
]);
|
|
166
|
+
organizationId = responses.signInOrganization.organizationId;
|
|
167
|
+
clientIDCandidate = responses.signInOrganization.cliClientId;
|
|
135
168
|
}
|
|
136
169
|
}
|
|
137
170
|
else {
|
|
@@ -139,76 +172,103 @@ class Login extends core_1.Command {
|
|
|
139
172
|
// which is parity with our web app.
|
|
140
173
|
}
|
|
141
174
|
}
|
|
175
|
+
const { resp: signInResp } = await (0, handler_1.runMutation)({
|
|
176
|
+
command: this,
|
|
177
|
+
query: SignInDocument,
|
|
178
|
+
variables: {
|
|
179
|
+
input: { organizationId },
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
const state = (_d = signInResp === null || signInResp === void 0 ? void 0 : signInResp.data.signIn) === null || _d === void 0 ? void 0 : _d.state;
|
|
142
183
|
let issuer;
|
|
143
|
-
if
|
|
184
|
+
// issuerURL may come from configData if set by set-airgap-auth
|
|
185
|
+
if (configData.issuerURL) {
|
|
186
|
+
issuer = await openid_client_1.Issuer.discover(configData.issuerURL);
|
|
187
|
+
}
|
|
188
|
+
else if ((0, config_1.isProduction)(this.config.configDir)) {
|
|
144
189
|
issuer = await openid_client_1.Issuer.discover(ISSUER_PROD);
|
|
145
190
|
}
|
|
146
191
|
else {
|
|
147
192
|
issuer = await openid_client_1.Issuer.discover(ISSUER_DEV);
|
|
148
193
|
}
|
|
149
|
-
let
|
|
150
|
-
if (
|
|
151
|
-
|
|
194
|
+
let clientID;
|
|
195
|
+
if (clientIDCandidate) {
|
|
196
|
+
// clientIdCandidate gets stored in creds, and is mostly relevant for on-prem envs using Auth0 and SAML
|
|
197
|
+
clientID = clientIDCandidate;
|
|
198
|
+
}
|
|
199
|
+
else if (configData.clientID) {
|
|
200
|
+
// clientID may come from configData if set by set-airgap-auth
|
|
201
|
+
clientID = configData.clientID;
|
|
152
202
|
}
|
|
153
203
|
else if ((0, config_1.isProduction)(this.config.configDir)) {
|
|
154
|
-
|
|
204
|
+
clientID = CLIENT_ID_PROD;
|
|
155
205
|
}
|
|
156
206
|
else {
|
|
157
|
-
|
|
207
|
+
clientID = CLIENT_ID_DEV;
|
|
158
208
|
}
|
|
159
|
-
/* eslint-disable camelcase */
|
|
160
209
|
const client = new issuer.Client({
|
|
161
210
|
grant_types: [GRANT_TYPE],
|
|
162
|
-
client_id:
|
|
211
|
+
client_id: clientID,
|
|
163
212
|
response_types: [],
|
|
164
213
|
redirect_uris: [],
|
|
165
|
-
token_endpoint_auth_method:
|
|
166
|
-
application_type:
|
|
214
|
+
token_endpoint_auth_method: "none",
|
|
215
|
+
application_type: "native",
|
|
167
216
|
});
|
|
168
|
-
/* eslint-enable camelcase */
|
|
169
217
|
const handle = await client.deviceAuthorization({
|
|
170
|
-
audience:
|
|
171
|
-
scope:
|
|
218
|
+
audience: "https://opal.dev",
|
|
219
|
+
scope: "openid email profile",
|
|
172
220
|
});
|
|
173
|
-
this.log(
|
|
221
|
+
this.log("\nYou are being redirected to your browser to authenticate.\n");
|
|
174
222
|
this.log(` User Code: ${handle.user_code}\n`);
|
|
175
223
|
// Wait before opening the browser window to ensure the user has time to
|
|
176
224
|
// see the User Code.
|
|
177
225
|
await (0, util_1.sleep)(1000);
|
|
178
226
|
await open(handle.verification_uri_complete, { wait: false });
|
|
179
227
|
const tokenSet = await handle.poll();
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
228
|
+
const { error: tokenExchangeError } = await (0, handler_1.runMutation)({
|
|
229
|
+
command: this,
|
|
230
|
+
query: CLITokenExchangeDocument,
|
|
231
|
+
variables: {
|
|
232
|
+
input: {
|
|
233
|
+
accessToken: tokenSet === null || tokenSet === void 0 ? void 0 : tokenSet.access_token,
|
|
234
|
+
state,
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
if (tokenExchangeError) {
|
|
239
|
+
this.log("WARN: Failed to exchange access token for session in Opal. Falling back to using access token for authenticating requests\n");
|
|
240
|
+
// TODO: consider adding a warn line recommending upgrading Opal to version XYZ, once accompanying PR is pushed to prod
|
|
241
|
+
await (0, credentials_1.setOpalCredentials)(this, email, organizationId !== null && organizationId !== void 0 ? organizationId : "", clientIDCandidate, (tokenSet === null || tokenSet === void 0 ? void 0 : tokenSet.access_token) || "", credentials_1.SecretType.ApiToken);
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
await (0, credentials_1.setOpalCredentials)(this, email, organizationId !== null && organizationId !== void 0 ? organizationId : "", clientIDCandidate, apollo_1.cookieStr, credentials_1.SecretType.Cookie);
|
|
185
245
|
}
|
|
186
|
-
await (0, credentials_1.setOpalCredentials)(this, userInfo.email, organizationID, clientIdCandidate, (tokenSet === null || tokenSet === void 0 ? void 0 : tokenSet.access_token) || '');
|
|
187
246
|
// "Representative" authenticated call to check the log-in worked as expected.
|
|
188
|
-
const { resp: authCheckResp, error: authCheckErr } = await (0, handler_1.
|
|
247
|
+
const { resp: authCheckResp, error: authCheckErr } = await (0, handler_1.runQueryDeprecated)({
|
|
189
248
|
command: this,
|
|
190
249
|
query: exports.CLIAuthSessionCheckDocument,
|
|
191
250
|
variables: {},
|
|
192
251
|
});
|
|
193
|
-
if (authCheckErr ||
|
|
194
|
-
|
|
252
|
+
if (authCheckErr ||
|
|
253
|
+
!((_g = (_f = (_e = authCheckResp === null || authCheckResp === void 0 ? void 0 : authCheckResp.data) === null || _e === void 0 ? void 0 : _e.organizationSettings) === null || _f === void 0 ? void 0 : _f.settings) === null || _g === void 0 ? void 0 : _g.id)) {
|
|
254
|
+
this.log("Error verifying log in. Authenticated commands may fail. Please double check your URL and use `opal logout; opal login` to try again.\n");
|
|
195
255
|
await (0, credentials_1.removeOpalCredentials)(this);
|
|
196
|
-
|
|
256
|
+
process.exit(1);
|
|
197
257
|
}
|
|
198
|
-
this.log(
|
|
258
|
+
this.log("🎉 You have successfully authenticated with Opal! You can now run authenticated commands.\n");
|
|
199
259
|
}
|
|
200
260
|
catch (error) {
|
|
201
261
|
this.error(error);
|
|
202
262
|
}
|
|
203
263
|
}
|
|
204
264
|
}
|
|
205
|
-
Login.description =
|
|
206
|
-
Login.examples = [
|
|
265
|
+
Login.description = "Authenticates you with the Opal server.";
|
|
266
|
+
Login.examples = ["$ opal login"];
|
|
207
267
|
Login.flags = {
|
|
208
268
|
help: flags_1.SHARED_FLAGS.help,
|
|
209
269
|
email: core_1.Flags.string({
|
|
210
270
|
multiple: false,
|
|
211
|
-
description:
|
|
271
|
+
description: "Email address to login with.",
|
|
212
272
|
}),
|
|
213
273
|
};
|
|
214
274
|
Login.args = {};
|
package/lib/commands/logout.d.ts
CHANGED
package/lib/commands/logout.js
CHANGED
|
@@ -7,15 +7,15 @@ class Logout extends core_1.Command {
|
|
|
7
7
|
async run() {
|
|
8
8
|
try {
|
|
9
9
|
await (0, credentials_1.removeOpalCredentials)(this);
|
|
10
|
-
this.log(
|
|
10
|
+
this.log("Successfully removed the saved Account ID and Auth Token from this computer");
|
|
11
11
|
}
|
|
12
12
|
catch (error) {
|
|
13
13
|
this.error(error);
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
-
Logout.description =
|
|
18
|
-
Logout.examples = [
|
|
17
|
+
Logout.description = "Clears locally stored Opal server authentication credentials.";
|
|
18
|
+
Logout.examples = ["$ opal logout"];
|
|
19
19
|
Logout.flags = {
|
|
20
20
|
help: flags_1.SHARED_FLAGS.help,
|
|
21
21
|
};
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
4
|
const inquirer = require("inquirer");
|
|
5
|
-
const cmd_1 = require("../../lib/cmd");
|
|
6
5
|
const apollo_1 = require("../../lib/apollo");
|
|
6
|
+
const cmd_1 = require("../../lib/cmd");
|
|
7
|
+
const flags_1 = require("../../lib/flags");
|
|
7
8
|
const resources_1 = require("../../lib/resources");
|
|
8
|
-
const util_1 = require("../../lib/util");
|
|
9
9
|
const sessions_1 = require("../../lib/sessions");
|
|
10
|
-
const
|
|
10
|
+
const util_1 = require("../../lib/util");
|
|
11
11
|
const RdsSessionMetadataFragment = `
|
|
12
12
|
... on AwsIamFederatedRdsSession {
|
|
13
13
|
dbUser
|
|
@@ -18,18 +18,18 @@ const RdsSessionMetadataFragment = `
|
|
|
18
18
|
}`;
|
|
19
19
|
const methodChoices = [
|
|
20
20
|
{
|
|
21
|
-
name:
|
|
22
|
-
value:
|
|
21
|
+
name: "Start psql session in shell",
|
|
22
|
+
value: "psql",
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
|
-
name:
|
|
26
|
-
value:
|
|
25
|
+
name: "View connection configuration details",
|
|
26
|
+
value: "view",
|
|
27
27
|
},
|
|
28
28
|
];
|
|
29
|
-
if (process.platform ===
|
|
29
|
+
if (process.platform === "darwin") {
|
|
30
30
|
methodChoices.unshift({
|
|
31
|
-
name:
|
|
32
|
-
value:
|
|
31
|
+
name: "Open external database app",
|
|
32
|
+
value: "open",
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
35
|
class StartPostgresInstanceSession extends core_1.Command {
|
|
@@ -37,21 +37,21 @@ class StartPostgresInstanceSession extends core_1.Command {
|
|
|
37
37
|
(0, cmd_1.setMostRecentCommand)(this);
|
|
38
38
|
const { flags } = await this.parse(StartPostgresInstanceSession);
|
|
39
39
|
if (flags.sessionId && flags.refresh) {
|
|
40
|
-
return (0, apollo_1.handleError)(this,
|
|
40
|
+
return (0, apollo_1.handleError)(this, "Cannot use both --sessionId and --refresh");
|
|
41
41
|
}
|
|
42
42
|
let instanceId = flags.id;
|
|
43
43
|
let instanceName = null;
|
|
44
44
|
const sessionId = flags.sessionId;
|
|
45
45
|
let action = flags.action;
|
|
46
46
|
if (!instanceId) {
|
|
47
|
-
const selectedInstance = await (0, resources_1.promptUserForResource)(this,
|
|
47
|
+
const selectedInstance = await (0, resources_1.promptUserForResource)(this, "AWS_RDS_POSTGRES_INSTANCE", "Select an RDS Postgres instance to connect to");
|
|
48
48
|
if (!selectedInstance) {
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
51
51
|
instanceId = selectedInstance.id;
|
|
52
52
|
instanceName = selectedInstance.name;
|
|
53
53
|
}
|
|
54
|
-
const accessLevel = await (0, resources_1.promptUserForAccessLevels)(this, instanceId,
|
|
54
|
+
const accessLevel = await (0, resources_1.promptUserForAccessLevels)(this, instanceId, "Postgres database", flags.accessLevelRemoteId);
|
|
55
55
|
if (!accessLevel) {
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
@@ -61,29 +61,31 @@ class StartPostgresInstanceSession extends core_1.Command {
|
|
|
61
61
|
}
|
|
62
62
|
const metadata = session.metadata;
|
|
63
63
|
switch (metadata === null || metadata === void 0 ? void 0 : metadata.__typename) {
|
|
64
|
-
case
|
|
64
|
+
case "AwsIamFederatedRdsSession": {
|
|
65
65
|
// Don't inform the user about RDS session expiration time, since RDS works differently.
|
|
66
66
|
// Opal RDS sessions expire after 15min because after that time they can no longer be used to connect.
|
|
67
67
|
// However, once connected, RDS sessions can be used for up to 12h.
|
|
68
68
|
// Since there's many options for how the user can use RDS credentials, it's unclear which expiration
|
|
69
69
|
// we want to show the user.
|
|
70
70
|
if (!action) {
|
|
71
|
-
const selectedMethodInfo = await inquirer.prompt([
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
const selectedMethodInfo = await inquirer.prompt([
|
|
72
|
+
{
|
|
73
|
+
name: "method",
|
|
74
|
+
message: "Select how to access the database",
|
|
75
|
+
type: "list",
|
|
75
76
|
choices: methodChoices,
|
|
76
|
-
}
|
|
77
|
+
},
|
|
78
|
+
]);
|
|
77
79
|
action = selectedMethodInfo.method;
|
|
78
80
|
}
|
|
79
81
|
const dbUrl = `postgresql://${metadata.dbUser}:${encodeURIComponent(metadata.dbPassword)}@${metadata.dbHostname}:${metadata.dbPort}/${metadata.dbName}`;
|
|
80
82
|
switch (action) {
|
|
81
|
-
case
|
|
82
|
-
|
|
83
|
-
(0, cmd_1.runCommandExec)(startSessionCmd, `Opened external app for ${instanceName ? `"${instanceName}" instance` :
|
|
83
|
+
case "open": {
|
|
84
|
+
const startSessionCmd = `open ${dbUrl}`;
|
|
85
|
+
(0, cmd_1.runCommandExec)(startSessionCmd, `Opened external app for ${instanceName ? `"${instanceName}" instance` : "instance"}`, `Failed to open external app for ${instanceName ? `"${instanceName}" instance` : "instance"}`);
|
|
84
86
|
break;
|
|
85
87
|
}
|
|
86
|
-
case
|
|
88
|
+
case "view": {
|
|
87
89
|
const contentParts = [
|
|
88
90
|
`[Connection URL]\n${dbUrl}`,
|
|
89
91
|
`[Hostname]\n${metadata.dbHostname}`,
|
|
@@ -92,13 +94,13 @@ class StartPostgresInstanceSession extends core_1.Command {
|
|
|
92
94
|
`[Password]\n${metadata.dbPassword}`,
|
|
93
95
|
`[Database]\n${metadata.dbName}`,
|
|
94
96
|
];
|
|
95
|
-
const content = contentParts.join(
|
|
97
|
+
const content = contentParts.join("\n\n");
|
|
96
98
|
(0, util_1.displayContent)(content);
|
|
97
99
|
break;
|
|
98
100
|
}
|
|
99
|
-
case
|
|
101
|
+
case "psql": {
|
|
100
102
|
const startSessionCmd = `psql ${dbUrl}`;
|
|
101
|
-
(0, cmd_1.startInteractiveShell)(startSessionCmd, `shell with psql session for ${instanceName ? `"${instanceName}" instance` :
|
|
103
|
+
(0, cmd_1.startInteractiveShell)(startSessionCmd, `shell with psql session for ${instanceName ? `"${instanceName}" instance` : "instance"}`);
|
|
102
104
|
break;
|
|
103
105
|
}
|
|
104
106
|
}
|
|
@@ -109,12 +111,12 @@ class StartPostgresInstanceSession extends core_1.Command {
|
|
|
109
111
|
}
|
|
110
112
|
}
|
|
111
113
|
}
|
|
112
|
-
StartPostgresInstanceSession.description =
|
|
114
|
+
StartPostgresInstanceSession.description = "Starts a session to connect to a Postgres database.";
|
|
113
115
|
StartPostgresInstanceSession.examples = [
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
"opal postgres-instances:start",
|
|
117
|
+
"opal postgres-instances:start --id 51f7176b-0464-4a6f-8369-e951e187b398",
|
|
118
|
+
"opal postgres-instances:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --accessLevelRemoteId fullaccess",
|
|
119
|
+
"opal postgres-instances:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --accessLevelRemoteId fullaccess --action view",
|
|
118
120
|
];
|
|
119
121
|
StartPostgresInstanceSession.flags = {
|
|
120
122
|
help: flags_1.SHARED_FLAGS.help,
|
|
@@ -124,9 +126,8 @@ StartPostgresInstanceSession.flags = {
|
|
|
124
126
|
refresh: flags_1.SHARED_FLAGS.refresh,
|
|
125
127
|
action: core_1.Flags.string({
|
|
126
128
|
multiple: false,
|
|
127
|
-
description:
|
|
128
|
-
|
|
129
|
-
options: methodChoices.map(c => c.value),
|
|
129
|
+
description: `Method of connecting to the database.\n${methodChoices.map((c) => `- ${c.value}: ${c.name}`).join("\n")}`,
|
|
130
|
+
options: methodChoices.map((c) => c.value),
|
|
130
131
|
}),
|
|
131
132
|
};
|
|
132
133
|
exports.default = StartPostgresInstanceSession;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Command } from
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
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;
|
|
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.GetResourceDocument = void 0;
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
5
|
const handler_1 = require("../../handler");
|
|
6
|
-
const cmd_1 = require("../../lib/cmd");
|
|
7
6
|
const apollo_1 = require("../../lib/apollo");
|
|
7
|
+
const cmd_1 = require("../../lib/cmd");
|
|
8
8
|
const flags_1 = require("../../lib/flags");
|
|
9
9
|
exports.GetResourceDocument = `
|
|
10
10
|
query GetResource($id: ResourceId!) {
|
|
@@ -44,7 +44,7 @@ class GetResource extends core_1.Command {
|
|
|
44
44
|
async run() {
|
|
45
45
|
(0, cmd_1.setMostRecentCommand)(this);
|
|
46
46
|
const { flags } = await this.parse(GetResource);
|
|
47
|
-
const { resp, error } = await (0, handler_1.
|
|
47
|
+
const { resp, error } = await (0, handler_1.runQueryDeprecated)({
|
|
48
48
|
command: this,
|
|
49
49
|
query: exports.GetResourceDocument,
|
|
50
50
|
variables: flags,
|
|
@@ -55,8 +55,10 @@ class GetResource extends core_1.Command {
|
|
|
55
55
|
(0, apollo_1.printResponse)(this, resp);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
GetResource.description =
|
|
59
|
-
GetResource.examples = [
|
|
58
|
+
GetResource.description = "Get resource info for a particular resource.";
|
|
59
|
+
GetResource.examples = [
|
|
60
|
+
"opal resources:get --id 54052a3e-5375-4392-aeaf-0c6c44c131d4",
|
|
61
|
+
];
|
|
60
62
|
GetResource.flags = {
|
|
61
63
|
help: flags_1.SHARED_FLAGS.help,
|
|
62
64
|
id: flags_1.SHARED_FLAGS.id,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
export default class SetAuthProvider extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
help: import("@oclif/core/lib/interfaces").BooleanFlag<void>;
|
|
7
|
+
clientID: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
8
|
+
issuerUrl: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
9
|
+
};
|
|
10
|
+
run(): Promise<void>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const config_1 = require("../lib/config");
|
|
5
|
+
const credentials_1 = require("../lib/credentials");
|
|
6
|
+
const flags_1 = require("../lib/flags");
|
|
7
|
+
class SetAuthProvider extends core_1.Command {
|
|
8
|
+
async run() {
|
|
9
|
+
try {
|
|
10
|
+
const { flags, args } = await this.parse(SetAuthProvider);
|
|
11
|
+
const configData = (0, config_1.getOrCreateConfigData)(this.config.configDir);
|
|
12
|
+
configData.issuerURL = flags.issuerUrl;
|
|
13
|
+
configData.clientID = flags.clientID;
|
|
14
|
+
(0, config_1.writeConfigData)(this.config.configDir, configData);
|
|
15
|
+
await (0, credentials_1.removeOpalCredentials)(this);
|
|
16
|
+
this.log("Client ID and Issuer URL updated");
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
this.error(error);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
SetAuthProvider.description = `Sets the Issuer URL and Client ID of the Auth Provider that the CLI will authenticate with.
|
|
24
|
+
Only use this if you are running a self-hosted, air-gapped instance of Opal that uses a custom Auth Provider.
|
|
25
|
+
|
|
26
|
+
Note - you will need an OIDC provider that supports the device_code grant.
|
|
27
|
+
`;
|
|
28
|
+
SetAuthProvider.examples = [
|
|
29
|
+
"$ opal set-auth-provider --clientID 1234asdf --issuerUrl https://auth.example.com",
|
|
30
|
+
];
|
|
31
|
+
SetAuthProvider.flags = {
|
|
32
|
+
help: flags_1.SHARED_FLAGS.help,
|
|
33
|
+
clientID: core_1.Flags.string({
|
|
34
|
+
multiple: false,
|
|
35
|
+
description: "Client ID of your Auth Provider",
|
|
36
|
+
required: true,
|
|
37
|
+
}),
|
|
38
|
+
issuerUrl: core_1.Flags.string({
|
|
39
|
+
multiple: false,
|
|
40
|
+
description: "Issuer URL of your Auth Provider",
|
|
41
|
+
required: true,
|
|
42
|
+
}),
|
|
43
|
+
};
|
|
44
|
+
exports.default = SetAuthProvider;
|