Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d3dc5b8

Browse filesBrowse files
author
Akos Kitta
committed
fix: removed unsafe shell when executing process
Ref: PNX-3671 Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
1 parent e47fb2e commit d3dc5b8
Copy full SHA for d3dc5b8

12 files changed

+407
-221
lines changed

‎arduino-ide-extension/package.json

Copy file name to clipboardExpand all lines: arduino-ide-extension/package.json
+1-4Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,17 +104,14 @@
104104
"temp": "^0.9.1",
105105
"temp-dir": "^2.0.0",
106106
"tree-kill": "^1.2.1",
107-
"util": "^0.12.5",
108-
"which": "^1.3.1"
107+
"util": "^0.12.5"
109108
},
110109
"devDependencies": {
111110
"@octokit/rest": "^18.12.0",
112111
"@types/chai": "^4.2.7",
113-
"@types/chai-string": "^1.4.2",
114112
"@types/mocha": "^5.2.7",
115113
"@types/react-window": "^1.8.5",
116114
"chai": "^4.2.0",
117-
"chai-string": "^1.5.0",
118115
"decompress": "^4.2.0",
119116
"decompress-tarbz2": "^4.1.1",
120117
"decompress-targz": "^4.1.1",

‎arduino-ide-extension/src/common/protocol/executable-service.ts

Copy file name to clipboardExpand all lines: arduino-ide-extension/src/common/protocol/executable-service.ts
-1Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,5 @@ export interface ExecutableService {
55
clangdUri: string;
66
cliUri: string;
77
lsUri: string;
8-
fwuploaderUri: string;
98
}>;
109
}

‎arduino-ide-extension/src/node/arduino-daemon-impl.ts

Copy file name to clipboardExpand all lines: arduino-ide-extension/src/node/arduino-daemon-impl.ts
+6-13Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ export class ArduinoDaemonImpl
4444

4545
private _running = false;
4646
private _port = new Deferred<string>();
47-
private _execPath: string | undefined;
4847

4948
// Backend application lifecycle.
5049

@@ -68,7 +67,7 @@ export class ArduinoDaemonImpl
6867
async start(): Promise<string> {
6968
try {
7069
this.toDispose.dispose(); // This will `kill` the previously started daemon process, if any.
71-
const cliPath = await this.getExecPath();
70+
const cliPath = this.getExecPath();
7271
this.onData(`Starting daemon from ${cliPath}...`);
7372
const { daemon, port } = await this.spawnDaemonProcess();
7473
// Watchdog process for terminating the daemon process when the backend app terminates.
@@ -132,12 +131,8 @@ export class ArduinoDaemonImpl
132131
return this.onDaemonStoppedEmitter.event;
133132
}
134133

135-
async getExecPath(): Promise<string> {
136-
if (this._execPath) {
137-
return this._execPath;
138-
}
139-
this._execPath = await getExecPath('arduino-cli', this.onError.bind(this));
140-
return this._execPath;
134+
getExecPath(): string {
135+
return getExecPath('arduino-cli');
141136
}
142137

143138
protected async getSpawnArgs(): Promise<string[]> {
@@ -151,7 +146,7 @@ export class ArduinoDaemonImpl
151146
'--port',
152147
'0',
153148
'--config-file',
154-
`"${cliConfigPath}"`,
149+
cliConfigPath,
155150
'-v',
156151
];
157152
if (debug) {
@@ -173,10 +168,8 @@ export class ArduinoDaemonImpl
173168
daemon: ChildProcess;
174169
port: string;
175170
}> {
176-
const [cliPath, args] = await Promise.all([
177-
this.getExecPath(),
178-
this.getSpawnArgs(),
179-
]);
171+
const args = await this.getSpawnArgs();
172+
const cliPath = this.getExecPath();
180173
const ready = new Deferred<{ daemon: ChildProcess; port: string }>();
181174
const options = { shell: true };
182175
const daemon = spawn(`"${cliPath}"`, args, options);
+17-34Lines changed: 17 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,22 @@
1+
import { ILogger } from '@theia/core/lib/common/logger';
2+
import { inject, injectable, named } from '@theia/core/shared/inversify';
3+
import type { Port } from '../common/protocol';
14
import {
25
ArduinoFirmwareUploader,
36
FirmwareInfo,
47
} from '../common/protocol/arduino-firmware-uploader';
5-
import { injectable, inject, named } from '@theia/core/shared/inversify';
6-
import { ExecutableService, Port } from '../common/protocol';
78
import { getExecPath, spawnCommand } from './exec-util';
8-
import { ILogger } from '@theia/core/lib/common/logger';
99
import { MonitorManager } from './monitor-manager';
1010

1111
@injectable()
1212
export class ArduinoFirmwareUploaderImpl implements ArduinoFirmwareUploader {
13-
@inject(ExecutableService)
14-
protected executableService: ExecutableService;
15-
16-
protected _execPath: string | undefined;
17-
1813
@inject(ILogger)
1914
@named('fwuploader')
20-
protected readonly logger: ILogger;
21-
15+
private readonly logger: ILogger;
2216
@inject(MonitorManager)
23-
protected readonly monitorManager: MonitorManager;
24-
25-
protected onError(error: any): void {
26-
this.logger.error(error);
27-
}
28-
29-
async getExecPath(): Promise<string> {
30-
if (this._execPath) {
31-
return this._execPath;
32-
}
33-
this._execPath = await getExecPath('arduino-fwuploader');
34-
return this._execPath;
35-
}
36-
37-
async runCommand(args: string[]): Promise<any> {
38-
const execPath = await this.getExecPath();
39-
return await spawnCommand(`"${execPath}"`, args, this.onError.bind(this));
40-
}
17+
private readonly monitorManager: MonitorManager;
4118

42-
async uploadCertificates(command: string): Promise<any> {
19+
async uploadCertificates(command: string): Promise<string> {
4320
return await this.runCommand(['certificates', 'flash', command]);
4421
}
4522

@@ -70,14 +47,13 @@ export class ArduinoFirmwareUploaderImpl implements ArduinoFirmwareUploader {
7047
}
7148

7249
async flash(firmware: FirmwareInfo, port: Port): Promise<string> {
73-
let output;
7450
const board = {
7551
name: firmware.board_name,
7652
fqbn: firmware.board_fqbn,
7753
};
7854
try {
7955
await this.monitorManager.notifyUploadStarted(board.fqbn, port);
80-
output = await this.runCommand([
56+
const output = await this.runCommand([
8157
'firmware',
8258
'flash',
8359
'--fqbn',
@@ -87,11 +63,18 @@ export class ArduinoFirmwareUploaderImpl implements ArduinoFirmwareUploader {
8763
'--module',
8864
`${firmware.module}@${firmware.firmware_version}`,
8965
]);
90-
} catch (e) {
91-
throw e;
66+
return output;
9267
} finally {
9368
await this.monitorManager.notifyUploadFinished(board.fqbn, port);
94-
return output;
9569
}
9670
}
71+
72+
private onError(error: Error): void {
73+
this.logger.error(error);
74+
}
75+
76+
private async runCommand(args: string[]): Promise<string> {
77+
const execPath = getExecPath('arduino-fwuploader');
78+
return await spawnCommand(execPath, args, this.onError.bind(this));
79+
}
9780
}
+41-42Lines changed: 41 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import * as os from 'node:os';
21
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
32
import { MaybePromise } from '@theia/core/lib/common/types';
43
import { FileUri } from '@theia/core/lib/node/file-uri';
@@ -15,7 +14,7 @@ export class ClangFormatter implements Formatter {
1514
private readonly configService: ConfigService;
1615

1716
@inject(EnvVariablesServer)
18-
private readonly envVariableServer: EnvVariablesServer;
17+
private readonly envVariablesServer: EnvVariablesServer;
1918

2019
async format({
2120
content,
@@ -26,26 +25,19 @@ export class ClangFormatter implements Formatter {
2625
formatterConfigFolderUris: string[];
2726
options?: FormatterOptions;
2827
}): Promise<string> {
29-
const [execPath, style] = await Promise.all([
30-
this.execPath(),
31-
this.style(formatterConfigFolderUris, options),
32-
]);
28+
const execPath = this.execPath();
29+
const args = await this.styleArgs(formatterConfigFolderUris, options);
3330
const formatted = await spawnCommand(
34-
`"${execPath}"`,
35-
[style],
31+
execPath,
32+
args,
3633
console.error,
3734
content
3835
);
3936
return formatted;
4037
}
4138

42-
private _execPath: string | undefined;
43-
private async execPath(): Promise<string> {
44-
if (this._execPath) {
45-
return this._execPath;
46-
}
47-
this._execPath = await getExecPath('clang-format');
48-
return this._execPath;
39+
private execPath(): string {
40+
return getExecPath('clang-format');
4941
}
5042

5143
/**
@@ -60,10 +52,10 @@ export class ClangFormatter implements Formatter {
6052
*
6153
* See: https://github.com/arduino/arduino-ide/issues/566
6254
*/
63-
private async style(
55+
private async styleArgs(
6456
formatterConfigFolderUris: string[],
6557
options?: FormatterOptions
66-
): Promise<string> {
58+
): Promise<string[]> {
6759
const clangFormatPaths = await Promise.all([
6860
...formatterConfigFolderUris.map((uri) => this.clangConfigPath(uri)),
6961
this.clangConfigPath(this.configDirPath()),
@@ -72,11 +64,11 @@ export class ClangFormatter implements Formatter {
7264
const first = clangFormatPaths.filter(Boolean).shift();
7365
if (first) {
7466
console.debug(
75-
`Using ${ClangFormatFile} style configuration from '${first}'.`
67+
`Using ${clangFormatFilename} style configuration from '${first}'.`
7668
);
77-
return `-style=file:"${first}"`;
69+
return ['-style', `file:${first}`];
7870
}
79-
return `-style="${style(toClangOptions(options))}"`;
71+
return ['-style', style(toClangOptions(options))];
8072
}
8173

8274
private async dataDirPath(): Promise<string | undefined> {
@@ -88,7 +80,7 @@ export class ClangFormatter implements Formatter {
8880
}
8981

9082
private async configDirPath(): Promise<string> {
91-
const configDirUri = await this.envVariableServer.getConfigDirUri();
83+
const configDirUri = await this.envVariablesServer.getConfigDirUri();
9284
return FileUri.fsPath(configDirUri);
9385
}
9486

@@ -100,7 +92,7 @@ export class ClangFormatter implements Formatter {
10092
return undefined;
10193
}
10294
const folderPath = FileUri.fsPath(uri);
103-
const clangFormatPath = join(folderPath, ClangFormatFile);
95+
const clangFormatPath = join(folderPath, clangFormatFilename);
10496
try {
10597
await fs.access(clangFormatPath, constants.R_OK);
10698
return clangFormatPath;
@@ -115,7 +107,7 @@ interface ClangFormatOptions {
115107
readonly TabWidth: number;
116108
}
117109

118-
const ClangFormatFile = '.clang-format';
110+
export const clangFormatFilename = '.clang-format';
119111

120112
function toClangOptions(
121113
options?: FormatterOptions | undefined
@@ -129,30 +121,14 @@ function toClangOptions(
129121
return { UseTab: 'Never', TabWidth: 2 };
130122
}
131123

132-
export function style({ TabWidth, UseTab }: ClangFormatOptions): string {
133-
let styleArgument = JSON.stringify(styleJson({ TabWidth, UseTab })).replace(
134-
/[\\"]/g,
135-
'\\$&'
136-
);
137-
if (os.platform() === 'win32') {
138-
// Windows command interpreter does not use backslash escapes. This causes the argument to have alternate quoted and
139-
// unquoted sections.
140-
// Special characters in the unquoted sections must be caret escaped.
141-
const styleArgumentSplit = styleArgument.split('"');
142-
for (let i = 1; i < styleArgumentSplit.length; i += 2) {
143-
styleArgumentSplit[i] = styleArgumentSplit[i].replace(/[<>^|]/g, '^$&');
144-
}
145-
146-
styleArgument = styleArgumentSplit.join('"');
147-
}
148-
149-
return styleArgument;
124+
function style({ TabWidth, UseTab }: ClangFormatOptions): string {
125+
return stringifyConfiguration(styleJson({ TabWidth, UseTab }));
150126
}
151127

152128
function styleJson({
153129
TabWidth,
154130
UseTab,
155-
}: ClangFormatOptions): Record<string, unknown> {
131+
}: ClangFormatOptions): ClangConfiguration {
156132
// Source: https://github.com/arduino/tooling-project-assets/tree/main/other/clang-format-configuration
157133
const defaultConfig = require('../../src/node/default-formatter-config.json');
158134
return {
@@ -161,3 +137,26 @@ function styleJson({
161137
UseTab,
162138
};
163139
}
140+
141+
export type ClangStyleValue =
142+
| string
143+
| number
144+
| boolean
145+
| ClangStyleValue[]
146+
| { [key: string]: ClangStyleValue };
147+
export type ClangConfiguration = Record<string, ClangStyleValue>;
148+
149+
export function stringifyConfiguration(
150+
value: ClangStyleValue | ClangConfiguration
151+
): string {
152+
if (Array.isArray(value)) {
153+
return `[${value.map((item) => stringifyConfiguration(item)).join(', ')}]`;
154+
} else if (typeof value === 'object') {
155+
return `{${Object.entries(value)
156+
.map(([key, v]) => `${key}: ${stringifyConfiguration(v)}`)
157+
.join(', ')}}`;
158+
} else if (typeof value === 'string') {
159+
return `'${value}'`;
160+
}
161+
return String(value);
162+
}

‎arduino-ide-extension/src/node/config-service-impl.ts

Copy file name to clipboardExpand all lines: arduino-ide-extension/src/node/config-service-impl.ts
+4-9Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,8 @@ export class ConfigServiceImpl
222222
}
223223

224224
private async getFallbackCliConfig(): Promise<DefaultCliConfig> {
225-
const cliPath = await this.daemon.getExecPath();
226-
const rawJson = await spawnCommand(`"${cliPath}"`, [
225+
const cliPath = this.daemon.getExecPath();
226+
const rawJson = await spawnCommand(cliPath, [
227227
'config',
228228
'dump',
229229
'format',
@@ -233,13 +233,8 @@ export class ConfigServiceImpl
233233
}
234234

235235
private async initCliConfigTo(fsPathToDir: string): Promise<void> {
236-
const cliPath = await this.daemon.getExecPath();
237-
await spawnCommand(`"${cliPath}"`, [
238-
'config',
239-
'init',
240-
'--dest-dir',
241-
`"${fsPathToDir}"`,
242-
]);
236+
const cliPath = this.daemon.getExecPath();
237+
await spawnCommand(cliPath, ['config', 'init', '--dest-dir', fsPathToDir]);
243238
}
244239

245240
private async mapCliConfigToAppConfig(

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.