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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bdy",
3
3
  "preferGlobal": false,
4
- "version": "1.16.14-dev",
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",
@@ -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
- authorization: `Bearer ${this.token}`,
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
- headers['content-type'] = 'application/json; charset=utf-8';
35
- bodyParsed = JSON.stringify(body);
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
- function getSecurityUrl(region, baseUrl) {
13
- switch (region) {
14
- case utils_1.REST_API_REGION.US:
15
- return 'https://app.buddy.works/security';
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 inputToken(region, baseUrl) {
56
- const securityUrl = getSecurityUrl(region, baseUrl);
57
- output_1.default.normal((0, texts_1.TXT_LOGIN_ENTER_TOKEN)(securityUrl));
58
- return await output_1.default.inputString();
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
- let token = options.token || process.env.BUDDY_TOKEN;
72
- let workspace = options.workspace || process.env.BUDDY_WORKSPACE;
73
- let project = options.project || process.env.BUDDY_PROJECT;
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
- token = await inputToken(region, api);
100
- }
101
- const client = new client_1.default(new URL(`https://${api}`), token);
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
- workspace = await output_1.default.selectWorkspace(w.workspaces);
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;
@@ -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);
@@ -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.TXT_LOGIN_SUCCESS = exports.TXT_LOGIN_SELECT_WORKSPACE = exports.TXT_LOGIN_ENTER_TOKEN = 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.TXT_SANDBOX_EXEC_FAILED = exports.TXT_SANDBOX_EXEC_INPROGRESS = exports.TXT_SANDBOX_EXEC_SUCCESS = 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.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';
@@ -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.server = http_1.default.createServer((req, res) => this.processRequest(req, res, host));
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: logRequest.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, host) {
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, host) {
74
- if (!this.checkHostHeader(req, res, host))
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.server = http2_1.default.createServer((req, res) => this.processRequest(req, res, host));
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(logRequest.headers);
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, host) {
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, host) {
78
- if (!this.checkHostHeader(req, res, host))
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.14-dev",
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",