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/handler.d.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import type { ApolloError, OperationVariables } from "@apollo/client/core";
|
|
2
|
+
import type { Command } from "@oclif/core";
|
|
3
3
|
interface QueryHandlerProps<TVar = Record<string, any>> {
|
|
4
4
|
command: Command;
|
|
5
5
|
query: string;
|
|
6
6
|
variables?: TVar;
|
|
7
7
|
}
|
|
8
8
|
export declare const runMutation: ({ command, query, variables, }: QueryHandlerProps) => Promise<{
|
|
9
|
-
resp: import("@apollo/client/core").FetchResult<any> | null;
|
|
9
|
+
resp: import("@apollo/client/core").FetchResult<any> | null | undefined;
|
|
10
10
|
error: unknown;
|
|
11
11
|
}>;
|
|
12
|
-
export declare const
|
|
13
|
-
resp: import("@apollo/client/core").ApolloQueryResult<TResponse> | null;
|
|
12
|
+
export declare const runQueryDeprecated: <TResponse = any, TVar extends OperationVariables = Record<string, any>>({ command, query, variables, }: QueryHandlerProps<TVar>) => Promise<{
|
|
13
|
+
resp: import("@apollo/client/core").ApolloQueryResult<TResponse> | null | undefined;
|
|
14
14
|
error: ApolloError;
|
|
15
15
|
}>;
|
|
16
16
|
export {};
|
package/lib/handler.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.runQueryDeprecated = exports.runMutation = void 0;
|
|
4
4
|
const graphql_tag_1 = require("graphql-tag");
|
|
5
5
|
const apollo_1 = require("./lib/apollo");
|
|
6
6
|
const runMutation = async ({ command, query, variables, }) => {
|
|
@@ -8,12 +8,12 @@ const runMutation = async ({ command, query, variables, }) => {
|
|
|
8
8
|
let mutationResp = null;
|
|
9
9
|
let mutationError = null;
|
|
10
10
|
try {
|
|
11
|
-
mutationResp = await apollo_1.client.mutate({
|
|
11
|
+
mutationResp = await (apollo_1.client === null || apollo_1.client === void 0 ? void 0 : apollo_1.client.mutate({
|
|
12
12
|
mutation: (0, graphql_tag_1.default) `
|
|
13
13
|
${query}
|
|
14
14
|
`,
|
|
15
15
|
variables: variables,
|
|
16
|
-
});
|
|
16
|
+
}));
|
|
17
17
|
}
|
|
18
18
|
catch (error) {
|
|
19
19
|
mutationError = error;
|
|
@@ -21,21 +21,21 @@ const runMutation = async ({ command, query, variables, }) => {
|
|
|
21
21
|
return { resp: mutationResp, error: mutationError };
|
|
22
22
|
};
|
|
23
23
|
exports.runMutation = runMutation;
|
|
24
|
-
const
|
|
24
|
+
const runQueryDeprecated = async ({ command, query, variables, }) => {
|
|
25
25
|
await (0, apollo_1.initClient)(command);
|
|
26
26
|
let queryResp = null;
|
|
27
27
|
let queryError = null;
|
|
28
28
|
try {
|
|
29
|
-
queryResp = await apollo_1.client.query({
|
|
29
|
+
queryResp = await (apollo_1.client === null || apollo_1.client === void 0 ? void 0 : apollo_1.client.query({
|
|
30
30
|
query: (0, graphql_tag_1.default) `
|
|
31
31
|
${query}
|
|
32
32
|
`,
|
|
33
33
|
variables: variables,
|
|
34
|
-
});
|
|
34
|
+
}));
|
|
35
35
|
}
|
|
36
36
|
catch (error) {
|
|
37
37
|
queryError = error;
|
|
38
38
|
}
|
|
39
39
|
return { resp: queryResp, error: queryError };
|
|
40
40
|
};
|
|
41
|
-
exports.
|
|
41
|
+
exports.runQueryDeprecated = runQueryDeprecated;
|
package/lib/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { run } from
|
|
1
|
+
export { run } from "@oclif/core";
|
package/lib/lib/apollo.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { ApolloClient, NormalizedCacheObject } from
|
|
2
|
-
import { Command } from
|
|
1
|
+
import { ApolloClient, type NormalizedCacheObject } from "@apollo/client/core";
|
|
2
|
+
import type { Command } from "@oclif/core";
|
|
3
3
|
export declare let client: ApolloClient<NormalizedCacheObject> | null;
|
|
4
|
+
export declare let cookieStr: string;
|
|
4
5
|
export declare const printResponse: (command: Command, resp: any) => void;
|
|
5
6
|
export declare const handleError: (command: Command, err: any, resp?: any) => void;
|
|
6
7
|
export declare const initClient: (command: Command, fetchAccessToken?: boolean) => Promise<void>;
|
|
8
|
+
export declare function getClient(command: Command, fetchAccessToken?: boolean): Promise<ApolloClient<NormalizedCacheObject>>;
|
package/lib/lib/apollo.js
CHANGED
|
@@ -1,25 +1,32 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.initClient = exports.handleError = exports.printResponse = exports.client = void 0;
|
|
3
|
+
exports.initClient = exports.handleError = exports.printResponse = exports.cookieStr = exports.client = void 0;
|
|
4
|
+
exports.getClient = getClient;
|
|
4
5
|
const core_1 = require("@apollo/client/core");
|
|
5
6
|
const context_1 = require("@apollo/client/link/context");
|
|
6
7
|
const error_1 = require("@apollo/client/link/error");
|
|
7
|
-
const prettyjson_1 = require("prettyjson");
|
|
8
|
-
const semver_1 = require("semver");
|
|
9
8
|
const chalk_1 = require("chalk");
|
|
10
9
|
const moment = require("moment");
|
|
11
|
-
const
|
|
12
|
-
const
|
|
10
|
+
const prettyjson_1 = require("prettyjson");
|
|
11
|
+
const semver_1 = require("semver");
|
|
12
|
+
const globals_1 = require("@apollo/client/utilities/globals");
|
|
13
13
|
const login_1 = require("../commands/login");
|
|
14
14
|
const cmd_1 = require("../lib/cmd");
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
15
|
+
const config_1 = require("../lib/config");
|
|
16
|
+
const credentials_1 = require("../lib/credentials");
|
|
17
|
+
const fetch = require("node-fetch");
|
|
18
|
+
const https = require("node:https");
|
|
19
|
+
const http = require("node:http");
|
|
20
|
+
// DO NOT USE DIRECTLY, use getClient instead
|
|
18
21
|
exports.client = null;
|
|
19
|
-
|
|
22
|
+
// This is used to keep track of the auth-session cookie during login, before we can persist it into the credential store
|
|
23
|
+
exports.cookieStr = "";
|
|
24
|
+
let alreadyWarnedAboutVersion = false;
|
|
20
25
|
const printResponse = (command, resp) => {
|
|
21
26
|
const filteredJson = JSON.parse(JSON.stringify(resp.data, (k, v) => {
|
|
22
|
-
if (k ===
|
|
27
|
+
if (k === "__typename" ||
|
|
28
|
+
v === null ||
|
|
29
|
+
(Array.isArray(v) && v.length === 0)) {
|
|
23
30
|
return undefined;
|
|
24
31
|
}
|
|
25
32
|
return v;
|
|
@@ -28,27 +35,32 @@ const printResponse = (command, resp) => {
|
|
|
28
35
|
};
|
|
29
36
|
exports.printResponse = printResponse;
|
|
30
37
|
const handleError = (command, err, resp) => {
|
|
31
|
-
if (err &&
|
|
38
|
+
if (err &&
|
|
39
|
+
typeof err === "object" &&
|
|
40
|
+
"networkError" in err &&
|
|
41
|
+
"statusCode" in err.networkError) {
|
|
32
42
|
// Status code errors are already handled in the global Apollo handler, so we can just return here.
|
|
33
43
|
return;
|
|
34
44
|
}
|
|
35
45
|
let errorMsg;
|
|
36
46
|
if (!err) {
|
|
37
|
-
errorMsg =
|
|
47
|
+
errorMsg =
|
|
48
|
+
"Unexpected response from server (see below). Please contact Opal support if this issue persists.";
|
|
38
49
|
}
|
|
39
|
-
else if (typeof err ===
|
|
40
|
-
|
|
50
|
+
else if (typeof err === "object" &&
|
|
51
|
+
err.toString().includes("self signed certificate")) {
|
|
52
|
+
errorMsg =
|
|
53
|
+
'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"';
|
|
41
54
|
}
|
|
42
55
|
else {
|
|
43
56
|
errorMsg = `Error: ${err}`;
|
|
44
57
|
}
|
|
45
|
-
errorMsg =
|
|
58
|
+
errorMsg = `❗ ${errorMsg}`;
|
|
46
59
|
command.log(errorMsg);
|
|
47
60
|
if (resp) {
|
|
48
61
|
(0, exports.printResponse)(command, resp);
|
|
49
62
|
}
|
|
50
63
|
// OPAL-6579: Use process.exit to avoid UnhandledPromiseRejectionWarning
|
|
51
|
-
// eslint-disable-next-line no-process-exit,unicorn/no-process-exit
|
|
52
64
|
process.exit(1);
|
|
53
65
|
};
|
|
54
66
|
exports.handleError = handleError;
|
|
@@ -57,7 +69,6 @@ const initClient = async (command, fetchAccessToken = true) => {
|
|
|
57
69
|
const currentCLIVersion = command.config.version;
|
|
58
70
|
const configData = (0, config_1.getOrCreateConfigData)(configDir);
|
|
59
71
|
const opalCreds = await (0, credentials_1.getOpalCredentials)(command, fetchAccessToken);
|
|
60
|
-
const accessToken = opalCreds === null || opalCreds === void 0 ? void 0 : opalCreds.accessToken;
|
|
61
72
|
const organizationID = opalCreds === null || opalCreds === void 0 ? void 0 : opalCreds.organizationID;
|
|
62
73
|
const httpsAgent = new https.Agent({
|
|
63
74
|
rejectUnauthorized: !configData[config_1.allowSelfSignedCertsKey],
|
|
@@ -65,22 +76,26 @@ const initClient = async (command, fetchAccessToken = true) => {
|
|
|
65
76
|
const httpAgent = new http.Agent({});
|
|
66
77
|
const specifiedUrl = configData[config_1.urlKey];
|
|
67
78
|
const customHeader = configData[config_1.customHttpHeaderKey];
|
|
68
|
-
const customHeaderKey = customHeader === undefined ?
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const customHeaderValue = customHeader === undefined ?
|
|
72
|
-
'' :
|
|
73
|
-
customHeader.split(':')[1];
|
|
74
|
-
const agent = specifiedUrl.includes('https') ? httpsAgent : httpAgent;
|
|
79
|
+
const customHeaderKey = customHeader === undefined ? "" : customHeader.split(":")[0];
|
|
80
|
+
const customHeaderValue = customHeader === undefined ? "" : customHeader.split(":")[1];
|
|
81
|
+
const agent = specifiedUrl.includes("https") ? httpsAgent : httpAgent;
|
|
75
82
|
const httpLink = (0, core_1.createHttpLink)({
|
|
76
83
|
uri: `${specifiedUrl}/query`,
|
|
84
|
+
credentials: "include",
|
|
77
85
|
fetch,
|
|
78
86
|
fetchOptions: {
|
|
79
87
|
agent: agent,
|
|
88
|
+
credentials: "include",
|
|
80
89
|
},
|
|
81
90
|
});
|
|
82
91
|
const authLink = (0, context_1.setContext)((_, { headers }) => {
|
|
83
|
-
const baseHeaders = Object.assign(Object.assign({}, headers), {
|
|
92
|
+
const baseHeaders = Object.assign(Object.assign({}, headers), { "User-Agent": `Opal CLI v${currentCLIVersion}`, "X-Opal-Organization-ID": organizationID, "X-Opal-Cli-Version": currentCLIVersion });
|
|
93
|
+
if (opalCreds.secretType === credentials_1.SecretType.ApiToken) {
|
|
94
|
+
baseHeaders.authorization = `Bearer ${opalCreds.secret}`;
|
|
95
|
+
}
|
|
96
|
+
else if (!!opalCreds.secret || !!exports.cookieStr) {
|
|
97
|
+
baseHeaders.cookie = opalCreds.secret || exports.cookieStr;
|
|
98
|
+
}
|
|
84
99
|
if (customHeaderKey) {
|
|
85
100
|
return {
|
|
86
101
|
headers: Object.assign(Object.assign({}, baseHeaders), { [customHeaderKey]: customHeaderValue }),
|
|
@@ -90,58 +105,75 @@ const initClient = async (command, fetchAccessToken = true) => {
|
|
|
90
105
|
headers: Object.assign({}, baseHeaders),
|
|
91
106
|
};
|
|
92
107
|
});
|
|
108
|
+
/**
|
|
109
|
+
* How this check actually works:
|
|
110
|
+
* - no hard fails throughout, just warns
|
|
111
|
+
* - Looks for an 'expected CLI major version' header from the backend, and:
|
|
112
|
+
* - if CLI version is < that, warns you need to upgrade CLI
|
|
113
|
+
* - if CLI version is > that, warns you need to upgrade Opal
|
|
114
|
+
* - also, if there's a 'recommended version' header and CLI version is less, just suggests that you upgrade your CLI
|
|
115
|
+
* - note the backend does not currently send this header)
|
|
116
|
+
*/
|
|
93
117
|
const checkCLIVersion = (operation) => {
|
|
94
118
|
var _a;
|
|
95
119
|
const headers = (_a = operation.getContext().response) === null || _a === void 0 ? void 0 : _a.headers;
|
|
96
|
-
if (headers) {
|
|
97
|
-
|
|
98
|
-
|
|
120
|
+
if (!alreadyWarnedAboutVersion && headers) {
|
|
121
|
+
// we expect these versions to be a single number - a major version
|
|
122
|
+
const expectedCLIMajorVersion = headers.get("Opal-CLI-Expected-Major-Version");
|
|
123
|
+
if (expectedCLIMajorVersion === null || expectedCLIMajorVersion === void 0 ? void 0 : expectedCLIMajorVersion.match(/^\d+$/)) {
|
|
99
124
|
const semverExpectedMinCLIVersion = `${expectedCLIMajorVersion}.0.0`;
|
|
100
125
|
if ((0, semver_1.major)(currentCLIVersion) < (0, semver_1.major)(semverExpectedMinCLIVersion)) {
|
|
101
|
-
command.
|
|
102
|
-
|
|
126
|
+
command.log(chalk_1.default.yellow(`
|
|
127
|
+
❗ Your CLI is outdated and is incompatible with your Opal server.
|
|
103
128
|
Expected major version ${chalk_1.default.blueBright(semverExpectedMinCLIVersion)}, but version ${chalk_1.default.blueBright(currentCLIVersion)} is installed.
|
|
104
|
-
Upgrade using the following command: ${chalk_1.default.blueBright(
|
|
129
|
+
Upgrade using the following command: ${chalk_1.default.blueBright("brew upgrade opalsecurity/brew/opal-security")}\n`));
|
|
130
|
+
alreadyWarnedAboutVersion = true;
|
|
105
131
|
}
|
|
106
132
|
else if ((0, semver_1.major)(currentCLIVersion) > (0, semver_1.major)(semverExpectedMinCLIVersion)) {
|
|
107
|
-
command.
|
|
108
|
-
|
|
133
|
+
command.log(chalk_1.default.yellow(`
|
|
134
|
+
❗ Uh oh! The currently installed Opal server is outdated. Please contact your Opal admins to let them know they need to upgrade their deployment.\n`));
|
|
135
|
+
alreadyWarnedAboutVersion = true;
|
|
109
136
|
}
|
|
110
137
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
138
|
+
const recommendedCLIMajorVersion = headers.get("Opal-CLI-Recommended-Version");
|
|
139
|
+
if (recommendedCLIMajorVersion === null || recommendedCLIMajorVersion === void 0 ? void 0 : recommendedCLIMajorVersion.match(/^\d+$/)) {
|
|
140
|
+
const recommendedSemverString = `${recommendedCLIMajorVersion}.0.0`;
|
|
141
|
+
if (recommendedSemverString &&
|
|
142
|
+
(0, semver_1.major)(currentCLIVersion) < (0, semver_1.major)(recommendedSemverString)) {
|
|
114
143
|
command.log(chalk_1.default.yellow(`
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
144
|
+
❗ Opal recommends that you upgrade your CLI.
|
|
145
|
+
Recommended version >=${chalk_1.default.blueBright(recommendedSemverString)}, but version ${chalk_1.default.blueBright(currentCLIVersion)} is installed.
|
|
146
|
+
Upgrade using the following command: ${chalk_1.default.blueBright("brew upgrade opalsecurity/brew/opal-security")}\n`));
|
|
118
147
|
}
|
|
119
|
-
|
|
148
|
+
alreadyWarnedAboutVersion = true;
|
|
120
149
|
}
|
|
121
150
|
}
|
|
122
151
|
};
|
|
123
152
|
const checkCLIVersionLink = new core_1.ApolloLink((operation, forward) => {
|
|
124
|
-
return forward(operation).map(response => {
|
|
153
|
+
return forward(operation).map((response) => {
|
|
125
154
|
checkCLIVersion(operation);
|
|
126
155
|
return response;
|
|
127
156
|
});
|
|
128
157
|
});
|
|
129
158
|
const errorLink = (0, error_1.onError)(({ networkError, operation }) => {
|
|
130
159
|
var _a;
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
//
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
//
|
|
160
|
+
// There's a few GQL operations where we don't want to use this error handler:
|
|
161
|
+
const customErrorOperations = [
|
|
162
|
+
// This is triggered just after the user called `opal login` or `opal set-token`, and has
|
|
163
|
+
// special handling if they fail, so we don't trigger an automatic re-login
|
|
164
|
+
login_1.CLIAuthSessionCheckName,
|
|
165
|
+
// This has special error handling to fall back to an older auth method that uses the OAuth access token
|
|
166
|
+
login_1.CLITokenExchangeName,
|
|
167
|
+
// This has special error handling due to the fact that the backend version
|
|
139
168
|
// can be out of date and not include the new cliClientId field.
|
|
169
|
+
login_1.CLISignInMethodName,
|
|
170
|
+
];
|
|
171
|
+
if (customErrorOperations.includes(operation.operationName)) {
|
|
140
172
|
return;
|
|
141
173
|
}
|
|
142
|
-
if (networkError &&
|
|
174
|
+
if (networkError && "statusCode" in networkError) {
|
|
143
175
|
let errorMessage = null;
|
|
144
|
-
if (
|
|
176
|
+
if ("result" in networkError) {
|
|
145
177
|
const result = networkError.result;
|
|
146
178
|
// result is now of type string | Record<string, any>
|
|
147
179
|
if (typeof result === "string")
|
|
@@ -152,12 +184,13 @@ const initClient = async (command, fetchAccessToken = true) => {
|
|
|
152
184
|
}
|
|
153
185
|
switch (networkError.statusCode) {
|
|
154
186
|
case 401: {
|
|
155
|
-
command.log(
|
|
187
|
+
command.log("Your session is invalid or expired. Authenticating now...\n");
|
|
156
188
|
const loginCommand = new login_1.default([], command.config);
|
|
157
189
|
loginCommand.run().then(() => {
|
|
158
190
|
if (cmd_1.mostRecentCommandTime && cmd_1.mostRecentCommand) {
|
|
159
|
-
const lastCommandReexecutionDuration = moment.duration(2,
|
|
160
|
-
const lastCommandReexecutionDurationHasElapsed = cmd_1.mostRecentCommandTime.add(lastCommandReexecutionDuration) >
|
|
191
|
+
const lastCommandReexecutionDuration = moment.duration(2, "minutes");
|
|
192
|
+
const lastCommandReexecutionDurationHasElapsed = cmd_1.mostRecentCommandTime.add(lastCommandReexecutionDuration) >
|
|
193
|
+
moment(new Date());
|
|
161
194
|
if (lastCommandReexecutionDurationHasElapsed) {
|
|
162
195
|
cmd_1.mostRecentCommand.run();
|
|
163
196
|
}
|
|
@@ -166,16 +199,35 @@ const initClient = async (command, fetchAccessToken = true) => {
|
|
|
166
199
|
break;
|
|
167
200
|
}
|
|
168
201
|
default:
|
|
169
|
-
return (0, exports.handleError)(command, `Received status code ${networkError.statusCode} from server${errorMessage ? ` with message "${errorMessage}"` :
|
|
202
|
+
return (0, exports.handleError)(command, `Received status code ${networkError.statusCode} from server${errorMessage ? ` with message "${errorMessage}"` : ""}`);
|
|
170
203
|
}
|
|
171
204
|
}
|
|
172
205
|
});
|
|
206
|
+
// Parses our auth-session cookie out of the Set-Cookie response header, saving it locally so we can use it for future requests
|
|
207
|
+
const preserveCookiesLink = new core_1.ApolloLink((operation, forward) => {
|
|
208
|
+
return forward(operation).map((response) => {
|
|
209
|
+
var _a, _b, _c, _d;
|
|
210
|
+
const cookieHeaderStr = (_c = (_b = (_a = operation.getContext().response) === null || _a === void 0 ? void 0 : _a.headers) === null || _b === void 0 ? void 0 : _b.get("Set-Cookie")) !== null && _c !== void 0 ? _c : "";
|
|
211
|
+
const authSessionCookie = (_d = cookieHeaderStr.match(/auth-session=[^;]+;/)) === null || _d === void 0 ? void 0 : _d[0];
|
|
212
|
+
if (authSessionCookie) {
|
|
213
|
+
exports.cookieStr = authSessionCookie;
|
|
214
|
+
}
|
|
215
|
+
return response;
|
|
216
|
+
});
|
|
217
|
+
});
|
|
173
218
|
let link = authLink.concat(httpLink);
|
|
174
219
|
link = checkCLIVersionLink.concat(link);
|
|
220
|
+
link = preserveCookiesLink.concat(link);
|
|
175
221
|
link = errorLink.concat(link);
|
|
176
222
|
exports.client = new core_1.ApolloClient({
|
|
177
223
|
link: link,
|
|
224
|
+
credentials: "include",
|
|
178
225
|
cache: new core_1.InMemoryCache(),
|
|
179
226
|
});
|
|
180
227
|
};
|
|
181
228
|
exports.initClient = initClient;
|
|
229
|
+
async function getClient(command, fetchAccessToken = true) {
|
|
230
|
+
await (0, exports.initClient)(command, fetchAccessToken);
|
|
231
|
+
(0, globals_1.invariant)(exports.client, "Failed to initialize Opal Client");
|
|
232
|
+
return exports.client;
|
|
233
|
+
}
|
package/lib/lib/aws.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getAwsEnvVarMessage = exports.getAwsConfigUpdateCmd = void 0;
|
|
4
|
-
const opalProfileKey =
|
|
4
|
+
const opalProfileKey = "opal";
|
|
5
5
|
const sanitize = (str) => {
|
|
6
6
|
// Remove non standard characters.
|
|
7
7
|
// Note: AWS supports profile names containing alphanumeric characters, symbols, and white spaces
|
|
8
8
|
// from the ASCII character set.
|
|
9
|
-
let sanitizedStr = str.replace(/[^A-Za-z0-9-_ ]/g,
|
|
9
|
+
let sanitizedStr = str.replace(/[^A-Za-z0-9-_ ]/g, "");
|
|
10
10
|
// De-dupe spaces
|
|
11
|
-
sanitizedStr = sanitizedStr.replace(/\s+/g,
|
|
11
|
+
sanitizedStr = sanitizedStr.replace(/\s+/g, " ");
|
|
12
12
|
// Map remaining spaces to '-'
|
|
13
|
-
sanitizedStr = sanitizedStr.replace(/ /g,
|
|
13
|
+
sanitizedStr = sanitizedStr.replace(/ /g, "-");
|
|
14
14
|
return sanitizedStr;
|
|
15
15
|
};
|
|
16
16
|
const getAwsConfigUpdateCmd = (itemName, awsAccessKeyId, awsSecretAccessKey, awsSessionToken) => {
|
|
17
|
-
let updateProfilesCmd =
|
|
17
|
+
let updateProfilesCmd = "";
|
|
18
18
|
const sanitizedProfileName = sanitize(itemName);
|
|
19
19
|
const profileNames = [opalProfileKey, sanitizedProfileName];
|
|
20
20
|
profileNames.forEach((profileName, i) => {
|
|
@@ -25,25 +25,28 @@ const getAwsConfigUpdateCmd = (itemName, awsAccessKeyId, awsSecretAccessKey, aws
|
|
|
25
25
|
const cmd = `${updateAccessKeyCmd} && ${updateAccessSecretCmd} && ${updateSessionTokenCmd}`;
|
|
26
26
|
updateProfilesCmd += cmd;
|
|
27
27
|
if (i !== profileNames.length - 1) {
|
|
28
|
-
updateProfilesCmd +=
|
|
28
|
+
updateProfilesCmd += "&& ";
|
|
29
29
|
}
|
|
30
30
|
});
|
|
31
31
|
return updateProfilesCmd;
|
|
32
32
|
};
|
|
33
33
|
exports.getAwsConfigUpdateCmd = getAwsConfigUpdateCmd;
|
|
34
34
|
const getAwsEnvVarMessage = () => {
|
|
35
|
-
if (!process.env.AWS_DEFAULT_PROFILE ||
|
|
36
|
-
|
|
35
|
+
if (!process.env.AWS_DEFAULT_PROFILE ||
|
|
36
|
+
process.env.AWS_DEFAULT_PROFILE !== opalProfileKey) {
|
|
37
|
+
let envVarPhrase = "";
|
|
37
38
|
if (!process.env.AWS_DEFAULT_PROFILE) {
|
|
38
|
-
envVarPhrase =
|
|
39
|
+
envVarPhrase = "unset";
|
|
39
40
|
}
|
|
40
41
|
else if (process.env.AWS_DEFAULT_PROFILE !== opalProfileKey) {
|
|
41
42
|
envVarPhrase = `set to "${process.env.AWS_DEFAULT_PROFILE}"`;
|
|
42
43
|
}
|
|
43
|
-
return
|
|
44
|
+
return (
|
|
45
|
+
// biome-ignore lint/style/useTemplate: it's more readable if split across lines
|
|
46
|
+
"\n\n💡 Did you know you can set your AWS_DEFAULT_PROFILE environment " +
|
|
44
47
|
`variable to "${opalProfileKey}" to avoid explicitly specifying profile in each command? ` +
|
|
45
|
-
`Currently, this variable is ${envVarPhrase}
|
|
48
|
+
`Currently, this variable is ${envVarPhrase}.`);
|
|
46
49
|
}
|
|
47
|
-
return
|
|
50
|
+
return "";
|
|
48
51
|
};
|
|
49
52
|
exports.getAwsEnvVarMessage = getAwsEnvVarMessage;
|
package/lib/lib/cmd.d.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
import { Command } from '@oclif/core';
|
|
5
|
-
import * as moment from 'moment';
|
|
1
|
+
import type { ExecException } from "node:child_process";
|
|
2
|
+
import type { Command } from "@oclif/core";
|
|
3
|
+
import * as moment from "moment";
|
|
6
4
|
export declare let mostRecentCommand: Command | null;
|
|
7
5
|
export declare let mostRecentCommandTime: moment.Moment | null;
|
|
8
6
|
export declare const setMostRecentCommand: (cmd: Command) => void;
|
|
9
7
|
export declare const startInteractiveShell: (runCmd: string, shellName?: string) => void;
|
|
10
8
|
export declare const runCommandExec: (runCmd: string, successMessage: string, errorMessage: string, envVars?: Record<string, any>) => void;
|
|
11
|
-
export declare const runCommandExecWithCallback: (cmd: string, callback?: (
|
|
9
|
+
export declare const runCommandExecWithCallback: (cmd: string, callback?: (error: ExecException | null, stdout: Buffer, stderr: Buffer) => void) => Promise<unknown>;
|
|
12
10
|
export declare const runCommandSpawn: (runCmd: string, successMessage: string, errorMessage: string, envVars?: Record<string, any>) => void;
|
package/lib/lib/cmd.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.runCommandSpawn = exports.runCommandExecWithCallback = exports.runCommandExec = exports.startInteractiveShell = exports.setMostRecentCommand = exports.mostRecentCommandTime = exports.mostRecentCommand = void 0;
|
|
4
4
|
const _ = require("lodash");
|
|
5
5
|
const moment = require("moment");
|
|
6
|
-
const { exec, spawn } = require(
|
|
6
|
+
const { exec, spawn } = require("node:child_process");
|
|
7
7
|
exports.mostRecentCommand = null;
|
|
8
8
|
exports.mostRecentCommandTime = null;
|
|
9
9
|
const setMostRecentCommand = (cmd) => {
|
|
@@ -14,10 +14,10 @@ exports.setMostRecentCommand = setMostRecentCommand;
|
|
|
14
14
|
const startInteractiveShell = (runCmd, shellName) => {
|
|
15
15
|
const shell = spawn(`${runCmd}`, [], {
|
|
16
16
|
env: Object.assign(Object.assign({}, process.env), { SCRIPT_PATH: __dirname }),
|
|
17
|
-
stdio:
|
|
17
|
+
stdio: "inherit",
|
|
18
18
|
shell: true,
|
|
19
19
|
});
|
|
20
|
-
shell.on(
|
|
20
|
+
shell.on("close", (code) => {
|
|
21
21
|
if (shellName) {
|
|
22
22
|
if (code === 0) {
|
|
23
23
|
console.log(`The previously launched ${shellName} has successfully terminated.`);
|
|
@@ -30,10 +30,10 @@ const startInteractiveShell = (runCmd, shellName) => {
|
|
|
30
30
|
console.log(`❗ Error: shell terminated with code ${code}.`);
|
|
31
31
|
}
|
|
32
32
|
});
|
|
33
|
-
process.on(
|
|
33
|
+
process.on("SIGINT", () => {
|
|
34
34
|
// intercepting SIGINT
|
|
35
35
|
});
|
|
36
|
-
process.on(
|
|
36
|
+
process.on("SIGTSTP", () => {
|
|
37
37
|
// intercepting SIGTSTP
|
|
38
38
|
});
|
|
39
39
|
};
|
|
@@ -42,7 +42,7 @@ const runCommandExec = (runCmd, successMessage, errorMessage, envVars) => {
|
|
|
42
42
|
const envVarsToUse = envVars || {};
|
|
43
43
|
exec(`${runCmd}`, {
|
|
44
44
|
env: Object.assign(Object.assign(Object.assign({}, process.env), { SCRIPT_PATH: __dirname }), envVarsToUse),
|
|
45
|
-
},
|
|
45
|
+
}, (error, stdOut, stdErr) => {
|
|
46
46
|
if (error) {
|
|
47
47
|
console.log(`\n❗ Error: ${_.upperFirst(errorMessage)}`);
|
|
48
48
|
}
|
|
@@ -59,9 +59,9 @@ const runCommandExec = (runCmd, successMessage, errorMessage, envVars) => {
|
|
|
59
59
|
};
|
|
60
60
|
exports.runCommandExec = runCommandExec;
|
|
61
61
|
const runCommandExecWithCallback = (cmd, callback) => {
|
|
62
|
-
return new Promise(resolve => {
|
|
63
|
-
exec(cmd,
|
|
64
|
-
callback
|
|
62
|
+
return new Promise((resolve) => {
|
|
63
|
+
exec(cmd, (error, stdOut, stdErr) => {
|
|
64
|
+
callback === null || callback === void 0 ? void 0 : callback(error, stdOut, stdErr);
|
|
65
65
|
resolve(stdOut);
|
|
66
66
|
});
|
|
67
67
|
});
|
|
@@ -71,10 +71,10 @@ const runCommandSpawn = (runCmd, successMessage, errorMessage, envVars) => {
|
|
|
71
71
|
const envVarsToUse = envVars || {};
|
|
72
72
|
const shell = spawn(`${runCmd}`, [], {
|
|
73
73
|
env: Object.assign(Object.assign(Object.assign({}, process.env), { SCRIPT_PATH: __dirname }), envVarsToUse),
|
|
74
|
-
stdio:
|
|
74
|
+
stdio: "inherit",
|
|
75
75
|
shell: true,
|
|
76
76
|
});
|
|
77
|
-
shell.on(
|
|
77
|
+
shell.on("close", (code) => {
|
|
78
78
|
if (code === 0) {
|
|
79
79
|
console.log(`🎉 Success! ${_.upperFirst(successMessage)}`);
|
|
80
80
|
}
|
package/lib/lib/config.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isProduction = exports.writeConfigData = exports.getOrCreateConfigData = exports.customHttpHeaderKey = exports.defaultAllowSelfSignedCerts = exports.allowSelfSignedCertsKey = exports.defaultUrl = exports.urlKey = void 0;
|
|
4
|
-
const fs = require("fs");
|
|
5
|
-
const path = require("path");
|
|
6
|
-
exports.urlKey =
|
|
7
|
-
exports.defaultUrl =
|
|
8
|
-
exports.allowSelfSignedCertsKey =
|
|
4
|
+
const fs = require("node:fs");
|
|
5
|
+
const path = require("node:path");
|
|
6
|
+
exports.urlKey = "url";
|
|
7
|
+
exports.defaultUrl = "https://app.opal.dev";
|
|
8
|
+
exports.allowSelfSignedCertsKey = "allowSelfSignedCerts";
|
|
9
9
|
exports.defaultAllowSelfSignedCerts = false;
|
|
10
|
-
exports.customHttpHeaderKey =
|
|
10
|
+
exports.customHttpHeaderKey = "customHttpHeader";
|
|
11
11
|
const getOrCreateConfigData = (configDir) => {
|
|
12
12
|
if (!fs.existsSync(configDir)) {
|
|
13
13
|
fs.mkdirSync(configDir, { recursive: true });
|
|
14
14
|
}
|
|
15
|
-
const configFilePath = path.join(configDir,
|
|
15
|
+
const configFilePath = path.join(configDir, "config.json");
|
|
16
16
|
if (!fs.existsSync(configFilePath)) {
|
|
17
17
|
fs.writeFileSync(configFilePath, JSON.stringify({
|
|
18
18
|
[exports.urlKey]: exports.defaultUrl,
|
|
@@ -22,10 +22,10 @@ const getOrCreateConfigData = (configDir) => {
|
|
|
22
22
|
let configData = {};
|
|
23
23
|
try {
|
|
24
24
|
const configDataRaw = fs.readFileSync(configFilePath);
|
|
25
|
-
configData = JSON.parse(configDataRaw.toString());
|
|
25
|
+
configData = JSON.parse(configDataRaw === null || configDataRaw === void 0 ? void 0 : configDataRaw.toString());
|
|
26
26
|
}
|
|
27
27
|
catch (error) {
|
|
28
|
-
if (error.code !==
|
|
28
|
+
if (error.code !== "ENOENT") {
|
|
29
29
|
throw error;
|
|
30
30
|
}
|
|
31
31
|
}
|
|
@@ -37,7 +37,7 @@ const writeConfigData = (configDir, newConfigData) => {
|
|
|
37
37
|
for (const [key, value] of Object.entries(newConfigData)) {
|
|
38
38
|
existingData[key] = value;
|
|
39
39
|
}
|
|
40
|
-
const configFilePath = path.join(configDir,
|
|
40
|
+
const configFilePath = path.join(configDir, "config.json");
|
|
41
41
|
fs.writeFileSync(configFilePath, JSON.stringify(existingData), {
|
|
42
42
|
mode: 0o0600,
|
|
43
43
|
});
|
|
@@ -46,10 +46,9 @@ exports.writeConfigData = writeConfigData;
|
|
|
46
46
|
const isProduction = (configDir) => {
|
|
47
47
|
const configData = (0, exports.getOrCreateConfigData)(configDir);
|
|
48
48
|
// Custom URLs are considered production since it includes on-prem
|
|
49
|
-
return configData[exports.urlKey] !==
|
|
50
|
-
configData[exports.urlKey] !==
|
|
51
|
-
configData[exports.urlKey] !==
|
|
52
|
-
configData[exports.urlKey]
|
|
53
|
-
configData[exports.urlKey] !== 'https://staging.opal.dev';
|
|
49
|
+
return (configData[exports.urlKey] !== "https://dev.opal.dev" &&
|
|
50
|
+
configData[exports.urlKey] !== "https://demo.opal.dev" &&
|
|
51
|
+
configData[exports.urlKey] !== "https://staging.opal.dev" &&
|
|
52
|
+
!configData[exports.urlKey].match(/https?:\/\/localhost/));
|
|
54
53
|
};
|
|
55
54
|
exports.isProduction = isProduction;
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
import { Command } from
|
|
1
|
+
import type { Command } from "@oclif/core";
|
|
2
2
|
interface OpalCredentials {
|
|
3
3
|
email?: string;
|
|
4
4
|
organizationID?: string;
|
|
5
5
|
clientIDCandidate?: string;
|
|
6
|
-
|
|
6
|
+
secret?: string;
|
|
7
|
+
secretType?: SecretType;
|
|
7
8
|
}
|
|
8
|
-
export declare
|
|
9
|
-
|
|
9
|
+
export declare enum SecretType {
|
|
10
|
+
Cookie = "COOKIE",
|
|
11
|
+
ApiToken = "API_TOKEN"
|
|
12
|
+
}
|
|
13
|
+
export declare const setOpalCredentials: (command: Command, email: string | undefined, organizationID: string, clientIDCandidate: string | undefined | null, secret: string, secretType: SecretType) => Promise<void>;
|
|
14
|
+
export declare const getOpalCredentials: (command: Command, includeAuthSecret?: boolean) => Promise<OpalCredentials>;
|
|
10
15
|
export declare const removeOpalCredentials: (command: Command) => Promise<void>;
|
|
11
16
|
export {};
|