@theia/terminal 1.73.0-next.43 → 1.73.0-next.51
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/lib/node/shell-terminal-server.d.ts +7 -0
- package/lib/node/shell-terminal-server.d.ts.map +1 -1
- package/lib/node/shell-terminal-server.js +69 -0
- package/lib/node/shell-terminal-server.js.map +1 -1
- package/lib/node/shell-terminal-server.spec.js +99 -0
- package/lib/node/shell-terminal-server.spec.js.map +1 -1
- package/package.json +9 -9
- package/src/node/shell-terminal-server.spec.ts +119 -1
- package/src/node/shell-terminal-server.ts +70 -0
|
@@ -13,6 +13,13 @@ export declare class ShellTerminalServer extends BaseTerminalServer implements I
|
|
|
13
13
|
readonly collections: MultiKeyMap<string, EnvironmentVariableCollectionWithPersistence>;
|
|
14
14
|
constructor(shellFactory: ShellProcessFactory, processManager: ProcessManager, logger: ILogger);
|
|
15
15
|
create(options: IShellTerminalServerOptions): Promise<number>;
|
|
16
|
+
/**
|
|
17
|
+
* Validates and sanitizes terminal options received from the client.
|
|
18
|
+
* Invalid values are replaced with safe defaults rather than rejecting the request,
|
|
19
|
+
* so legitimate users with misconfigured preferences still get a working terminal.
|
|
20
|
+
*/
|
|
21
|
+
protected validateTerminalOptions(options: IShellTerminalServerOptions): void;
|
|
22
|
+
protected isValidShell(shell: string): boolean;
|
|
16
23
|
private spawnAsPromised;
|
|
17
24
|
hasChildProcesses(processId: number | undefined): Promise<boolean>;
|
|
18
25
|
applyToProcessEnvironment(cwdUri: URI, env: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-terminal-server.d.ts","sourceRoot":"","sources":["../../src/node/shell-terminal-server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"shell-terminal-server.d.ts","sourceRoot":"","sources":["../../src/node/shell-terminal-server.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAe,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,cAAc,EAAmB,MAAM,yBAAyB,CAAC;AAG1E,OAAO,EACH,4CAA4C,EAA+C,yCAAyC,EACpI,oBAAoB,EAAE,2BAA2B,EACpD,MACQ,mCAAmC,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,2DAA2D,CAAC;AAa3F,qBACa,mBAAoB,SAAQ,kBAAmB,YAAW,oBAAoB;IAMtD,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,mBAAmB;IAL3D,SAAS,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAEvE,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,4CAA4C,CAAC,CAAsB;gBAGzD,YAAY,EAAE,mBAAmB,EACzD,cAAc,EAAE,cAAc,EAClB,MAAM,EAAE,OAAO;IAIjD,MAAM,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,MAAM,CAAC;IAgBnE;;;;OAIG;IACH,SAAS,CAAC,uBAAuB,CAAC,OAAO,EAAE,2BAA2B,GAAG,IAAI;IAiD7E,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAe9C,OAAO,CAAC,eAAe;IAoBhB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IAuCzE,yBAAyB,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI;IA4BnF,cAAc,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAUrD,aAAa,CAAC,mBAAmB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAC3E,UAAU,EAAE,yCAAyC,GAAG,IAAI;IAKhE,OAAO,CAAC,eAAe;IASvB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAMzC,gBAAgB,CAAC,mBAAmB,EAAE,MAAM,GAAG,IAAI;IAKnD,OAAO,CAAC,iBAAiB;IAIzB,SAAS,CAAC,kBAAkB,IAAI,IAAI;IAoB9B,0CAA0C,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,MAAM,GAAG,cAAc,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;IAcrH,oBAAoB,IAAI,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,yCAAyC,CAAC,EAAE,CAAC;CAShH"}
|
|
@@ -18,6 +18,7 @@ const tslib_1 = require("tslib");
|
|
|
18
18
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
19
19
|
// *****************************************************************************
|
|
20
20
|
const child_process_1 = require("child_process");
|
|
21
|
+
const fs = require("fs");
|
|
21
22
|
const inversify_1 = require("@theia/core/shared/inversify");
|
|
22
23
|
const logger_1 = require("@theia/core/lib/common/logger");
|
|
23
24
|
const environment_utils_1 = require("@theia/core/lib/node/environment-utils");
|
|
@@ -37,6 +38,7 @@ let ShellTerminalServer = class ShellTerminalServer extends base_terminal_server
|
|
|
37
38
|
}
|
|
38
39
|
async create(options) {
|
|
39
40
|
try {
|
|
41
|
+
this.validateTerminalOptions(options);
|
|
40
42
|
if (options.strictEnv !== true) {
|
|
41
43
|
options.env = this.environmentUtils.mergeProcessEnv(options.env);
|
|
42
44
|
this.applyToProcessEnvironment(core_1.URI.fromFilePath((0, shell_process_1.getRootPath)(options.rootURI)), options.env);
|
|
@@ -50,6 +52,73 @@ let ShellTerminalServer = class ShellTerminalServer extends base_terminal_server
|
|
|
50
52
|
return -1;
|
|
51
53
|
}
|
|
52
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Validates and sanitizes terminal options received from the client.
|
|
57
|
+
* Invalid values are replaced with safe defaults rather than rejecting the request,
|
|
58
|
+
* so legitimate users with misconfigured preferences still get a working terminal.
|
|
59
|
+
*/
|
|
60
|
+
validateTerminalOptions(options) {
|
|
61
|
+
// Validate shell: must be an existing, executable file. Fall back to default otherwise.
|
|
62
|
+
if (options.shell !== undefined) {
|
|
63
|
+
if (typeof options.shell !== 'string' || !this.isValidShell(options.shell)) {
|
|
64
|
+
this.logger.warn(`Invalid shell "${options.shell}": falling back to default shell.`);
|
|
65
|
+
options.shell = undefined;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Validate rootURI: must resolve to an existing directory.
|
|
69
|
+
if (options.rootURI !== undefined) {
|
|
70
|
+
try {
|
|
71
|
+
const rootPath = (0, shell_process_1.getRootPath)(options.rootURI);
|
|
72
|
+
if (!fs.existsSync(rootPath) || !fs.statSync(rootPath).isDirectory()) {
|
|
73
|
+
this.logger.warn(`Invalid rootURI "${options.rootURI}": falling back to home directory.`);
|
|
74
|
+
options.rootURI = undefined;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
this.logger.warn(`Invalid rootURI "${options.rootURI}": falling back to home directory.`);
|
|
79
|
+
options.rootURI = undefined;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Validate cols/rows: must be positive integers within reasonable bounds.
|
|
83
|
+
if (options.cols !== undefined) {
|
|
84
|
+
if (typeof options.cols !== 'number' || !Number.isInteger(options.cols) || options.cols < 1 || options.cols > 500) {
|
|
85
|
+
options.cols = undefined;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (options.rows !== undefined) {
|
|
89
|
+
if (typeof options.rows !== 'number' || !Number.isInteger(options.rows) || options.rows < 1 || options.rows > 500) {
|
|
90
|
+
options.rows = undefined;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Validate args: must be a string array or a single string.
|
|
94
|
+
if (options.args !== undefined) {
|
|
95
|
+
if (typeof options.args === 'string') {
|
|
96
|
+
// single string is fine
|
|
97
|
+
}
|
|
98
|
+
else if (Array.isArray(options.args)) {
|
|
99
|
+
if (!options.args.every(arg => typeof arg === 'string')) {
|
|
100
|
+
options.args = undefined;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
options.args = undefined;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
isValidShell(shell) {
|
|
109
|
+
try {
|
|
110
|
+
// On Windows, cmd.exe and powershell.exe are resolved from PATH,
|
|
111
|
+
// so we only check accessibility for absolute paths.
|
|
112
|
+
if (os_1.isWindows && !/[/\\]/.test(shell)) {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
fs.accessSync(shell, fs.constants.X_OK);
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
53
122
|
// copied and modified from https://github.com/microsoft/vscode/blob/4636be2b71c87bfb0bfe3c94278b447a5efcc1f1/src/vs/workbench/contrib/debug/node/terminals.ts#L32-L75
|
|
54
123
|
spawnAsPromised(command, args) {
|
|
55
124
|
return new Promise((resolve, reject) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-terminal-server.js","sourceRoot":"","sources":["../../src/node/shell-terminal-server.ts"],"names":[],"mappings":";;;;AAAA,gFAAgF;AAChF,0CAA0C;AAC1C,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;AAChF,iDAAqC;
|
|
1
|
+
{"version":3,"file":"shell-terminal-server.js","sourceRoot":"","sources":["../../src/node/shell-terminal-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,6 +16,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
16
16
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
17
17
|
// *****************************************************************************
|
|
18
18
|
const chai = require("chai");
|
|
19
|
+
const os = require("os");
|
|
20
|
+
const path = require("path");
|
|
21
|
+
const file_uri_1 = require("@theia/core/lib/common/file-uri");
|
|
19
22
|
const terminal_test_container_1 = require("./test/terminal-test-container");
|
|
20
23
|
const shell_terminal_protocol_1 = require("../common/shell-terminal-protocol");
|
|
21
24
|
/**
|
|
@@ -32,5 +35,101 @@ describe('ShellServer', function () {
|
|
|
32
35
|
const createResult = shellTerminalServer.create({});
|
|
33
36
|
expect(await createResult).to.be.greaterThan(-1);
|
|
34
37
|
});
|
|
38
|
+
describe('validateTerminalOptions', () => {
|
|
39
|
+
// Access the protected method for direct testing
|
|
40
|
+
function validate(options) {
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
+
shellTerminalServer.validateTerminalOptions(options);
|
|
43
|
+
return options;
|
|
44
|
+
}
|
|
45
|
+
it('should accept valid options unchanged', () => {
|
|
46
|
+
const options = validate({ cols: 80, rows: 24 });
|
|
47
|
+
expect(options.cols).to.equal(80);
|
|
48
|
+
expect(options.rows).to.equal(24);
|
|
49
|
+
});
|
|
50
|
+
it('should reset cols/rows outside valid range', () => {
|
|
51
|
+
const options = validate({ cols: -1, rows: 9999 });
|
|
52
|
+
expect(options.cols).to.be.undefined;
|
|
53
|
+
expect(options.rows).to.be.undefined;
|
|
54
|
+
});
|
|
55
|
+
it('should reset non-integer cols/rows', () => {
|
|
56
|
+
const options = validate({ cols: 80.5, rows: NaN });
|
|
57
|
+
expect(options.cols).to.be.undefined;
|
|
58
|
+
expect(options.rows).to.be.undefined;
|
|
59
|
+
});
|
|
60
|
+
it('should accept valid string args', () => {
|
|
61
|
+
const options = validate({ args: ['-l', '--color'] });
|
|
62
|
+
expect(options.args).to.deep.equal(['-l', '--color']);
|
|
63
|
+
});
|
|
64
|
+
it('should accept a single string as args', () => {
|
|
65
|
+
const options = validate({ args: '-l' });
|
|
66
|
+
expect(options.args).to.equal('-l');
|
|
67
|
+
});
|
|
68
|
+
it('should reset args with non-string elements', () => {
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
70
|
+
const options = validate({ args: ['-l', 42] });
|
|
71
|
+
expect(options.args).to.be.undefined;
|
|
72
|
+
});
|
|
73
|
+
it('should reset non-array non-string args', () => {
|
|
74
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
75
|
+
const options = validate({ args: { cmd: 'evil' } });
|
|
76
|
+
expect(options.args).to.be.undefined;
|
|
77
|
+
});
|
|
78
|
+
it('should accept rootURI pointing to an existing directory', () => {
|
|
79
|
+
const uri = file_uri_1.FileUri.create(os.tmpdir()).toString();
|
|
80
|
+
const options = validate({ rootURI: uri });
|
|
81
|
+
expect(options.rootURI).to.equal(uri);
|
|
82
|
+
});
|
|
83
|
+
it('should reset rootURI pointing to a non-existent path', () => {
|
|
84
|
+
const options = validate({ rootURI: 'file:///nonexistent/path/xyz123' });
|
|
85
|
+
expect(options.rootURI).to.be.undefined;
|
|
86
|
+
});
|
|
87
|
+
it('should reset rootURI pointing to a file instead of directory', () => {
|
|
88
|
+
const filePath = path.join(os.tmpdir(), 'theia-test-' + Date.now());
|
|
89
|
+
require('fs').writeFileSync(filePath, 'test');
|
|
90
|
+
try {
|
|
91
|
+
const options = validate({ rootURI: file_uri_1.FileUri.create(filePath).toString() });
|
|
92
|
+
expect(options.rootURI).to.be.undefined;
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
require('fs').unlinkSync(filePath);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
it('should reset shell that does not exist', () => {
|
|
99
|
+
const options = validate({ shell: '/nonexistent/shell' });
|
|
100
|
+
expect(options.shell).to.be.undefined;
|
|
101
|
+
});
|
|
102
|
+
it('should accept a valid shell', () => {
|
|
103
|
+
// process.execPath is the Node binary used to run the tests, so it always exists
|
|
104
|
+
// and is executable on every platform - making it a reliable cross-platform shell value.
|
|
105
|
+
const options = validate({ shell: process.execPath });
|
|
106
|
+
expect(options.shell).to.equal(process.execPath);
|
|
107
|
+
});
|
|
108
|
+
it('should reset non-string shell type', () => {
|
|
109
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
110
|
+
const options = validate({ shell: 42 });
|
|
111
|
+
expect(options.shell).to.be.undefined;
|
|
112
|
+
});
|
|
113
|
+
it('should reset malformed rootURI', () => {
|
|
114
|
+
const options = validate({ rootURI: 'not-a-valid-uri' });
|
|
115
|
+
expect(options.rootURI).to.be.undefined;
|
|
116
|
+
});
|
|
117
|
+
it('should reject cols: 0 (below minimum)', () => {
|
|
118
|
+
const options = validate({ cols: 0 });
|
|
119
|
+
expect(options.cols).to.be.undefined;
|
|
120
|
+
});
|
|
121
|
+
it('should accept cols: 500 (upper boundary)', () => {
|
|
122
|
+
const options = validate({ cols: 500 });
|
|
123
|
+
expect(options.cols).to.equal(500);
|
|
124
|
+
});
|
|
125
|
+
it('should reject cols: 501 (above maximum)', () => {
|
|
126
|
+
const options = validate({ cols: 501 });
|
|
127
|
+
expect(options.cols).to.be.undefined;
|
|
128
|
+
});
|
|
129
|
+
it('should accept rows: 1 (lower boundary)', () => {
|
|
130
|
+
const options = validate({ rows: 1 });
|
|
131
|
+
expect(options.rows).to.equal(1);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
35
134
|
});
|
|
36
135
|
//# sourceMappingURL=shell-terminal-server.spec.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-terminal-server.spec.js","sourceRoot":"","sources":["../../src/node/shell-terminal-server.spec.ts"],"names":[],"mappings":";;AAAA,gFAAgF;AAChF,0CAA0C;AAC1C,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;AAChF,6BAA6B;AAC7B,4EAA6E;AAC7E,+
|
|
1
|
+
{"version":3,"file":"shell-terminal-server.spec.js","sourceRoot":"","sources":["../../src/node/shell-terminal-server.spec.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theia/terminal",
|
|
3
|
-
"version": "1.73.0-next.
|
|
3
|
+
"version": "1.73.0-next.51+154e74fa4",
|
|
4
4
|
"description": "Theia - Terminal Extension",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@theia/core": "1.73.0-next.
|
|
7
|
-
"@theia/editor": "1.73.0-next.
|
|
8
|
-
"@theia/file-search": "1.73.0-next.
|
|
9
|
-
"@theia/filesystem": "1.73.0-next.
|
|
10
|
-
"@theia/process": "1.73.0-next.
|
|
11
|
-
"@theia/variable-resolver": "1.73.0-next.
|
|
12
|
-
"@theia/workspace": "1.73.0-next.
|
|
6
|
+
"@theia/core": "1.73.0-next.51+154e74fa4",
|
|
7
|
+
"@theia/editor": "1.73.0-next.51+154e74fa4",
|
|
8
|
+
"@theia/file-search": "1.73.0-next.51+154e74fa4",
|
|
9
|
+
"@theia/filesystem": "1.73.0-next.51+154e74fa4",
|
|
10
|
+
"@theia/process": "1.73.0-next.51+154e74fa4",
|
|
11
|
+
"@theia/variable-resolver": "1.73.0-next.51+154e74fa4",
|
|
12
|
+
"@theia/workspace": "1.73.0-next.51+154e74fa4",
|
|
13
13
|
"tslib": "^2.8.1",
|
|
14
14
|
"xterm": "^5.3.0",
|
|
15
15
|
"xterm-addon-fit": "^0.8.0",
|
|
@@ -56,5 +56,5 @@
|
|
|
56
56
|
"nyc": {
|
|
57
57
|
"extends": "../../configs/nyc.json"
|
|
58
58
|
},
|
|
59
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "154e74fa48e7b7427a902630240df88e7865f4b1"
|
|
60
60
|
}
|
|
@@ -14,8 +14,11 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
import * as chai from 'chai';
|
|
17
|
+
import * as os from 'os';
|
|
18
|
+
import * as path from 'path';
|
|
19
|
+
import { FileUri } from '@theia/core/lib/common/file-uri';
|
|
17
20
|
import { createTerminalTestContainer } from './test/terminal-test-container';
|
|
18
|
-
import { IShellTerminalServer } from '../common/shell-terminal-protocol';
|
|
21
|
+
import { IShellTerminalServer, IShellTerminalServerOptions } from '../common/shell-terminal-protocol';
|
|
19
22
|
|
|
20
23
|
/**
|
|
21
24
|
* Globals
|
|
@@ -37,4 +40,119 @@ describe('ShellServer', function (): void {
|
|
|
37
40
|
|
|
38
41
|
expect(await createResult).to.be.greaterThan(-1);
|
|
39
42
|
});
|
|
43
|
+
|
|
44
|
+
describe('validateTerminalOptions', () => {
|
|
45
|
+
|
|
46
|
+
// Access the protected method for direct testing
|
|
47
|
+
function validate(options: IShellTerminalServerOptions): IShellTerminalServerOptions {
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
49
|
+
(shellTerminalServer as any).validateTerminalOptions(options);
|
|
50
|
+
return options;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
it('should accept valid options unchanged', () => {
|
|
54
|
+
const options = validate({ cols: 80, rows: 24 });
|
|
55
|
+
expect(options.cols).to.equal(80);
|
|
56
|
+
expect(options.rows).to.equal(24);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should reset cols/rows outside valid range', () => {
|
|
60
|
+
const options = validate({ cols: -1, rows: 9999 });
|
|
61
|
+
expect(options.cols).to.be.undefined;
|
|
62
|
+
expect(options.rows).to.be.undefined;
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should reset non-integer cols/rows', () => {
|
|
66
|
+
const options = validate({ cols: 80.5, rows: NaN });
|
|
67
|
+
expect(options.cols).to.be.undefined;
|
|
68
|
+
expect(options.rows).to.be.undefined;
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should accept valid string args', () => {
|
|
72
|
+
const options = validate({ args: ['-l', '--color'] });
|
|
73
|
+
expect(options.args).to.deep.equal(['-l', '--color']);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should accept a single string as args', () => {
|
|
77
|
+
const options = validate({ args: '-l' });
|
|
78
|
+
expect(options.args).to.equal('-l');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should reset args with non-string elements', () => {
|
|
82
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
83
|
+
const options = validate({ args: ['-l', 42 as any] });
|
|
84
|
+
expect(options.args).to.be.undefined;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should reset non-array non-string args', () => {
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
89
|
+
const options = validate({ args: { cmd: 'evil' } as any });
|
|
90
|
+
expect(options.args).to.be.undefined;
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should accept rootURI pointing to an existing directory', () => {
|
|
94
|
+
const uri = FileUri.create(os.tmpdir()).toString();
|
|
95
|
+
const options = validate({ rootURI: uri });
|
|
96
|
+
expect(options.rootURI).to.equal(uri);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should reset rootURI pointing to a non-existent path', () => {
|
|
100
|
+
const options = validate({ rootURI: 'file:///nonexistent/path/xyz123' });
|
|
101
|
+
expect(options.rootURI).to.be.undefined;
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should reset rootURI pointing to a file instead of directory', () => {
|
|
105
|
+
const filePath = path.join(os.tmpdir(), 'theia-test-' + Date.now());
|
|
106
|
+
require('fs').writeFileSync(filePath, 'test');
|
|
107
|
+
try {
|
|
108
|
+
const options = validate({ rootURI: FileUri.create(filePath).toString() });
|
|
109
|
+
expect(options.rootURI).to.be.undefined;
|
|
110
|
+
} finally {
|
|
111
|
+
require('fs').unlinkSync(filePath);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should reset shell that does not exist', () => {
|
|
116
|
+
const options = validate({ shell: '/nonexistent/shell' });
|
|
117
|
+
expect(options.shell).to.be.undefined;
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should accept a valid shell', () => {
|
|
121
|
+
// process.execPath is the Node binary used to run the tests, so it always exists
|
|
122
|
+
// and is executable on every platform - making it a reliable cross-platform shell value.
|
|
123
|
+
const options = validate({ shell: process.execPath });
|
|
124
|
+
expect(options.shell).to.equal(process.execPath);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('should reset non-string shell type', () => {
|
|
128
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
129
|
+
const options = validate({ shell: 42 as any });
|
|
130
|
+
expect(options.shell).to.be.undefined;
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should reset malformed rootURI', () => {
|
|
134
|
+
const options = validate({ rootURI: 'not-a-valid-uri' });
|
|
135
|
+
expect(options.rootURI).to.be.undefined;
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should reject cols: 0 (below minimum)', () => {
|
|
139
|
+
const options = validate({ cols: 0 });
|
|
140
|
+
expect(options.cols).to.be.undefined;
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should accept cols: 500 (upper boundary)', () => {
|
|
144
|
+
const options = validate({ cols: 500 });
|
|
145
|
+
expect(options.cols).to.equal(500);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should reject cols: 501 (above maximum)', () => {
|
|
149
|
+
const options = validate({ cols: 501 });
|
|
150
|
+
expect(options.cols).to.be.undefined;
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should accept rows: 1 (lower boundary)', () => {
|
|
154
|
+
const options = validate({ rows: 1 });
|
|
155
|
+
expect(options.rows).to.equal(1);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
40
158
|
});
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
import { exec } from 'child_process';
|
|
17
|
+
import * as fs from 'fs';
|
|
17
18
|
|
|
18
19
|
import { inject, injectable, named } from '@theia/core/shared/inversify';
|
|
19
20
|
import { ILogger } from '@theia/core/lib/common/logger';
|
|
@@ -58,6 +59,7 @@ export class ShellTerminalServer extends BaseTerminalServer implements IShellTer
|
|
|
58
59
|
|
|
59
60
|
async create(options: IShellTerminalServerOptions): Promise<number> {
|
|
60
61
|
try {
|
|
62
|
+
this.validateTerminalOptions(options);
|
|
61
63
|
if (options.strictEnv !== true) {
|
|
62
64
|
options.env = this.environmentUtils.mergeProcessEnv(options.env);
|
|
63
65
|
this.applyToProcessEnvironment(URI.fromFilePath(getRootPath(options.rootURI)), options.env);
|
|
@@ -71,6 +73,74 @@ export class ShellTerminalServer extends BaseTerminalServer implements IShellTer
|
|
|
71
73
|
}
|
|
72
74
|
}
|
|
73
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Validates and sanitizes terminal options received from the client.
|
|
78
|
+
* Invalid values are replaced with safe defaults rather than rejecting the request,
|
|
79
|
+
* so legitimate users with misconfigured preferences still get a working terminal.
|
|
80
|
+
*/
|
|
81
|
+
protected validateTerminalOptions(options: IShellTerminalServerOptions): void {
|
|
82
|
+
// Validate shell: must be an existing, executable file. Fall back to default otherwise.
|
|
83
|
+
if (options.shell !== undefined) {
|
|
84
|
+
if (typeof options.shell !== 'string' || !this.isValidShell(options.shell)) {
|
|
85
|
+
this.logger.warn(`Invalid shell "${options.shell}": falling back to default shell.`);
|
|
86
|
+
options.shell = undefined;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Validate rootURI: must resolve to an existing directory.
|
|
91
|
+
if (options.rootURI !== undefined) {
|
|
92
|
+
try {
|
|
93
|
+
const rootPath = getRootPath(options.rootURI);
|
|
94
|
+
if (!fs.existsSync(rootPath) || !fs.statSync(rootPath).isDirectory()) {
|
|
95
|
+
this.logger.warn(`Invalid rootURI "${options.rootURI}": falling back to home directory.`);
|
|
96
|
+
options.rootURI = undefined;
|
|
97
|
+
}
|
|
98
|
+
} catch {
|
|
99
|
+
this.logger.warn(`Invalid rootURI "${options.rootURI}": falling back to home directory.`);
|
|
100
|
+
options.rootURI = undefined;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Validate cols/rows: must be positive integers within reasonable bounds.
|
|
105
|
+
if (options.cols !== undefined) {
|
|
106
|
+
if (typeof options.cols !== 'number' || !Number.isInteger(options.cols) || options.cols < 1 || options.cols > 500) {
|
|
107
|
+
options.cols = undefined;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (options.rows !== undefined) {
|
|
111
|
+
if (typeof options.rows !== 'number' || !Number.isInteger(options.rows) || options.rows < 1 || options.rows > 500) {
|
|
112
|
+
options.rows = undefined;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Validate args: must be a string array or a single string.
|
|
117
|
+
if (options.args !== undefined) {
|
|
118
|
+
if (typeof options.args === 'string') {
|
|
119
|
+
// single string is fine
|
|
120
|
+
} else if (Array.isArray(options.args)) {
|
|
121
|
+
if (!options.args.every(arg => typeof arg === 'string')) {
|
|
122
|
+
options.args = undefined;
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
options.args = undefined;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
protected isValidShell(shell: string): boolean {
|
|
131
|
+
try {
|
|
132
|
+
// On Windows, cmd.exe and powershell.exe are resolved from PATH,
|
|
133
|
+
// so we only check accessibility for absolute paths.
|
|
134
|
+
if (isWindows && !/[/\\]/.test(shell)) {
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
fs.accessSync(shell, fs.constants.X_OK);
|
|
138
|
+
return true;
|
|
139
|
+
} catch {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
74
144
|
// copied and modified from https://github.com/microsoft/vscode/blob/4636be2b71c87bfb0bfe3c94278b447a5efcc1f1/src/vs/workbench/contrib/debug/node/terminals.ts#L32-L75
|
|
75
145
|
private spawnAsPromised(command: string, args: string[]): Promise<string> {
|
|
76
146
|
return new Promise((resolve, reject) => {
|