zerogterm 0.2.0-alpha.2 → 0.3.0-alpha.1
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/dist/main/main/session-service.js +13 -5
- package/dist/main/main/ssh-inventory.js +4 -1
- package/dist/renderer/assets/index-Cs9gfbAs.js +17 -0
- package/dist/renderer/assets/{voice-worker-Bde9NFkO.js → voice-worker-DWb1dVxY.js} +6 -6
- package/dist/renderer/index.html +1 -1
- package/package.json +6 -2
- package/dist/renderer/assets/index-BWVjX0UX.js +0 -17
|
@@ -6,8 +6,13 @@ import { promisify } from 'node:util';
|
|
|
6
6
|
const execFileAsync = promisify(execFile);
|
|
7
7
|
const require = createRequire(import.meta.url);
|
|
8
8
|
const NAME = /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,48}$/;
|
|
9
|
-
/**
|
|
10
|
-
|
|
9
|
+
/**
|
|
10
|
+
* host, user@host, host:port, user@host:port — no shell metacharacters.
|
|
11
|
+
* Host and user must start alphanumeric: a leading '-' would be parsed by
|
|
12
|
+
* ssh's getopt as an option, and `-Fsome.cfg` can point ssh at an attacker
|
|
13
|
+
* -chosen config file (hence ProxyCommand) without any shell involvement.
|
|
14
|
+
*/
|
|
15
|
+
const SSH_TARGET = /^(?:([A-Za-z0-9][A-Za-z0-9._-]*)@)?([A-Za-z0-9][A-Za-z0-9.-]*)(?::(\d{1,5}))?$/;
|
|
11
16
|
export function validateSessionName(name) {
|
|
12
17
|
const value = name.trim();
|
|
13
18
|
if (!NAME.test(value)) {
|
|
@@ -32,7 +37,8 @@ export function validateSshTarget(input) {
|
|
|
32
37
|
const args = ['-tt'];
|
|
33
38
|
if (portText)
|
|
34
39
|
args.push('-p', portText);
|
|
35
|
-
|
|
40
|
+
// '--' ends option parsing, so the destination can never be read as a flag.
|
|
41
|
+
args.push('--', destination);
|
|
36
42
|
return { target: value, args };
|
|
37
43
|
}
|
|
38
44
|
export function parseWslDistributions(output) {
|
|
@@ -198,7 +204,9 @@ export class ScreenService {
|
|
|
198
204
|
this.onEvent?.('attached', fallback, true);
|
|
199
205
|
return { ...fallback };
|
|
200
206
|
}
|
|
201
|
-
|
|
207
|
+
// Session ids cross the IPC boundary from the renderer, so re-validate
|
|
208
|
+
// rather than trusting that createLocal produced this one.
|
|
209
|
+
const name = validateSessionName(id.slice('local:'.length));
|
|
202
210
|
this.spawnCommand(id, 'screen', ['-x', name], onData, onExit);
|
|
203
211
|
this.onEvent?.('attached', existing, true);
|
|
204
212
|
return { ...existing, status: 'connected', persistence: 'screen' };
|
|
@@ -226,7 +234,7 @@ export class ScreenService {
|
|
|
226
234
|
const fallback = this.fallbackLocalSessions.get(id);
|
|
227
235
|
if (fallback)
|
|
228
236
|
return fallback;
|
|
229
|
-
const name = id.slice('local:'.length);
|
|
237
|
+
const name = validateSessionName(id.slice('local:'.length));
|
|
230
238
|
return {
|
|
231
239
|
id,
|
|
232
240
|
name,
|
|
@@ -2,7 +2,10 @@ import { homedir } from 'node:os';
|
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
const TOKEN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
4
4
|
const HOST = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,253}$/;
|
|
5
|
-
|
|
5
|
+
// Must start alphanumeric like TOKEN/HOST above: the user is concatenated into
|
|
6
|
+
// `user@host`, so a leading '-' makes the whole destination look like an option
|
|
7
|
+
// to ssh's getopt (`-Fevil.cfg@host` reads an attacker-chosen config file).
|
|
8
|
+
const USER = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
6
9
|
const SCREEN = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,48}$/;
|
|
7
10
|
function words(value) {
|
|
8
11
|
const result = [];
|