ssh-config 4.4.3 → 5.0.0
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/package.json +2 -2
- package/src/ssh-config.d.ts +10 -2
- package/src/ssh-config.js +40 -27
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ssh-config",
|
|
3
3
|
"description": "SSH config parser and stringifier",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "5.0.0",
|
|
5
5
|
"author": "Chen Yangjian (https://www.cyj.me)",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"mocha": "^8.2.1",
|
|
25
25
|
"nyc": "^15.1.0",
|
|
26
26
|
"sinon": "^17.0.1",
|
|
27
|
-
"typescript": "^4.
|
|
27
|
+
"typescript": "^5.4.4"
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
30
|
"lint": "eslint --ext ts .",
|
package/src/ssh-config.d.ts
CHANGED
|
@@ -9,14 +9,22 @@ export interface Directive {
|
|
|
9
9
|
after: string;
|
|
10
10
|
param: string;
|
|
11
11
|
separator: Separator;
|
|
12
|
-
value: string |
|
|
12
|
+
value: string | {
|
|
13
|
+
val: string;
|
|
14
|
+
separator: string;
|
|
15
|
+
quoted?: boolean;
|
|
16
|
+
}[];
|
|
13
17
|
quoted?: boolean;
|
|
14
18
|
}
|
|
15
19
|
export interface Section extends Directive {
|
|
16
20
|
config: SSHConfig;
|
|
17
21
|
}
|
|
18
22
|
export interface Match extends Section {
|
|
19
|
-
criteria: Record<string, string |
|
|
23
|
+
criteria: Record<string, string | {
|
|
24
|
+
val: string;
|
|
25
|
+
separator: string;
|
|
26
|
+
quoted?: boolean;
|
|
27
|
+
}[]>;
|
|
20
28
|
}
|
|
21
29
|
export interface Comment {
|
|
22
30
|
type: LineType.COMMENT;
|
package/src/ssh-config.js
CHANGED
|
@@ -3,7 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.LineType = void 0;
|
|
7
|
+
exports.parse = parse;
|
|
8
|
+
exports.stringify = stringify;
|
|
7
9
|
const glob_1 = __importDefault(require("./glob"));
|
|
8
10
|
const child_process_1 = require("child_process");
|
|
9
11
|
const os_1 = __importDefault(require("os"));
|
|
@@ -17,7 +19,7 @@ var LineType;
|
|
|
17
19
|
(function (LineType) {
|
|
18
20
|
LineType[LineType["DIRECTIVE"] = 1] = "DIRECTIVE";
|
|
19
21
|
LineType[LineType["COMMENT"] = 2] = "COMMENT";
|
|
20
|
-
})(LineType
|
|
22
|
+
})(LineType || (exports.LineType = LineType = {}));
|
|
21
23
|
const MULTIPLE_VALUE_PROPS = [
|
|
22
24
|
'IdentityFile',
|
|
23
25
|
'LocalForward',
|
|
@@ -69,7 +71,8 @@ function match(criteria, context) {
|
|
|
69
71
|
};
|
|
70
72
|
for (const key in criteria) {
|
|
71
73
|
const criterion = criteria[key];
|
|
72
|
-
|
|
74
|
+
const values = Array.isArray(criterion) ? criterion.map(({ val }) => val) : criterion;
|
|
75
|
+
if (!testCriterion(key, values)) {
|
|
73
76
|
return false;
|
|
74
77
|
}
|
|
75
78
|
}
|
|
@@ -133,7 +136,7 @@ class SSHConfig extends Array {
|
|
|
133
136
|
for (const line of this) {
|
|
134
137
|
if (line.type !== LineType.DIRECTIVE)
|
|
135
138
|
continue;
|
|
136
|
-
if (line.param === 'Host' && (0, glob_1.default)(line.value, context.params.Host)) {
|
|
139
|
+
if (line.param === 'Host' && (0, glob_1.default)(Array.isArray(line.value) ? line.value.map(({ val }) => val) : line.value, context.params.Host)) {
|
|
137
140
|
let canonicalizeHostName = false;
|
|
138
141
|
let canonicalDomains = [];
|
|
139
142
|
setProperty(line.param, line.value);
|
|
@@ -144,15 +147,15 @@ class SSHConfig extends Array {
|
|
|
144
147
|
canonicalizeHostName = true;
|
|
145
148
|
}
|
|
146
149
|
if (/^CanonicalDomains$/i.test(subline.param) && Array.isArray(subline.value)) {
|
|
147
|
-
canonicalDomains = subline.value;
|
|
150
|
+
canonicalDomains = subline.value.map(({ val }) => val);
|
|
148
151
|
}
|
|
149
152
|
}
|
|
150
153
|
}
|
|
151
|
-
if (canonicalDomains.length > 0 && canonicalizeHostName) {
|
|
154
|
+
if (canonicalDomains.length > 0 && canonicalizeHostName && context.params.Host === context.params.OriginalHost) {
|
|
152
155
|
for (const domain of canonicalDomains) {
|
|
153
|
-
const host = `${
|
|
154
|
-
const {
|
|
155
|
-
if (!/
|
|
156
|
+
const host = `${context.params.OriginalHost}.${domain}`;
|
|
157
|
+
const { status, stderr } = (0, child_process_1.spawnSync)('nslookup', [host]);
|
|
158
|
+
if (status === 0 && !/can't find/.test(stderr.toString())) {
|
|
156
159
|
context.params.Host = host;
|
|
157
160
|
setProperty('Host', host);
|
|
158
161
|
doPass();
|
|
@@ -224,7 +227,7 @@ class SSHConfig extends Array {
|
|
|
224
227
|
type: LineType.DIRECTIVE,
|
|
225
228
|
param,
|
|
226
229
|
separator: ' ',
|
|
227
|
-
value,
|
|
230
|
+
value: Array.isArray(value) ? value.map((val, i) => ({ val, separator: i === 0 ? '' : ' ' })) : value,
|
|
228
231
|
before: sectionLineFound ? indent : indent.replace(/ |\t/, ''),
|
|
229
232
|
after: '\n',
|
|
230
233
|
};
|
|
@@ -272,7 +275,7 @@ class SSHConfig extends Array {
|
|
|
272
275
|
type: LineType.DIRECTIVE,
|
|
273
276
|
param,
|
|
274
277
|
separator: ' ',
|
|
275
|
-
value,
|
|
278
|
+
value: Array.isArray(value) ? value.map((val, i) => ({ val, separator: i === 0 ? '' : ' ' })) : value,
|
|
276
279
|
before: '',
|
|
277
280
|
after: '\n',
|
|
278
281
|
};
|
|
@@ -302,9 +305,9 @@ class SSHConfig extends Array {
|
|
|
302
305
|
return config;
|
|
303
306
|
}
|
|
304
307
|
}
|
|
305
|
-
exports.default = SSHConfig;
|
|
306
308
|
SSHConfig.DIRECTIVE = LineType.DIRECTIVE;
|
|
307
309
|
SSHConfig.COMMENT = LineType.COMMENT;
|
|
310
|
+
exports.default = SSHConfig;
|
|
308
311
|
/**
|
|
309
312
|
* Parse SSH config text into structured object.
|
|
310
313
|
*/
|
|
@@ -393,6 +396,11 @@ function parse(text) {
|
|
|
393
396
|
function values() {
|
|
394
397
|
const results = [];
|
|
395
398
|
let val = '';
|
|
399
|
+
// whether current value is quoted or not
|
|
400
|
+
let valQuoted = false;
|
|
401
|
+
// the separator preceding current value
|
|
402
|
+
let valSeparator = ' ';
|
|
403
|
+
// whether current context is within quotations or not
|
|
396
404
|
let quoted = false;
|
|
397
405
|
let escaped = false;
|
|
398
406
|
while (chr && !RE_LINE_BREAK.test(chr)) {
|
|
@@ -408,15 +416,18 @@ function parse(text) {
|
|
|
408
416
|
}
|
|
409
417
|
else if (quoted) {
|
|
410
418
|
val += chr;
|
|
419
|
+
valQuoted = true;
|
|
411
420
|
}
|
|
412
421
|
else if (/[ \t=]/.test(chr)) {
|
|
413
422
|
if (val) {
|
|
414
|
-
results.push(val);
|
|
423
|
+
results.push({ val, separator: valSeparator, quoted: valQuoted });
|
|
415
424
|
val = '';
|
|
425
|
+
valQuoted = false;
|
|
426
|
+
valSeparator = chr;
|
|
416
427
|
}
|
|
417
428
|
// otherwise ignore the space
|
|
418
429
|
}
|
|
419
|
-
else if (chr === '#') {
|
|
430
|
+
else if (chr === '#' && results.length > 0) {
|
|
420
431
|
break;
|
|
421
432
|
}
|
|
422
433
|
else {
|
|
@@ -425,11 +436,11 @@ function parse(text) {
|
|
|
425
436
|
chr = next();
|
|
426
437
|
}
|
|
427
438
|
if (quoted || escaped) {
|
|
428
|
-
throw new Error(`Unexpected line break at ${results.concat(val).join(' ')}`);
|
|
439
|
+
throw new Error(`Unexpected line break at ${results.map(({ val }) => val).concat(val).join(' ')}`);
|
|
429
440
|
}
|
|
430
441
|
if (val)
|
|
431
|
-
results.push(val);
|
|
432
|
-
return results.length > 1 ? results : results[0];
|
|
442
|
+
results.push({ val, separator: valSeparator, quoted: valQuoted });
|
|
443
|
+
return results.length > 1 ? results : results[0].val;
|
|
433
444
|
}
|
|
434
445
|
function directive() {
|
|
435
446
|
const type = LineType.DIRECTIVE;
|
|
@@ -450,11 +461,11 @@ function parse(text) {
|
|
|
450
461
|
if (/^Match$/i.test(param)) {
|
|
451
462
|
const criteria = {};
|
|
452
463
|
if (typeof result.value === 'string') {
|
|
453
|
-
result.value = [result.value];
|
|
464
|
+
result.value = [{ val: result.value, separator: '', quoted: result.quoted }];
|
|
454
465
|
}
|
|
455
466
|
let i = 0;
|
|
456
467
|
while (i < result.value.length) {
|
|
457
|
-
const keyword = result.value[i];
|
|
468
|
+
const { val: keyword } = result.value[i];
|
|
458
469
|
switch (keyword.toLowerCase()) {
|
|
459
470
|
case 'all':
|
|
460
471
|
case 'canonical':
|
|
@@ -466,7 +477,7 @@ function parse(text) {
|
|
|
466
477
|
if (i + 1 >= result.value.length) {
|
|
467
478
|
throw new Error(`Missing value for match criteria ${keyword}`);
|
|
468
479
|
}
|
|
469
|
-
criteria[keyword] = result.value[i + 1];
|
|
480
|
+
criteria[keyword] = result.value[i + 1].val;
|
|
470
481
|
i += 2;
|
|
471
482
|
break;
|
|
472
483
|
}
|
|
@@ -505,7 +516,6 @@ function parse(text) {
|
|
|
505
516
|
}
|
|
506
517
|
return configWas;
|
|
507
518
|
}
|
|
508
|
-
exports.parse = parse;
|
|
509
519
|
/**
|
|
510
520
|
* Stringify structured object into SSH config text.
|
|
511
521
|
*/
|
|
@@ -513,7 +523,11 @@ function stringify(config) {
|
|
|
513
523
|
let str = '';
|
|
514
524
|
function formatValue(value, quoted) {
|
|
515
525
|
if (Array.isArray(value)) {
|
|
516
|
-
|
|
526
|
+
let result = '';
|
|
527
|
+
for (const { val, separator, quoted } of value) {
|
|
528
|
+
result += (result ? separator : '') + formatValue(val, quoted || RE_SPACE.test(val));
|
|
529
|
+
}
|
|
530
|
+
return result;
|
|
517
531
|
}
|
|
518
532
|
return quoted ? `"${value}"` : value;
|
|
519
533
|
}
|
|
@@ -523,14 +537,14 @@ function stringify(config) {
|
|
|
523
537
|
const value = formatValue(line.value, quoted);
|
|
524
538
|
return `${line.param}${line.separator}${value}`;
|
|
525
539
|
}
|
|
526
|
-
const format = line => {
|
|
540
|
+
const format = (line) => {
|
|
527
541
|
str += line.before;
|
|
528
542
|
if (line.type === LineType.COMMENT) {
|
|
529
543
|
str += line.content;
|
|
530
544
|
}
|
|
531
545
|
else if (line.type === LineType.DIRECTIVE && MULTIPLE_VALUE_PROPS.includes(line.param)) {
|
|
532
|
-
|
|
533
|
-
str += formatDirective({ ...line, value });
|
|
546
|
+
(Array.isArray(line.value) ? line.value : [line.value]).forEach((value, i, values) => {
|
|
547
|
+
str += formatDirective({ ...line, value: typeof value !== 'string' ? value.val : value });
|
|
534
548
|
if (i < values.length - 1)
|
|
535
549
|
str += `\n${line.before}`;
|
|
536
550
|
});
|
|
@@ -539,12 +553,11 @@ function stringify(config) {
|
|
|
539
553
|
str += formatDirective(line);
|
|
540
554
|
}
|
|
541
555
|
str += line.after;
|
|
542
|
-
if (line
|
|
556
|
+
if ('config' in line) {
|
|
543
557
|
line.config.forEach(format);
|
|
544
558
|
}
|
|
545
559
|
};
|
|
546
560
|
config.forEach(format);
|
|
547
561
|
return str;
|
|
548
562
|
}
|
|
549
|
-
exports.stringify = stringify;
|
|
550
563
|
//# sourceMappingURL=ssh-config.js.map
|