bdy 1.16.14-dev → 1.16.16-dev
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/distTs/package.json +2 -1
- package/distTs/src/api/client.js +37 -6
- package/distTs/src/command/login.js +103 -46
- package/distTs/src/command/whoami.js +31 -0
- package/distTs/src/index.js +2 -0
- package/distTs/src/texts.js +10 -3
- package/distTs/src/tunnel/cfg.js +17 -0
- package/distTs/src/tunnel/server/http1.js +11 -6
- package/distTs/src/tunnel/server/http2.js +14 -6
- package/package.json +2 -1
package/distTs/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bdy",
|
|
3
3
|
"preferGlobal": false,
|
|
4
|
-
"version": "1.16.
|
|
4
|
+
"version": "1.16.16-dev",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"scripts": {
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"eventsource": "4.0.0",
|
|
32
32
|
"fastify": "4.28.1",
|
|
33
33
|
"fdir": "6.5.0",
|
|
34
|
+
"open": "11.0.0",
|
|
34
35
|
"fflate": "0.8.2",
|
|
35
36
|
"human-id": "^4.1.3",
|
|
36
37
|
"isbinaryfile": "5.0.2",
|
package/distTs/src/api/client.js
CHANGED
|
@@ -21,18 +21,24 @@ class ApiClient {
|
|
|
21
21
|
},
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
|
-
async request(method, path, body, parseResponseBody = false, rawResponseBody = false) {
|
|
25
|
-
const headers = {
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
async request(method, path, body, parseResponseBody = false, rawResponseBody = false, httpUrlEncoded = false) {
|
|
25
|
+
const headers = {};
|
|
26
|
+
if (this.token)
|
|
27
|
+
headers.authorization = `Bearer ${this.token}`;
|
|
28
28
|
let bodyParsed = undefined;
|
|
29
29
|
if (body) {
|
|
30
30
|
if (body instanceof undici_1.FormData) {
|
|
31
31
|
bodyParsed = body;
|
|
32
32
|
}
|
|
33
33
|
else {
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
if (httpUrlEncoded) {
|
|
35
|
+
headers['content-type'] = 'application/x-www-form-urlencoded; charset=utf-8';
|
|
36
|
+
bodyParsed = new URLSearchParams(body).toString();
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
headers['content-type'] = 'application/json; charset=utf-8';
|
|
40
|
+
bodyParsed = JSON.stringify(body);
|
|
41
|
+
}
|
|
36
42
|
}
|
|
37
43
|
}
|
|
38
44
|
const opts = {
|
|
@@ -138,6 +144,9 @@ class ApiClient {
|
|
|
138
144
|
async getPipelineRun(workspace, project, pipelineId, executionId) {
|
|
139
145
|
return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/projects/${encodeURIComponent(project)}/pipelines/${encodeURIComponent(pipelineId)}/executions/${encodeURIComponent(executionId)}`, null, true);
|
|
140
146
|
}
|
|
147
|
+
async getInvoker() {
|
|
148
|
+
return await this.request('GET', '/user', null, true);
|
|
149
|
+
}
|
|
141
150
|
async postPipelineRun(workspace, project, pipelineId, body) {
|
|
142
151
|
return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/projects/${encodeURIComponent(project)}/pipelines/${encodeURIComponent(pipelineId)}/executions`, body, true);
|
|
143
152
|
}
|
|
@@ -169,6 +178,28 @@ class ApiClient {
|
|
|
169
178
|
async stopSandbox(workspace, sandboxId) {
|
|
170
179
|
return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/stop`, {}, true);
|
|
171
180
|
}
|
|
181
|
+
async registerApp(name, redirectUrl) {
|
|
182
|
+
return await this.request('POST', '/auth/register', {
|
|
183
|
+
redirect_uris: [redirectUrl],
|
|
184
|
+
client_name: name,
|
|
185
|
+
grant_types: ['authorization_code', 'refresh_token'],
|
|
186
|
+
response_types: ['code'],
|
|
187
|
+
token_endpoint_auth_method: "client_secret_basic",
|
|
188
|
+
token_expires_in: 3600
|
|
189
|
+
}, true);
|
|
190
|
+
}
|
|
191
|
+
async getApp(clientId) {
|
|
192
|
+
return await this.request('GET', `/auth/register/${encodeURIComponent(clientId)}`, null, true);
|
|
193
|
+
}
|
|
194
|
+
async exchangeAppToken(code, clientId, clientSecret, redirectUrl) {
|
|
195
|
+
return await this.request('POST', '/oauth2/token', {
|
|
196
|
+
grant_type: 'authorization_code',
|
|
197
|
+
code,
|
|
198
|
+
client_id: clientId,
|
|
199
|
+
client_secret: clientSecret,
|
|
200
|
+
redirect_uri: redirectUrl
|
|
201
|
+
}, true, false, true);
|
|
202
|
+
}
|
|
172
203
|
async restartSandbox(workspace, sandboxId) {
|
|
173
204
|
return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/restart`, {}, true);
|
|
174
205
|
}
|
|
@@ -6,21 +6,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const cfg_1 = __importDefault(require("../tunnel/cfg"));
|
|
7
7
|
const output_1 = __importDefault(require("../output"));
|
|
8
8
|
const client_1 = __importDefault(require("../api/client"));
|
|
9
|
+
const node_http_1 = __importDefault(require("node:http"));
|
|
10
|
+
const open_1 = __importDefault(require("open"));
|
|
9
11
|
const texts_1 = require("../texts");
|
|
10
12
|
const utils_1 = require("../utils");
|
|
11
13
|
const input_1 = __importDefault(require("../input"));
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
case utils_1.REST_API_REGION.EU:
|
|
17
|
-
return 'https://eu.buddy.works/security';
|
|
18
|
-
case utils_1.REST_API_REGION.AS:
|
|
19
|
-
return 'https://asia.buddy.works/security';
|
|
20
|
-
default:
|
|
21
|
-
return `https://${baseUrl}/security`;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
14
|
+
const OAUTH_CLIENT_APP_PORT = 7596;
|
|
15
|
+
const OAUTH_CLIENT_APP_HOST = 'localhost';
|
|
16
|
+
const OAUTH_CLIENT_APP_REDIRECT_URL = `http://localhost:${OAUTH_CLIENT_APP_PORT}`;
|
|
17
|
+
const OAUTH_CLIENT_APP_SCOPES = 'WORKSPACE USER_INFO EXECUTION_MANAGE SANDBOX_MANAGE';
|
|
24
18
|
function normalizeBaseUrl(url) {
|
|
25
19
|
let normalized = url.trim();
|
|
26
20
|
normalized = normalized.replace(/^https?:\/\//i, '');
|
|
@@ -52,10 +46,96 @@ async function restApiBaseUrl() {
|
|
|
52
46
|
}
|
|
53
47
|
return `${normalized}/api`;
|
|
54
48
|
}
|
|
55
|
-
async function
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
49
|
+
async function oauthServer(api, clientId, clientSecret) {
|
|
50
|
+
return new Promise((resolve, reject) => {
|
|
51
|
+
const s = node_http_1.default.createServer(async (req, res) => {
|
|
52
|
+
const url = new URL(req.url || '', `http://${OAUTH_CLIENT_APP_HOST}`);
|
|
53
|
+
const urlCode = url.searchParams.get('code');
|
|
54
|
+
if (!urlCode) {
|
|
55
|
+
res.end(texts_1.ERR_LOGIN_HTTP_FAILED);
|
|
56
|
+
s.close();
|
|
57
|
+
reject(new Error(texts_1.ERR_LOGIN_HTTP_FAILED));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const client = new client_1.default(new URL(`https://${api}`));
|
|
61
|
+
try {
|
|
62
|
+
const response = await client.exchangeAppToken(urlCode, clientId, clientSecret, OAUTH_CLIENT_APP_REDIRECT_URL);
|
|
63
|
+
res.end(texts_1.ERR_LOGIN_HTTP_SUCCESS);
|
|
64
|
+
s.close();
|
|
65
|
+
resolve(response.access_token);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
res.end(texts_1.ERR_LOGIN_HTTP_FAILED);
|
|
69
|
+
s.close();
|
|
70
|
+
reject(new Error(texts_1.ERR_LOGIN_HTTP_FAILED));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
s.on('error', () => {
|
|
75
|
+
s.close();
|
|
76
|
+
reject(texts_1.ERR_LOGIN_HTTP_SERVER_PORT_TAKEN);
|
|
77
|
+
});
|
|
78
|
+
s.listen(OAUTH_CLIENT_APP_PORT, OAUTH_CLIENT_APP_HOST);
|
|
79
|
+
(0, open_1.default)(`https://${api}/oauth2/authorize?type=web_server&client_id=${encodeURIComponent(clientId)}&redirect_uri=${encodeURIComponent(OAUTH_CLIENT_APP_REDIRECT_URL)}&response_type=code&scope=${encodeURIComponent(OAUTH_CLIENT_APP_SCOPES)}`);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
async function getOrCreateApp(api) {
|
|
83
|
+
const client = new client_1.default(new URL(`https://${api}`));
|
|
84
|
+
let clientId = cfg_1.default.getApiClientId();
|
|
85
|
+
let clientSecret = cfg_1.default.getApiClientSecret();
|
|
86
|
+
if (clientId && clientSecret) {
|
|
87
|
+
try {
|
|
88
|
+
await client.getApp(clientId);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
clientId = null;
|
|
92
|
+
clientSecret = null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (!clientId || !clientSecret) {
|
|
96
|
+
const app = await client.registerApp('bdy cli app', OAUTH_CLIENT_APP_REDIRECT_URL);
|
|
97
|
+
clientId = app.client_id;
|
|
98
|
+
clientSecret = app.client_secret;
|
|
99
|
+
cfg_1.default.setApiClient(clientId, clientSecret);
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
clientId,
|
|
103
|
+
clientSecret,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
async function authorizeOAuth(api) {
|
|
107
|
+
const { clientId, clientSecret } = await getOrCreateApp(api);
|
|
108
|
+
return await oauthServer(api, clientId, clientSecret);
|
|
109
|
+
}
|
|
110
|
+
async function authorizeToken(api, token, workspace, project) {
|
|
111
|
+
const client = new client_1.default(new URL(`https://${api}`), token);
|
|
112
|
+
const w = await client.getWorkspaces();
|
|
113
|
+
if (!w.workspaces?.length) {
|
|
114
|
+
output_1.default.exitError(texts_1.ERR_LOGIN_NO_WORKSPACES);
|
|
115
|
+
}
|
|
116
|
+
if (workspace) {
|
|
117
|
+
const found = w.workspaces.find((w) => w.domain === workspace);
|
|
118
|
+
if (!found) {
|
|
119
|
+
output_1.default.exitError(texts_1.ERR_LOGIN_NO_WORKSPACE_FOUND);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
workspace = await output_1.default.selectWorkspace(w.workspaces);
|
|
124
|
+
}
|
|
125
|
+
cfg_1.default.setApiToken(token);
|
|
126
|
+
cfg_1.default.setWorkspace(workspace);
|
|
127
|
+
const p = await client.getProjects(workspace);
|
|
128
|
+
if (project) {
|
|
129
|
+
const found = p.projects.find((p) => p.name === project);
|
|
130
|
+
if (!found) {
|
|
131
|
+
output_1.default.exitError(texts_1.ERR_LOGIN_NO_PROJECT_FOUND);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
project = await output_1.default.selectProject(p.projects);
|
|
136
|
+
}
|
|
137
|
+
cfg_1.default.setProject(project);
|
|
138
|
+
output_1.default.exitSuccess(texts_1.TXT_LOGIN_SUCCESS);
|
|
59
139
|
}
|
|
60
140
|
const commandLogin = (0, utils_1.newCommand)('login', texts_1.DESC_COMMAND_LOGIN);
|
|
61
141
|
commandLogin.option('--token <token>', texts_1.OPTION_REST_API_TOKEN);
|
|
@@ -68,9 +148,9 @@ commandLogin.action(async (options) => {
|
|
|
68
148
|
cfg_1.default.clearLogin();
|
|
69
149
|
let api = options.api || process.env.BUDDY_API_ENDPOINT;
|
|
70
150
|
let region = options.region || process.env.BUDDY_REGION;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
151
|
+
const token = options.token || process.env.BUDDY_TOKEN;
|
|
152
|
+
const workspace = options.workspace || process.env.BUDDY_WORKSPACE;
|
|
153
|
+
const project = options.project || process.env.BUDDY_PROJECT;
|
|
74
154
|
if (api) {
|
|
75
155
|
region = utils_1.REST_API_REGION.ONPREM;
|
|
76
156
|
}
|
|
@@ -96,35 +176,12 @@ commandLogin.action(async (options) => {
|
|
|
96
176
|
}
|
|
97
177
|
cfg_1.default.setBaseUrl(api);
|
|
98
178
|
if (!token) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const w = await client.getWorkspaces();
|
|
103
|
-
if (!w.workspaces?.length) {
|
|
104
|
-
output_1.default.exitError(texts_1.ERR_LOGIN_NO_WORKSPACES);
|
|
105
|
-
}
|
|
106
|
-
if (workspace) {
|
|
107
|
-
const found = w.workspaces.find((w) => w.domain === workspace);
|
|
108
|
-
if (!found) {
|
|
109
|
-
output_1.default.exitError(texts_1.ERR_LOGIN_NO_WORKSPACE_FOUND);
|
|
110
|
-
}
|
|
179
|
+
output_1.default.normal(texts_1.TXT_LOGIN_OAUTH);
|
|
180
|
+
const token = await authorizeOAuth(api);
|
|
181
|
+
await authorizeToken(api, token, workspace, project);
|
|
111
182
|
}
|
|
112
183
|
else {
|
|
113
|
-
|
|
184
|
+
await authorizeToken(api, token, workspace, project);
|
|
114
185
|
}
|
|
115
|
-
cfg_1.default.setApiToken(token);
|
|
116
|
-
cfg_1.default.setWorkspace(workspace);
|
|
117
|
-
const p = await client.getProjects(workspace);
|
|
118
|
-
if (project) {
|
|
119
|
-
const found = p.projects.find((p) => p.name === project);
|
|
120
|
-
if (!found) {
|
|
121
|
-
output_1.default.exitError(texts_1.ERR_LOGIN_NO_PROJECT_FOUND);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
project = await output_1.default.selectProject(p.projects);
|
|
126
|
-
}
|
|
127
|
-
cfg_1.default.setProject(project);
|
|
128
|
-
output_1.default.exitSuccess(texts_1.TXT_LOGIN_SUCCESS);
|
|
129
186
|
});
|
|
130
187
|
exports.default = commandLogin;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
|
+
const texts_1 = require("../texts");
|
|
8
|
+
const cfg_1 = __importDefault(require("../tunnel/cfg"));
|
|
9
|
+
const output_1 = __importDefault(require("../output"));
|
|
10
|
+
const input_1 = __importDefault(require("../input"));
|
|
11
|
+
const client_1 = __importDefault(require("../api/client"));
|
|
12
|
+
const commandWhoami = (0, utils_1.newCommand)('whoami', texts_1.DESC_COMMAND_WHOAMI);
|
|
13
|
+
commandWhoami.action(async () => {
|
|
14
|
+
const token = cfg_1.default.getApiToken();
|
|
15
|
+
const workspace = cfg_1.default.getWorkspace();
|
|
16
|
+
const project = cfg_1.default.getProject();
|
|
17
|
+
const baseUrl = input_1.default.restApiBaseUrl();
|
|
18
|
+
if (!token) {
|
|
19
|
+
output_1.default.exitError(texts_1.ERR_WHOAMI_LOGOUT);
|
|
20
|
+
}
|
|
21
|
+
const client = new client_1.default(baseUrl, token);
|
|
22
|
+
const user = await client.getInvoker();
|
|
23
|
+
if (!user) {
|
|
24
|
+
output_1.default.exitError(texts_1.ERR_WHOAMI_LOGOUT);
|
|
25
|
+
}
|
|
26
|
+
output_1.default.normal(user.name);
|
|
27
|
+
output_1.default.normal(`Workspace: ${!workspace ? texts_1.TXT_WHOAMI_NO_WORKSPACE : workspace}`);
|
|
28
|
+
output_1.default.normal(`Project: ${!project ? texts_1.TXT_WHOAMI_NO_PROJECT : project}`);
|
|
29
|
+
output_1.default.exitNormal();
|
|
30
|
+
});
|
|
31
|
+
exports.default = commandWhoami;
|
package/distTs/src/index.js
CHANGED
|
@@ -20,6 +20,7 @@ const login_1 = __importDefault(require("./command/login"));
|
|
|
20
20
|
const logout_1 = __importDefault(require("./command/logout"));
|
|
21
21
|
const workspace_1 = __importDefault(require("./command/workspace"));
|
|
22
22
|
const project_1 = __importDefault(require("./command/project"));
|
|
23
|
+
const whoami_1 = __importDefault(require("./command/whoami"));
|
|
23
24
|
stream_1.default.setDefaultHighWaterMark(false, 67108864);
|
|
24
25
|
process.title = 'bdy';
|
|
25
26
|
process.on('uncaughtException', (err) => {
|
|
@@ -40,6 +41,7 @@ program.addCommand(ut_1.default);
|
|
|
40
41
|
program.addCommand(pipeline_1.default);
|
|
41
42
|
program.addCommand(sandbox_1.default);
|
|
42
43
|
program.addCommand(login_1.default);
|
|
44
|
+
program.addCommand(whoami_1.default);
|
|
43
45
|
program.addCommand(logout_1.default);
|
|
44
46
|
program.addCommand(workspace_1.default);
|
|
45
47
|
program.addCommand(project_1.default);
|
package/distTs/src/texts.js
CHANGED
|
@@ -9,7 +9,7 @@ exports.LOG_SOCKET_DISCONNECTED = exports.LOG_SOCKET_CONNECTED = exports.LOG_AGE
|
|
|
9
9
|
exports.DEBUG_AUTO_SCROLL = exports.DEBUG_RESOURCE_SCRAPPING_URL = exports.DEBUG_SNAPSHOT_PROCESSING = exports.DEBUG_SNAPSHOTS_PROCESSING = exports.DEBUG_EXEC_COMMAND = exports.DEBUG_EXEC_TEST_COMMAND = exports.LOG_INSTALLED_BROWSER = exports.LOG_SESSION_LINK = exports.LOG_SENDING_DATA = exports.LOG_SENDING_REQUEST = exports.LOG_PROCESSING_SNAPSHOTS = exports.LOG_RUNNING_EXEC_COMMAND = exports.LOG_TUNNEL_SSH_STREAM = exports.LOG_TUNNEL_TLS_AGENT_STREAM = exports.LOG_TUNNEL_TLS_REGION_STREAM = exports.LOG_TUNNEL_TLS_TARGET_STREAM = exports.LOG_TUNNEL_HTTP2_STREAM = exports.LOG_TUNNEL_HTTP1_STREAM = exports.LOG_TUNNEL_TCP_STREAM = exports.LOG_TUNNEL_HTTP_WRONG_USER_AGENTS = exports.LOG_TUNNEL_HTTP_CIRCUIT_BREAKER_OPEN = exports.LOG_TUNNEL_HTTP_RATE_LIMIT = exports.LOG_TUNNEL_HTTP_WRON_AUTH = exports.LOG_TUNNEL_IDENTIFIED = exports.LOG_TUNNEL_DISCONNECTED = exports.LOG_TUNNEL_FAILED = exports.LOG_TUNNEL_CONNECTED = exports.LOG_AGENT_STARTED = exports.LOG_AGENT_SERVER_STARTED = exports.LOG_ERROR_STARTING_AGENT_SERVER = exports.LOG_SSH_CONNECTION = exports.LOG_WRONG_STREAM = exports.LOG_DETECTED_STREAM = exports.LOG_HTTP2_REQUEST = exports.LOG_HTTP2_CONNECTION = exports.LOG_HTTP1_REQUEST = exports.LOG_HTTP1_CONNECTION = exports.LOG_ERROR = exports.LOG_STOPPING_TUNNEL = exports.LOG_STARTING_TUNNEL = exports.LOG_ENABLING_AGENT_TARGET = exports.LOG_DISABLING_AGENT_TARGET = exports.LOG_REMOVING_TUNNEL = exports.LOG_TUNNEL_REGISTERED = exports.LOG_ERROR_WHILE_REFRESHING_AGENT = exports.LOG_REGISTERING_TUNNEL = exports.LOG_GETTING_AGENT = exports.LOG_UNREGISTERING_AGENT = exports.LOG_REGION_DETECTED = exports.LOG_AGENT_REGISTERED = void 0;
|
|
10
10
|
exports.TXT_SANDBOX_STOPPED = exports.TXT_SANDBOX_STARTED = exports.TXT_SANDBOX_DESTROYED = exports.TXT_SANDBOX_CREATED = exports.TXT_SANDBOX_CREATING = exports.OPTION_SANDBOX_COMMAND_LAST = exports.OPTION_SANDBOX_WAIT_TIMEOUT = exports.OPTION_SANDBOX_WAIT = exports.OPTION_SANDBOX_WAIT_APP = exports.OPTION_SANDBOX_WAIT_CONFIGURED = exports.OPTION_SANDBOX_WAIT_RUNNING = exports.ERR_SANDBOX_STOP_FAILED = exports.ERR_SANDBOX_NO_COMMANDS = exports.ERR_SANDBOX_RUNNING_FAILED = exports.ERR_SANDBOX_STOP_TIMEOUT = exports.ERR_SANDBOX_SNAPSHOT_TIMEOUT = exports.ERR_SANDBOX_RUNNING_TIMEOUT = exports.ERR_SANDBOX_APP_TIMEOUT = exports.ERR_SANDBOX_SETUP_TIMEOUT = exports.ERR_SANDBOX_APP_FAILED = exports.ERR_SANDBOX_SETUP_FAILED = exports.ERR_SANDBOX_INVALID_RUNTIME = exports.ERR_SANDBOX_INVALID_RESOURCES = exports.ERR_SANDBOX_NOT_FOUND = exports.OPTION_SANDBOX_COMMAND = exports.OPTION_SANDBOX_DETACHED = exports.OPTION_SANDBOX_RUNTIME = exports.OPTION_SANDBOX_APP_TYPE = exports.OPTION_SANDBOX_APP_DIR = exports.OPTION_SANDBOX_RUN_COMMAND = exports.OPTION_SANDBOX_TAGS = exports.OPTION_SANDBOX_INSTALL_COMMANDS = exports.OPTION_SANDBOX_RESOURCES = exports.OPTION_SANDBOX_OS = exports.OPTION_SANDBOX_NAME = exports.OPTION_SANDBOX_IDENTIFIER = exports.DESC_COMMAND_SANDBOX_EXEC = exports.DESC_COMMAND_SANDBOX_STATUS = exports.DESC_COMMAND_SANDBOX_RESTART = exports.DESC_COMMAND_SANDBOX_STOP = exports.DESC_COMMAND_SANDBOX_START = exports.DESC_COMMAND_SANDBOX_DESTROY = exports.DESC_COMMAND_SANDBOX_GET = exports.DESC_COMMAND_SANDBOX_LIST = exports.DESC_COMMAND_SANDBOX_CREATE = exports.DESC_COMMAND_SANDBOX = exports.DEBUG_WAIT_FOR_IDLE_TIMEOUT = exports.DEBUG_WAIT_FOR_IDLE = exports.DEBUG_RESOURCE_DISCOVERY_TIMEOUT = exports.DEBUG_AUTO_WIDTH = void 0;
|
|
11
11
|
exports.TXT_SANDBOX_EXEC_BACKGROUND = exports.TXT_SANDBOX_EXEC_ID = exports.ERR_SANDBOX_CP_INVALID_DEST = exports.ERR_SANDBOX_CP_SOURCE_NOT_FOUND = exports.TXT_SANDBOX_CP_DONE = exports.TXT_SANDBOX_CP_PROGRESS = exports.OPTION_SANDBOX_CP_SILENT = exports.OPTION_SANDBOX_CP_DEST = exports.OPTION_SANDBOX_CP_SOURCE = exports.DESC_COMMAND_SANDBOX_CP = exports.ERR_SANDBOX_ENDPOINTS_NOT_FOUND = exports.ERR_SANDBOX_ENDPOINT_NOT_FOUND = exports.ERR_SANDBOX_ENDPOINT_EXISTS = exports.TXT_SANDBOX_ENDPOINT_DELETED = exports.TXT_SANDBOX_ENDPOINT_ADDED = exports.OPTION_SANDBOX_ENDPOINT_TYPE = exports.OPTION_SANDBOX_ENDPOINT_PORT = exports.OPTION_SANDBOX_ENDPOINT_NAME_ARG = exports.OPTION_SANDBOX_ENDPOINT_NAME = exports.DESC_COMMAND_SANDBOX_ENDPOINT_DELETE = exports.DESC_COMMAND_SANDBOX_ENDPOINT_ADD = exports.DESC_COMMAND_SANDBOX_ENDPOINT_GET = exports.DESC_COMMAND_SANDBOX_ENDPOINT_LIST = exports.DESC_COMMAND_SANDBOX_ENDPOINT = exports.ERR_SANDBOX_SNAPSHOTS_NOT_FOUND = exports.ERR_SANDBOX_SNAPSHOT_NOT_FOUND = exports.ERR_SANDBOX_SNAPSHOT_FAILED = exports.TXT_SANDBOX_SNAPSHOT_WAITING = exports.TXT_SANDBOX_SNAPSHOT_DELETED = exports.TXT_SANDBOX_SNAPSHOT_CREATED = exports.OPTION_SANDBOX_FROM_SNAPSHOT = exports.OPTION_SANDBOX_SNAPSHOT_NAME_ARG = exports.OPTION_SANDBOX_SNAPSHOT_NAME = exports.DESC_COMMAND_SANDBOX_SNAPSHOT_DELETE = exports.DESC_COMMAND_SANDBOX_SNAPSHOT_GET = exports.DESC_COMMAND_SANDBOX_SNAPSHOT_CREATE = exports.DESC_COMMAND_SANDBOX_SNAPSHOT_LIST = exports.DESC_COMMAND_SANDBOX_SNAPSHOT = exports.TXT_SANDBOX_COMMAND_KILLED = exports.OPTION_SANDBOX_COMMAND_FOLLOW = exports.OPTION_SANDBOX_COMMAND_ID = exports.DESC_COMMAND_SANDBOX_EXEC_KILL = exports.DESC_COMMAND_SANDBOX_EXEC_LOGS = exports.DESC_COMMAND_SANDBOX_EXEC_STATUS = exports.DESC_COMMAND_SANDBOX_EXEC_LIST = exports.TXT_SANDBOX_WAITING_START = exports.TXT_SANDBOX_WAITING_STOP = exports.TXT_SANDBOX_WAITING_APP = exports.TXT_SANDBOX_WAITING_SETUP = exports.TXT_SANDBOX_WAITING_RUNNING = void 0;
|
|
12
|
-
exports.TXT_PROJECT_NONE = exports.ERR_PROJECT_NO_PROJECTS = exports.ERR_PROJECT_NOT_FOUND = exports.TXT_LOGIN_SELECT_PROJECT = exports.TXT_PROJECT_SET_CLEARED = exports.TXT_PROJECT_SET_SUCCESS = exports.DESC_COMMAND_PROJECT_GET = exports.ARG_COMMAND_PROJECT_NAME = exports.DESC_COMMAND_PROJECT_SET = exports.DESC_COMMAND_PROJECT_LIST = exports.DESC_COMMAND_PROJECT = exports.ERR_LOGIN_INVALID_BASE_URL = exports.ERR_LOGIN_NO_PROJECT_FOUND = exports.ERR_LOGIN_NO_WORKSPACE_FOUND = exports.ERR_LOGIN_NO_WORKSPACES = exports.
|
|
12
|
+
exports.TXT_PROJECT_NONE = exports.ERR_PROJECT_NO_PROJECTS = exports.ERR_PROJECT_NOT_FOUND = exports.TXT_LOGIN_SELECT_PROJECT = exports.TXT_PROJECT_SET_CLEARED = exports.TXT_PROJECT_SET_SUCCESS = exports.DESC_COMMAND_PROJECT_GET = exports.ARG_COMMAND_PROJECT_NAME = exports.DESC_COMMAND_PROJECT_SET = exports.DESC_COMMAND_PROJECT_LIST = exports.DESC_COMMAND_PROJECT = exports.ERR_LOGIN_INVALID_BASE_URL = exports.ERR_LOGIN_NO_PROJECT_FOUND = exports.ERR_LOGIN_NO_WORKSPACE_FOUND = exports.ERR_LOGIN_NO_WORKSPACES = exports.ERR_LOGIN_HTTP_SUCCESS = exports.ERR_LOGIN_HTTP_FAILED = exports.TXT_LOGIN_OAUTH = exports.ERR_LOGIN_HTTP_SERVER_PORT_TAKEN = exports.TXT_LOGIN_SUCCESS = exports.TXT_LOGIN_SELECT_WORKSPACE = exports.TXT_LOGIN_ENTER_BASE_URL = exports.TXT_LOGIN_SELECT_REGION = exports.TXT_WORKSPACE_NONE = exports.TXT_WORKSPACE_SET_SUCCESS = exports.ARG_COMMAND_WORKSPACE = exports.DESC_COMMAND_WORKSPACE_GET = exports.DESC_COMMAND_WORKSPACE_SET = exports.DESC_COMMAND_WORKSPACE_LIST = exports.DESC_COMMAND_WORKSPACE = exports.TXT_LOGOUT_SUCCESS = exports.DESC_COMMAND_LOGOUT = exports.DESC_COMMAND_LOGIN = exports.ERR_WHOAMI_LOGOUT = exports.TXT_WHOAMI_NO_PROJECT = exports.TXT_WHOAMI_NO_WORKSPACE = exports.DESC_COMMAND_WHOAMI = exports.TXT_SANDBOX_EXEC_FAILED = exports.TXT_SANDBOX_EXEC_INPROGRESS = exports.TXT_SANDBOX_EXEC_SUCCESS = void 0;
|
|
13
13
|
const utils_1 = require("./utils");
|
|
14
14
|
exports.ERR_REST_API_GENERAL_ERROR = 'Something went wrong';
|
|
15
15
|
exports.ERR_REST_API_CONNECT_ERROR = 'Connection refused. Check selected endpoint';
|
|
@@ -563,6 +563,11 @@ const TXT_SANDBOX_EXEC_INPROGRESS = (id) => `Command in progress: ${id}`;
|
|
|
563
563
|
exports.TXT_SANDBOX_EXEC_INPROGRESS = TXT_SANDBOX_EXEC_INPROGRESS;
|
|
564
564
|
const TXT_SANDBOX_EXEC_FAILED = (id) => `Command failed: ${id}`;
|
|
565
565
|
exports.TXT_SANDBOX_EXEC_FAILED = TXT_SANDBOX_EXEC_FAILED;
|
|
566
|
+
// Whoami command
|
|
567
|
+
exports.DESC_COMMAND_WHOAMI = 'Check login information';
|
|
568
|
+
exports.TXT_WHOAMI_NO_WORKSPACE = 'Not set. Run `bdy ws set` to set a workspace';
|
|
569
|
+
exports.TXT_WHOAMI_NO_PROJECT = 'Not set. Run `bdy proj set` to set a project';
|
|
570
|
+
exports.ERR_WHOAMI_LOGOUT = 'Not logged in. Run `bdy login` to authenticate.';
|
|
566
571
|
// Login command
|
|
567
572
|
exports.DESC_COMMAND_LOGIN = 'Log in to Buddy';
|
|
568
573
|
exports.DESC_COMMAND_LOGOUT = 'Log out from Buddy';
|
|
@@ -578,10 +583,12 @@ exports.TXT_WORKSPACE_SET_SUCCESS = TXT_WORKSPACE_SET_SUCCESS;
|
|
|
578
583
|
exports.TXT_WORKSPACE_NONE = 'No workspace configured. Run "bdy login" or "bdy workspace set" first.';
|
|
579
584
|
exports.TXT_LOGIN_SELECT_REGION = 'Select region:';
|
|
580
585
|
exports.TXT_LOGIN_ENTER_BASE_URL = 'Enter your Buddy instance URL (e.g., buddy.company.com):';
|
|
581
|
-
const TXT_LOGIN_ENTER_TOKEN = (url) => `Enter your personal access token (get your personal access token at: ${url}):`;
|
|
582
|
-
exports.TXT_LOGIN_ENTER_TOKEN = TXT_LOGIN_ENTER_TOKEN;
|
|
583
586
|
exports.TXT_LOGIN_SELECT_WORKSPACE = 'Select workspace:';
|
|
584
587
|
exports.TXT_LOGIN_SUCCESS = 'Logged in successfully!';
|
|
588
|
+
exports.ERR_LOGIN_HTTP_SERVER_PORT_TAKEN = 'Cant start local http server to authorize';
|
|
589
|
+
exports.TXT_LOGIN_OAUTH = 'Starting authorization process...';
|
|
590
|
+
exports.ERR_LOGIN_HTTP_FAILED = 'Failed to authorize. Try again...';
|
|
591
|
+
exports.ERR_LOGIN_HTTP_SUCCESS = 'Authorized. You can now safely close this browser tab';
|
|
585
592
|
exports.ERR_LOGIN_NO_WORKSPACES = 'No workspaces found for this token';
|
|
586
593
|
exports.ERR_LOGIN_NO_WORKSPACE_FOUND = 'Provided workspace has been not found';
|
|
587
594
|
exports.ERR_LOGIN_NO_PROJECT_FOUND = 'Provided project has been not found';
|
package/distTs/src/tunnel/cfg.js
CHANGED
|
@@ -172,6 +172,17 @@ class Cfg {
|
|
|
172
172
|
this.json.apiToken = token;
|
|
173
173
|
this.save();
|
|
174
174
|
}
|
|
175
|
+
setApiClient(clientId, clientSecret) {
|
|
176
|
+
if (!clientId || !clientSecret) {
|
|
177
|
+
delete this.json.apiClientId;
|
|
178
|
+
delete this.json.apiClientSecret;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
this.json.apiClientId = clientId;
|
|
182
|
+
this.json.apiClientSecret = clientSecret;
|
|
183
|
+
}
|
|
184
|
+
this.save();
|
|
185
|
+
}
|
|
175
186
|
setWhitelist(whitelist) {
|
|
176
187
|
if (!whitelist || !whitelist.length)
|
|
177
188
|
delete this.json.whitelist;
|
|
@@ -192,6 +203,12 @@ class Cfg {
|
|
|
192
203
|
getApiToken() {
|
|
193
204
|
return this.json.apiToken || '';
|
|
194
205
|
}
|
|
206
|
+
getApiClientId() {
|
|
207
|
+
return this.json.apiClientId || '';
|
|
208
|
+
}
|
|
209
|
+
getApiClientSecret() {
|
|
210
|
+
return this.json.apiClientSecret || '';
|
|
211
|
+
}
|
|
195
212
|
getTokenHost() {
|
|
196
213
|
const token = this.getToken();
|
|
197
214
|
if (!token) {
|
|
@@ -11,9 +11,11 @@ const texts_1 = require("../../texts");
|
|
|
11
11
|
const tunnel_1 = require("../../types/tunnel");
|
|
12
12
|
class ServerHttp1 extends events_1.default {
|
|
13
13
|
server;
|
|
14
|
+
host;
|
|
14
15
|
constructor(host) {
|
|
15
16
|
super();
|
|
16
|
-
this.
|
|
17
|
+
this.host = host;
|
|
18
|
+
this.server = http_1.default.createServer((req, res) => this.processRequest(req, res));
|
|
17
19
|
this.server.on('connection', (socket) => {
|
|
18
20
|
socket.id = (0, uuid_1.v4)();
|
|
19
21
|
this.emit(tunnel_1.TUNNEL_HTTP_SOCKET.OPEN, socket);
|
|
@@ -46,7 +48,10 @@ class ServerHttp1 extends events_1.default {
|
|
|
46
48
|
method: logRequest.method,
|
|
47
49
|
setHost: false,
|
|
48
50
|
path: logRequest.url,
|
|
49
|
-
headers:
|
|
51
|
+
headers: {
|
|
52
|
+
...logRequest.headers,
|
|
53
|
+
host: this.host
|
|
54
|
+
},
|
|
50
55
|
});
|
|
51
56
|
if (logRequest.requestBody.data.length > 0)
|
|
52
57
|
req.write(logRequest.requestBody.data);
|
|
@@ -60,9 +65,9 @@ class ServerHttp1 extends events_1.default {
|
|
|
60
65
|
});
|
|
61
66
|
req.end();
|
|
62
67
|
}
|
|
63
|
-
checkHostHeader(req, res
|
|
68
|
+
checkHostHeader(req, res) {
|
|
64
69
|
const headerHost = (req.headers.host || '').split(':')[0];
|
|
65
|
-
if (headerHost === host)
|
|
70
|
+
if (headerHost === this.host)
|
|
66
71
|
return true;
|
|
67
72
|
else {
|
|
68
73
|
res.statusCode = 421;
|
|
@@ -70,8 +75,8 @@ class ServerHttp1 extends events_1.default {
|
|
|
70
75
|
return false;
|
|
71
76
|
}
|
|
72
77
|
}
|
|
73
|
-
async processRequest(req, res
|
|
74
|
-
if (!this.checkHostHeader(req, res
|
|
78
|
+
async processRequest(req, res) {
|
|
79
|
+
if (!this.checkHostHeader(req, res))
|
|
75
80
|
return;
|
|
76
81
|
logger_1.default.debug((0, texts_1.LOG_HTTP1_REQUEST)(req.method, req.url));
|
|
77
82
|
this.emit(tunnel_1.TUNNEL_EVENT.HTTP_REQUEST, req, res);
|
|
@@ -11,9 +11,11 @@ const texts_1 = require("../../texts");
|
|
|
11
11
|
const tunnel_1 = require("../../types/tunnel");
|
|
12
12
|
class ServerHttp2 extends events_1.default {
|
|
13
13
|
server;
|
|
14
|
+
host;
|
|
14
15
|
constructor(host) {
|
|
15
16
|
super();
|
|
16
|
-
this.
|
|
17
|
+
this.host = host;
|
|
18
|
+
this.server = http2_1.default.createServer((req, res) => this.processRequest(req, res));
|
|
17
19
|
this.server.on('session', (session) => {
|
|
18
20
|
session.id = (0, uuid_1.v4)();
|
|
19
21
|
this.emit(tunnel_1.TUNNEL_EVENT.HTTP_SESSION_OPEN, session);
|
|
@@ -43,7 +45,10 @@ class ServerHttp2 extends events_1.default {
|
|
|
43
45
|
let client = http2_1.default.connect(`http://localhost:${address.port}`, {
|
|
44
46
|
maxSessionMemory: 100,
|
|
45
47
|
});
|
|
46
|
-
let req = client.request(
|
|
48
|
+
let req = client.request({
|
|
49
|
+
...logRequest.headers,
|
|
50
|
+
':authority': this.host
|
|
51
|
+
});
|
|
47
52
|
if (logRequest.requestBody.data.length > 0)
|
|
48
53
|
req.write(logRequest.requestBody.data);
|
|
49
54
|
req.on('response', () => {
|
|
@@ -64,9 +69,12 @@ class ServerHttp2 extends events_1.default {
|
|
|
64
69
|
});
|
|
65
70
|
req.end();
|
|
66
71
|
}
|
|
67
|
-
checkHostHeader(req, res
|
|
72
|
+
checkHostHeader(req, res) {
|
|
73
|
+
logger_js_1.default.info('checkHostHeader');
|
|
74
|
+
logger_js_1.default.info(this.host);
|
|
75
|
+
logger_js_1.default.info(req.headers[':authority']);
|
|
68
76
|
const headerHost = (req.headers[':authority'] || '').split(':')[0];
|
|
69
|
-
if (headerHost === host)
|
|
77
|
+
if (headerHost === this.host)
|
|
70
78
|
return true;
|
|
71
79
|
else {
|
|
72
80
|
res.statusCode = 421;
|
|
@@ -74,8 +82,8 @@ class ServerHttp2 extends events_1.default {
|
|
|
74
82
|
return false;
|
|
75
83
|
}
|
|
76
84
|
}
|
|
77
|
-
async processRequest(req, res
|
|
78
|
-
if (!this.checkHostHeader(req, res
|
|
85
|
+
async processRequest(req, res) {
|
|
86
|
+
if (!this.checkHostHeader(req, res))
|
|
79
87
|
return;
|
|
80
88
|
logger_js_1.default.debug((0, texts_1.LOG_HTTP2_REQUEST)(req.method, req.url));
|
|
81
89
|
this.emit(tunnel_1.TUNNEL_EVENT.HTTP_REQUEST, req, res);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bdy",
|
|
3
3
|
"preferGlobal": false,
|
|
4
|
-
"version": "1.16.
|
|
4
|
+
"version": "1.16.16-dev",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"scripts": {
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"eventsource": "4.0.0",
|
|
32
32
|
"fastify": "4.28.1",
|
|
33
33
|
"fdir": "6.5.0",
|
|
34
|
+
"open": "11.0.0",
|
|
34
35
|
"fflate": "0.8.2",
|
|
35
36
|
"human-id": "^4.1.3",
|
|
36
37
|
"isbinaryfile": "5.0.2",
|