ssh-config 4.2.1 → 4.4.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/index.d.ts +3 -0
- package/package.json +4 -2
- package/src/glob.d.ts +9 -0
- package/src/ssh-config.d.ts +91 -0
- package/src/ssh-config.js +141 -63
- package/src/glob.js.map +0 -1
- package/src/glob.ts +0 -45
- package/src/ssh-config.js.map +0 -1
- package/src/ssh-config.ts +0 -544
package/index.d.ts
ADDED
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.
|
|
4
|
+
"version": "4.4.0",
|
|
5
5
|
"author": "Chen Yangjian (https://www.cyj.me)",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"index.js",
|
|
12
|
-
"
|
|
12
|
+
"index.d.ts",
|
|
13
|
+
"src/*.js",
|
|
14
|
+
"src/*.d.ts"
|
|
13
15
|
],
|
|
14
16
|
"devDependencies": {
|
|
15
17
|
"@types/mocha": "^9.1.0",
|
package/src/glob.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A helper function to match input against [pattern-list](https://www.freebsd.org/cgi/man.cgi?query=ssh_config&sektion=5#PATTERNS).
|
|
3
|
+
* According to `man ssh_config`, negated patterns shall be matched first.
|
|
4
|
+
*
|
|
5
|
+
* @param {string|string[]} patternList
|
|
6
|
+
* @param {string} str
|
|
7
|
+
*/
|
|
8
|
+
declare function glob(patternList: string | string[], text: string): boolean;
|
|
9
|
+
export default glob;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export declare enum LineType {
|
|
2
|
+
DIRECTIVE = 1,
|
|
3
|
+
COMMENT = 2
|
|
4
|
+
}
|
|
5
|
+
export type Separator = ' ' | '=' | '\t';
|
|
6
|
+
export interface Directive {
|
|
7
|
+
type: LineType.DIRECTIVE;
|
|
8
|
+
before: string;
|
|
9
|
+
after: string;
|
|
10
|
+
param: string;
|
|
11
|
+
separator: Separator;
|
|
12
|
+
value: string | string[];
|
|
13
|
+
quoted?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface Section extends Directive {
|
|
16
|
+
config: SSHConfig;
|
|
17
|
+
}
|
|
18
|
+
export interface Match extends Section {
|
|
19
|
+
criteria: Record<string, string | string[]>;
|
|
20
|
+
}
|
|
21
|
+
export interface Comment {
|
|
22
|
+
type: LineType.COMMENT;
|
|
23
|
+
before: string;
|
|
24
|
+
after: string;
|
|
25
|
+
content: string;
|
|
26
|
+
}
|
|
27
|
+
export type Line = Match | Section | Directive | Comment;
|
|
28
|
+
export interface FindOptions {
|
|
29
|
+
Host?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface MatchOptions {
|
|
32
|
+
Host: string;
|
|
33
|
+
User?: string;
|
|
34
|
+
}
|
|
35
|
+
export default class SSHConfig extends Array<Line> {
|
|
36
|
+
static readonly DIRECTIVE: LineType.DIRECTIVE;
|
|
37
|
+
static readonly COMMENT: LineType.COMMENT;
|
|
38
|
+
/**
|
|
39
|
+
* Parse SSH config text into structured object.
|
|
40
|
+
*/
|
|
41
|
+
static parse(text: string): SSHConfig;
|
|
42
|
+
/**
|
|
43
|
+
* Stringify structured object into SSH config text.
|
|
44
|
+
*/
|
|
45
|
+
static stringify(config: SSHConfig): string;
|
|
46
|
+
/**
|
|
47
|
+
* Query SSH config by host.
|
|
48
|
+
*/
|
|
49
|
+
compute(host: string): Record<string, string | string[]>;
|
|
50
|
+
/**
|
|
51
|
+
* Query SSH config by host and user.
|
|
52
|
+
*/
|
|
53
|
+
compute(opts: MatchOptions): Record<string, string | string[]>;
|
|
54
|
+
/**
|
|
55
|
+
* Find by Host or Match.
|
|
56
|
+
*/
|
|
57
|
+
find(opts: FindOptions): Line | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Find by search function.
|
|
60
|
+
* @param predicate Function to check against each line; should return a truthy value when a
|
|
61
|
+
* matching line is given.
|
|
62
|
+
*/
|
|
63
|
+
find(predicate: (line: Line, index: number, config: Line[]) => unknown): Line | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Remove section by Host or Match.
|
|
66
|
+
*/
|
|
67
|
+
remove(opts: FindOptions): Line[] | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* Remove section by search function.
|
|
70
|
+
* @param predicate Function to check against each line; should return a truthy value when a
|
|
71
|
+
* matching line is given.
|
|
72
|
+
*/
|
|
73
|
+
remove(predicate: (line: Line, index: number, config: Line[]) => unknown): Line[] | undefined;
|
|
74
|
+
toString(): string;
|
|
75
|
+
/**
|
|
76
|
+
* Append new section to existing SSH config.
|
|
77
|
+
*/
|
|
78
|
+
append(opts: Record<string, string | string[]>): SSHConfig;
|
|
79
|
+
/**
|
|
80
|
+
* Prepend new section to existing SSH config.
|
|
81
|
+
*/
|
|
82
|
+
prepend(opts: Record<string, string | string[]>, beforeFirstSection?: boolean): SSHConfig;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Parse SSH config text into structured object.
|
|
86
|
+
*/
|
|
87
|
+
export declare function parse(text: string): SSHConfig;
|
|
88
|
+
/**
|
|
89
|
+
* Stringify structured object into SSH config text.
|
|
90
|
+
*/
|
|
91
|
+
export declare function stringify(config: SSHConfig): string;
|
package/src/ssh-config.js
CHANGED
|
@@ -3,20 +3,21 @@ 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.stringify = exports.parse = void 0;
|
|
6
|
+
exports.stringify = exports.parse = exports.LineType = void 0;
|
|
7
7
|
const glob_1 = __importDefault(require("./glob"));
|
|
8
8
|
const child_process_1 = require("child_process");
|
|
9
|
+
const os_1 = __importDefault(require("os"));
|
|
9
10
|
const RE_SPACE = /\s/;
|
|
10
11
|
const RE_LINE_BREAK = /\r|\n/;
|
|
11
12
|
const RE_SECTION_DIRECTIVE = /^(Host|Match)$/i;
|
|
12
|
-
const RE_MULTI_VALUE_DIRECTIVE = /^(GlobalKnownHostsFile|Host|IPQoS|SendEnv|UserKnownHostsFile|ProxyCommand|Match)$/i;
|
|
13
|
+
const RE_MULTI_VALUE_DIRECTIVE = /^(GlobalKnownHostsFile|Host|IPQoS|SendEnv|UserKnownHostsFile|ProxyCommand|Match|CanonicalDomains)$/i;
|
|
13
14
|
const RE_QUOTE_DIRECTIVE = /^(?:CertificateFile|IdentityFile|IdentityAgent|User)$/i;
|
|
14
15
|
const RE_SINGLE_LINE_DIRECTIVE = /^(Include|IdentityFile)$/i;
|
|
15
16
|
var LineType;
|
|
16
17
|
(function (LineType) {
|
|
17
18
|
LineType[LineType["DIRECTIVE"] = 1] = "DIRECTIVE";
|
|
18
19
|
LineType[LineType["COMMENT"] = 2] = "COMMENT";
|
|
19
|
-
})(LineType || (LineType = {}));
|
|
20
|
+
})(LineType = exports.LineType || (exports.LineType = {}));
|
|
20
21
|
const MULTIPLE_VALUE_PROPS = [
|
|
21
22
|
'IdentityFile',
|
|
22
23
|
'LocalForward',
|
|
@@ -39,25 +40,36 @@ function getIndent(config) {
|
|
|
39
40
|
}
|
|
40
41
|
return ' ';
|
|
41
42
|
}
|
|
42
|
-
function
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const command = `function main {
|
|
53
|
-
${criterion}
|
|
54
|
-
}
|
|
55
|
-
main`;
|
|
56
|
-
const { status } = (0, child_process_1.spawnSync)(command, { shell: true });
|
|
57
|
-
if (status != 0)
|
|
43
|
+
function match(criteria, context) {
|
|
44
|
+
const testCriterion = (key, criterion) => {
|
|
45
|
+
switch (key.toLowerCase()) {
|
|
46
|
+
case 'all':
|
|
47
|
+
return true;
|
|
48
|
+
case 'final':
|
|
49
|
+
if (context.inFinalPass) {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
context.doFinalPass = true;
|
|
58
53
|
return false;
|
|
54
|
+
case 'exec':
|
|
55
|
+
const command = `function main {
|
|
56
|
+
${criterion}
|
|
59
57
|
}
|
|
60
|
-
|
|
58
|
+
main`;
|
|
59
|
+
return (0, child_process_1.spawnSync)(command, { shell: true }).status === 0;
|
|
60
|
+
case 'host':
|
|
61
|
+
return (0, glob_1.default)(criterion, context.params.HostName);
|
|
62
|
+
case 'originalhost':
|
|
63
|
+
return (0, glob_1.default)(criterion, context.params.OriginalHost);
|
|
64
|
+
case 'user':
|
|
65
|
+
return (0, glob_1.default)(criterion, context.params.User);
|
|
66
|
+
case 'localuser':
|
|
67
|
+
return (0, glob_1.default)(criterion, context.params.LocalUser);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
for (const key in criteria) {
|
|
71
|
+
const criterion = criteria[key];
|
|
72
|
+
if (!testCriterion(key, criterion)) {
|
|
61
73
|
return false;
|
|
62
74
|
}
|
|
63
75
|
}
|
|
@@ -65,11 +77,31 @@ function match(criteria, params) {
|
|
|
65
77
|
}
|
|
66
78
|
class SSHConfig extends Array {
|
|
67
79
|
/**
|
|
68
|
-
*
|
|
80
|
+
* Parse SSH config text into structured object.
|
|
69
81
|
*/
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
82
|
+
static parse(text) {
|
|
83
|
+
return parse(text);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Stringify structured object into SSH config text.
|
|
87
|
+
*/
|
|
88
|
+
static stringify(config) {
|
|
89
|
+
return stringify(config);
|
|
90
|
+
}
|
|
91
|
+
compute(opts) {
|
|
92
|
+
if (typeof opts === 'string')
|
|
93
|
+
opts = { Host: opts };
|
|
94
|
+
const context = {
|
|
95
|
+
params: {
|
|
96
|
+
Host: opts.Host,
|
|
97
|
+
HostName: opts.Host,
|
|
98
|
+
OriginalHost: opts.Host,
|
|
99
|
+
User: os_1.default.userInfo().username,
|
|
100
|
+
LocalUser: os_1.default.userInfo().username,
|
|
101
|
+
},
|
|
102
|
+
inFinalPass: false,
|
|
103
|
+
doFinalPass: false,
|
|
104
|
+
};
|
|
73
105
|
const obj = {};
|
|
74
106
|
const setProperty = (name, value) => {
|
|
75
107
|
if (MULTIPLE_VALUE_PROPS.includes(name)) {
|
|
@@ -77,36 +109,71 @@ class SSHConfig extends Array {
|
|
|
77
109
|
list.push(value);
|
|
78
110
|
}
|
|
79
111
|
else if (obj[name] == null) {
|
|
112
|
+
if (name === 'HostName') {
|
|
113
|
+
context.params.HostName = value;
|
|
114
|
+
}
|
|
115
|
+
else if (name === 'User') {
|
|
116
|
+
context.params.User = value;
|
|
117
|
+
}
|
|
80
118
|
obj[name] = value;
|
|
81
119
|
}
|
|
82
120
|
};
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
121
|
+
if (opts.User !== undefined) {
|
|
122
|
+
setProperty('User', opts.User);
|
|
123
|
+
}
|
|
124
|
+
const doPass = () => {
|
|
125
|
+
for (const line of this) {
|
|
126
|
+
if (line.type !== LineType.DIRECTIVE)
|
|
127
|
+
continue;
|
|
128
|
+
if (line.param === 'Host' && (0, glob_1.default)(line.value, context.params.Host)) {
|
|
129
|
+
let canonicalizeHostName = false;
|
|
130
|
+
let canonicalDomains = [];
|
|
131
|
+
setProperty(line.param, line.value);
|
|
132
|
+
for (const subline of line.config) {
|
|
133
|
+
if (subline.type === LineType.DIRECTIVE) {
|
|
134
|
+
setProperty(subline.param, subline.value);
|
|
135
|
+
if (/^CanonicalizeHostName$/i.test(subline.param) && subline.value === 'yes') {
|
|
136
|
+
canonicalizeHostName = true;
|
|
137
|
+
}
|
|
138
|
+
if (/^CanonicalDomains$/i.test(subline.param) && Array.isArray(subline.value)) {
|
|
139
|
+
canonicalDomains = subline.value;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
console.log(canonicalizeHostName, canonicalDomains);
|
|
144
|
+
if (canonicalDomains.length > 0 && canonicalizeHostName) {
|
|
145
|
+
for (const domain of canonicalDomains) {
|
|
146
|
+
const host = `${line.value}.${domain}`;
|
|
147
|
+
const { stdout } = (0, child_process_1.spawnSync)('nslookup', [host]);
|
|
148
|
+
if (!/server can't find/.test(stdout.toString())) {
|
|
149
|
+
context.params.Host = host;
|
|
150
|
+
setProperty('Host', host);
|
|
151
|
+
doPass();
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
91
155
|
}
|
|
92
156
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
157
|
+
else if (line.param === 'Match' && 'criteria' in line && match(line.criteria, context)) {
|
|
158
|
+
for (const subline of line.config) {
|
|
159
|
+
if (subline.type === LineType.DIRECTIVE) {
|
|
160
|
+
setProperty(subline.param, subline.value);
|
|
161
|
+
}
|
|
98
162
|
}
|
|
99
163
|
}
|
|
164
|
+
else if (line.param !== 'Host' && line.param !== 'Match') {
|
|
165
|
+
setProperty(line.param, line.value);
|
|
166
|
+
}
|
|
100
167
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
168
|
+
};
|
|
169
|
+
doPass();
|
|
170
|
+
if (context.doFinalPass) {
|
|
171
|
+
context.inFinalPass = true;
|
|
172
|
+
context.params.Host = context.params.HostName;
|
|
173
|
+
doPass();
|
|
104
174
|
}
|
|
105
175
|
return obj;
|
|
106
176
|
}
|
|
107
|
-
/**
|
|
108
|
-
* find section by Host / Match or function
|
|
109
|
-
*/
|
|
110
177
|
find(opts) {
|
|
111
178
|
if (typeof opts === 'function')
|
|
112
179
|
return super.find(opts);
|
|
@@ -115,9 +182,6 @@ class SSHConfig extends Array {
|
|
|
115
182
|
}
|
|
116
183
|
return super.find(line => compare(line, opts));
|
|
117
184
|
}
|
|
118
|
-
/**
|
|
119
|
-
* Remove section by Host / Match or function
|
|
120
|
-
*/
|
|
121
185
|
remove(opts) {
|
|
122
186
|
let index;
|
|
123
187
|
if (typeof opts === 'function') {
|
|
@@ -136,8 +200,7 @@ class SSHConfig extends Array {
|
|
|
136
200
|
return stringify(this);
|
|
137
201
|
}
|
|
138
202
|
/**
|
|
139
|
-
* Append new section to existing
|
|
140
|
-
* @param {Object} opts
|
|
203
|
+
* Append new section to existing SSH config.
|
|
141
204
|
*/
|
|
142
205
|
append(opts) {
|
|
143
206
|
const indent = getIndent(this);
|
|
@@ -177,8 +240,7 @@ class SSHConfig extends Array {
|
|
|
177
240
|
return configWas;
|
|
178
241
|
}
|
|
179
242
|
/**
|
|
180
|
-
* Prepend new section to existing
|
|
181
|
-
* @param {Object} opts
|
|
243
|
+
* Prepend new section to existing SSH config.
|
|
182
244
|
*/
|
|
183
245
|
prepend(opts, beforeFirstSection = false) {
|
|
184
246
|
const indent = getIndent(this);
|
|
@@ -233,10 +295,11 @@ class SSHConfig extends Array {
|
|
|
233
295
|
return config;
|
|
234
296
|
}
|
|
235
297
|
}
|
|
298
|
+
exports.default = SSHConfig;
|
|
236
299
|
SSHConfig.DIRECTIVE = LineType.DIRECTIVE;
|
|
237
300
|
SSHConfig.COMMENT = LineType.COMMENT;
|
|
238
301
|
/**
|
|
239
|
-
* Parse
|
|
302
|
+
* Parse SSH config text into structured object.
|
|
240
303
|
*/
|
|
241
304
|
function parse(text) {
|
|
242
305
|
let i = 0;
|
|
@@ -373,10 +436,27 @@ function parse(text) {
|
|
|
373
436
|
delete result.quoted;
|
|
374
437
|
if (/^Match$/i.test(param)) {
|
|
375
438
|
const criteria = {};
|
|
376
|
-
|
|
439
|
+
if (typeof result.value === 'string') {
|
|
440
|
+
result.value = [result.value];
|
|
441
|
+
}
|
|
442
|
+
let i = 0;
|
|
443
|
+
while (i < result.value.length) {
|
|
377
444
|
const keyword = result.value[i];
|
|
378
|
-
|
|
379
|
-
|
|
445
|
+
switch (keyword.toLowerCase()) {
|
|
446
|
+
case 'all':
|
|
447
|
+
case 'canonical':
|
|
448
|
+
case 'final':
|
|
449
|
+
criteria[keyword] = [];
|
|
450
|
+
i += 1;
|
|
451
|
+
break;
|
|
452
|
+
default:
|
|
453
|
+
if (i + 1 >= result.value.length) {
|
|
454
|
+
throw new Error(`Missing value for match criteria ${keyword}`);
|
|
455
|
+
}
|
|
456
|
+
criteria[keyword] = result.value[i + 1];
|
|
457
|
+
i += 2;
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
380
460
|
}
|
|
381
461
|
result.criteria = criteria;
|
|
382
462
|
}
|
|
@@ -399,7 +479,12 @@ function parse(text) {
|
|
|
399
479
|
}
|
|
400
480
|
else if (node.type === LineType.DIRECTIVE && !node.param) {
|
|
401
481
|
// blank lines at file end
|
|
402
|
-
config
|
|
482
|
+
if (config.length === 0) {
|
|
483
|
+
configWas[configWas.length - 1].after += node.before;
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
config[config.length - 1].after += node.before;
|
|
487
|
+
}
|
|
403
488
|
}
|
|
404
489
|
else {
|
|
405
490
|
config.push(node);
|
|
@@ -409,17 +494,11 @@ function parse(text) {
|
|
|
409
494
|
}
|
|
410
495
|
exports.parse = parse;
|
|
411
496
|
/**
|
|
412
|
-
* Stringify structured object into
|
|
497
|
+
* Stringify structured object into SSH config text.
|
|
413
498
|
*/
|
|
414
499
|
function stringify(config) {
|
|
415
500
|
let str = '';
|
|
416
501
|
function formatValue(value, quoted) {
|
|
417
|
-
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
418
|
-
const result = [];
|
|
419
|
-
for (const key in value)
|
|
420
|
-
result.push(key, value[key]);
|
|
421
|
-
value = result;
|
|
422
|
-
}
|
|
423
502
|
if (Array.isArray(value)) {
|
|
424
503
|
return value.map(chunk => formatValue(chunk, RE_SPACE.test(chunk))).join(' ');
|
|
425
504
|
}
|
|
@@ -455,5 +534,4 @@ function stringify(config) {
|
|
|
455
534
|
return str;
|
|
456
535
|
}
|
|
457
536
|
exports.stringify = stringify;
|
|
458
|
-
exports.default = Object.assign(SSHConfig, { parse, stringify });
|
|
459
537
|
//# sourceMappingURL=ssh-config.js.map
|
package/src/glob.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"glob.js","sourceRoot":"","sources":["glob.ts"],"names":[],"mappings":";;AACA,SAAS,WAAW,CAAC,IAAY,EAAE,KAAa;IAC9C,KAAK,IAAI,IAAI,IAAI,KAAK,EAAE;QACtB,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,IAAI,EAAE,GAAG,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC,CAAA;KAC/D;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAS,KAAK,CAAC,OAAe,EAAE,IAAY;IAC1C,OAAO,GAAG,WAAW,CAAC,OAAO,EAAE,eAAe,CAAC,CAAA;IAC/C,OAAO,GAAG,OAAO;SACd,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC;SACpB,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;IAEvB,OAAO,IAAI,MAAM,CAAC,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACvD,CAAC;AAED;;;;;;GAMG;AACH,SAAS,IAAI,CAAC,WAA8B,EAAE,IAAY;IACxD,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAElF,+HAA+H;IAC/H,IAAI,MAAM,GAAG,KAAK,CAAA;IAClB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;QAC9B,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,GAAG,CAAA;QAEhC,IAAI,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE;YAC3C,OAAO,KAAK,CAAA;SACb;aAAM,IAAI,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE;YAC/B,uFAAuF;YACvF,MAAM,GAAG,IAAI,CAAA;SACd;KACF;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED,kBAAe,IAAI,CAAA"}
|
package/src/glob.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
function escapeChars(text: string, chars: string) {
|
|
3
|
-
for (let char of chars) {
|
|
4
|
-
text = text.replace(new RegExp('\\' + char, 'g'), '\\' + char)
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
return text
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function match(pattern: string, text: string) {
|
|
11
|
-
pattern = escapeChars(pattern, '\\()[]{}.+^$|')
|
|
12
|
-
pattern = pattern
|
|
13
|
-
.replace(/\*/g, '.*')
|
|
14
|
-
.replace(/\?/g, '.?')
|
|
15
|
-
|
|
16
|
-
return new RegExp('^(?:' + pattern + ')$').test(text)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* A helper function to match input against [pattern-list](https://www.freebsd.org/cgi/man.cgi?query=ssh_config&sektion=5#PATTERNS).
|
|
21
|
-
* According to `man ssh_config`, negated patterns shall be matched first.
|
|
22
|
-
*
|
|
23
|
-
* @param {string|string[]} patternList
|
|
24
|
-
* @param {string} str
|
|
25
|
-
*/
|
|
26
|
-
function glob(patternList: string | string[], text: string) {
|
|
27
|
-
const patterns = Array.isArray(patternList) ? patternList : patternList.split(/,/)
|
|
28
|
-
|
|
29
|
-
// > If a negated entry is matched, then the Host entry is ignored, regardless of whether any other patterns on the line match.
|
|
30
|
-
let result = false
|
|
31
|
-
for (const pattern of patterns) {
|
|
32
|
-
const negate = pattern[0] == '!'
|
|
33
|
-
|
|
34
|
-
if (negate && match(pattern.slice(1), text)) {
|
|
35
|
-
return false
|
|
36
|
-
} else if (match(pattern, text)) {
|
|
37
|
-
// wait until all of the pattern match results because there might be a negated pattern
|
|
38
|
-
result = true
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return result
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export default glob
|
package/src/ssh-config.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ssh-config.js","sourceRoot":"","sources":["ssh-config.ts"],"names":[],"mappings":"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"}
|
package/src/ssh-config.ts
DELETED
|
@@ -1,544 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import glob from './glob'
|
|
3
|
-
import { spawnSync } from 'child_process'
|
|
4
|
-
|
|
5
|
-
const RE_SPACE = /\s/
|
|
6
|
-
const RE_LINE_BREAK = /\r|\n/
|
|
7
|
-
const RE_SECTION_DIRECTIVE = /^(Host|Match)$/i
|
|
8
|
-
const RE_MULTI_VALUE_DIRECTIVE = /^(GlobalKnownHostsFile|Host|IPQoS|SendEnv|UserKnownHostsFile|ProxyCommand|Match)$/i
|
|
9
|
-
const RE_QUOTE_DIRECTIVE = /^(?:CertificateFile|IdentityFile|IdentityAgent|User)$/i
|
|
10
|
-
const RE_SINGLE_LINE_DIRECTIVE = /^(Include|IdentityFile)$/i
|
|
11
|
-
|
|
12
|
-
enum LineType {
|
|
13
|
-
DIRECTIVE = 1,
|
|
14
|
-
COMMENT = 2,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
type Separator = ' ' | '=' | '\t';
|
|
18
|
-
|
|
19
|
-
type Space = ' ' | '\t' | '\n';
|
|
20
|
-
|
|
21
|
-
interface Directive {
|
|
22
|
-
type: LineType.DIRECTIVE;
|
|
23
|
-
before: string;
|
|
24
|
-
after: string;
|
|
25
|
-
param: string;
|
|
26
|
-
separator: Separator;
|
|
27
|
-
value: string | string[];
|
|
28
|
-
quoted?: boolean;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
interface Section extends Directive {
|
|
32
|
-
config: SSHConfig;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
interface Match extends Section {
|
|
36
|
-
criteria: Record<string, string | string[]>
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
interface Comment {
|
|
40
|
-
type: LineType.COMMENT;
|
|
41
|
-
before: string;
|
|
42
|
-
after: string;
|
|
43
|
-
content: string;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
type Line = Match | Section | Directive | Comment;
|
|
47
|
-
|
|
48
|
-
interface FindOptions {
|
|
49
|
-
Host?: string;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const MULTIPLE_VALUE_PROPS = [
|
|
53
|
-
'IdentityFile',
|
|
54
|
-
'LocalForward',
|
|
55
|
-
'RemoteForward',
|
|
56
|
-
'DynamicForward',
|
|
57
|
-
'CertificateFile',
|
|
58
|
-
]
|
|
59
|
-
|
|
60
|
-
function compare(line, opts) {
|
|
61
|
-
return opts.hasOwnProperty(line.param) && opts[line.param] === line.value
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function getIndent(config: SSHConfig) {
|
|
65
|
-
for (const line of config) {
|
|
66
|
-
if (line.type === LineType.DIRECTIVE && 'config' in line) {
|
|
67
|
-
for (const subline of line.config) {
|
|
68
|
-
if (subline.before) {
|
|
69
|
-
return subline.before
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return ' '
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function capitalize(str) {
|
|
79
|
-
if (typeof str !== 'string') return str
|
|
80
|
-
return str[0].toUpperCase() + str.slice(1)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function match(criteria, params) {
|
|
84
|
-
for (const key in criteria) {
|
|
85
|
-
const criterion = criteria[key]
|
|
86
|
-
const keyword = key.toLowerCase()
|
|
87
|
-
if (keyword === 'exec') {
|
|
88
|
-
const command = `function main {
|
|
89
|
-
${criterion}
|
|
90
|
-
}
|
|
91
|
-
main`
|
|
92
|
-
const { status } = spawnSync(command, { shell: true })
|
|
93
|
-
if (status != 0) return false
|
|
94
|
-
} else if (!glob(criterion, params[capitalize(keyword)])) {
|
|
95
|
-
return false
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
return true
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
class SSHConfig extends Array<Line> {
|
|
102
|
-
static DIRECTIVE: LineType.DIRECTIVE = LineType.DIRECTIVE
|
|
103
|
-
static COMMENT: LineType.COMMENT = LineType.COMMENT
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Query ssh config by host.
|
|
107
|
-
*/
|
|
108
|
-
compute(params): Record<string, string | string[]> {
|
|
109
|
-
if (typeof params === 'string') params = { Host: params }
|
|
110
|
-
const obj = {}
|
|
111
|
-
const setProperty = (name, value) => {
|
|
112
|
-
if (MULTIPLE_VALUE_PROPS.includes(name)) {
|
|
113
|
-
const list = obj[name] || (obj[name] = [])
|
|
114
|
-
list.push(value)
|
|
115
|
-
} else if (obj[name] == null) {
|
|
116
|
-
obj[name] = value
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
for (const line of this) {
|
|
121
|
-
if (line.type !== LineType.DIRECTIVE) continue
|
|
122
|
-
if (line.param === 'Host' && glob(line.value, params.Host)) {
|
|
123
|
-
setProperty(line.param, line.value)
|
|
124
|
-
for (const subline of (line as Section).config) {
|
|
125
|
-
if (subline.type === LineType.DIRECTIVE) {
|
|
126
|
-
setProperty(subline.param, subline.value)
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
} else if (line.param === 'Match' && 'criteria' in line && match(line.criteria, params)) {
|
|
130
|
-
for (const subline of (line as Section).config) {
|
|
131
|
-
if (subline.type === LineType.DIRECTIVE) {
|
|
132
|
-
setProperty(subline.param, subline.value)
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
} else if (line.param !== 'Host' && line.param !== 'Match') {
|
|
136
|
-
setProperty(line.param, line.value)
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return obj
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* find section by Host / Match or function
|
|
145
|
-
*/
|
|
146
|
-
find(opts: ((line: Line, index: number, config: Line[]) => unknown) | FindOptions) {
|
|
147
|
-
if (typeof opts === 'function') return super.find(opts)
|
|
148
|
-
|
|
149
|
-
if (!(opts && ('Host' in opts || 'Match' in opts))) {
|
|
150
|
-
throw new Error('Can only find by Host or Match')
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return super.find(line => compare(line, opts))
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Remove section by Host / Match or function
|
|
158
|
-
*/
|
|
159
|
-
remove(opts: ((line: Line, index: number, config: Line[]) => unknown) | FindOptions) {
|
|
160
|
-
let index: number
|
|
161
|
-
|
|
162
|
-
if (typeof opts === 'function') {
|
|
163
|
-
index = super.findIndex(opts)
|
|
164
|
-
} else if (!(opts && ('Host' in opts || 'Match' in opts))) {
|
|
165
|
-
throw new Error('Can only remove by Host or Match')
|
|
166
|
-
} else {
|
|
167
|
-
index = super.findIndex(line => compare(line, opts))
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (index >= 0) return this.splice(index, 1)
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
toString(): string {
|
|
174
|
-
return stringify(this)
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Append new section to existing ssh config.
|
|
179
|
-
* @param {Object} opts
|
|
180
|
-
*/
|
|
181
|
-
append(opts: Record<string, string | string[]>) {
|
|
182
|
-
const indent = getIndent(this)
|
|
183
|
-
const lastEntry = this.length > 0 ? this[this.length - 1] : null
|
|
184
|
-
let config = lastEntry && (lastEntry as Section).config || this
|
|
185
|
-
let configWas = this
|
|
186
|
-
|
|
187
|
-
let lastLine = config.length > 0 ? config[config.length - 1] : lastEntry
|
|
188
|
-
if (lastLine && !lastLine.after) lastLine.after = '\n'
|
|
189
|
-
|
|
190
|
-
let sectionLineFound = config !== configWas
|
|
191
|
-
|
|
192
|
-
for (const param in opts) {
|
|
193
|
-
const value = opts[param]
|
|
194
|
-
const line: Directive = {
|
|
195
|
-
type: LineType.DIRECTIVE,
|
|
196
|
-
param,
|
|
197
|
-
separator: ' ',
|
|
198
|
-
value,
|
|
199
|
-
before: sectionLineFound ? indent : indent.replace(/ |\t/, ''),
|
|
200
|
-
after: '\n',
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if (RE_SECTION_DIRECTIVE.test(param)) {
|
|
204
|
-
sectionLineFound = true
|
|
205
|
-
line.before = indent.replace(/ |\t/, '')
|
|
206
|
-
config = configWas
|
|
207
|
-
// separate sections with an extra newline
|
|
208
|
-
// https://github.com/cyjake/ssh-config/issues/23#issuecomment-564768248
|
|
209
|
-
if (lastLine && lastLine.after === '\n') lastLine.after += '\n'
|
|
210
|
-
config.push(line)
|
|
211
|
-
config = (line as Section).config = new SSHConfig()
|
|
212
|
-
} else {
|
|
213
|
-
config.push(line)
|
|
214
|
-
}
|
|
215
|
-
lastLine = line
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return configWas
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Prepend new section to existing ssh config.
|
|
223
|
-
* @param {Object} opts
|
|
224
|
-
*/
|
|
225
|
-
prepend(opts: Record<string, string | string[]>, beforeFirstSection = false) {
|
|
226
|
-
const indent = getIndent(this)
|
|
227
|
-
let config: SSHConfig = this
|
|
228
|
-
let i = 0
|
|
229
|
-
|
|
230
|
-
// insert above known sections
|
|
231
|
-
if (beforeFirstSection) {
|
|
232
|
-
while (i < this.length && !('config' in this[i])) {
|
|
233
|
-
i += 1
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (i >= this.length) { // No sections in original config
|
|
237
|
-
return this.append(opts)
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// Prepend new section above the first section
|
|
242
|
-
let sectionLineFound = false
|
|
243
|
-
let processedLines = 0
|
|
244
|
-
|
|
245
|
-
for (const param in opts) {
|
|
246
|
-
processedLines += 1
|
|
247
|
-
const value = opts[param]
|
|
248
|
-
const line: Directive = {
|
|
249
|
-
type: LineType.DIRECTIVE,
|
|
250
|
-
param,
|
|
251
|
-
separator: ' ',
|
|
252
|
-
value,
|
|
253
|
-
before: '',
|
|
254
|
-
after: '\n',
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
if (RE_SECTION_DIRECTIVE.test(param)) {
|
|
258
|
-
line.before = indent.replace(/ |\t/, '')
|
|
259
|
-
config.splice(i, 0, line)
|
|
260
|
-
config = (line as Section).config = new SSHConfig()
|
|
261
|
-
sectionLineFound = true
|
|
262
|
-
continue
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// separate from previous sections with an extra newline
|
|
266
|
-
if (processedLines === Object.keys(opts).length) {
|
|
267
|
-
line.after += '\n'
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
if (!sectionLineFound) {
|
|
271
|
-
config.splice(i, 0, line)
|
|
272
|
-
i += 1
|
|
273
|
-
|
|
274
|
-
// Add an extra newline if a single line directive like Include
|
|
275
|
-
if (RE_SINGLE_LINE_DIRECTIVE.test(param)) {
|
|
276
|
-
line.after += '\n'
|
|
277
|
-
}
|
|
278
|
-
continue
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
line.before = indent
|
|
282
|
-
config.push(line)
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
return config
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* Parse ssh config text into structured object.
|
|
291
|
-
*/
|
|
292
|
-
export function parse(text: string): SSHConfig {
|
|
293
|
-
let i = 0
|
|
294
|
-
let chr = next()
|
|
295
|
-
let config: SSHConfig = new SSHConfig()
|
|
296
|
-
let configWas = config
|
|
297
|
-
|
|
298
|
-
function next() {
|
|
299
|
-
return text[i++]
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
function space(): Space {
|
|
303
|
-
let spaces = ''
|
|
304
|
-
|
|
305
|
-
while (RE_SPACE.test(chr)) {
|
|
306
|
-
spaces += chr
|
|
307
|
-
chr = next()
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
return spaces as Space
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
function linebreak() {
|
|
314
|
-
let breaks = ''
|
|
315
|
-
|
|
316
|
-
while (RE_LINE_BREAK.test(chr)) {
|
|
317
|
-
breaks += chr
|
|
318
|
-
chr = next()
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
return breaks
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
function parameter() {
|
|
325
|
-
let param = ''
|
|
326
|
-
|
|
327
|
-
while (chr && /[^ \t=]/.test(chr)) {
|
|
328
|
-
param += chr
|
|
329
|
-
chr = next()
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
return param
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
function separator(): Separator {
|
|
336
|
-
let sep = space()
|
|
337
|
-
|
|
338
|
-
if (chr === '=') {
|
|
339
|
-
sep += chr
|
|
340
|
-
chr = next()
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
return (sep + space()) as Separator
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
function value() {
|
|
347
|
-
let val = ''
|
|
348
|
-
let quoted = false
|
|
349
|
-
let escaped = false
|
|
350
|
-
|
|
351
|
-
while (chr && !RE_LINE_BREAK.test(chr)) {
|
|
352
|
-
// backslash escapes only double quotes
|
|
353
|
-
if (escaped) {
|
|
354
|
-
val += chr === '"' ? chr : `\\${chr}`
|
|
355
|
-
escaped = false
|
|
356
|
-
}
|
|
357
|
-
// ProxyCommand ssh -W "%h:%p" firewall.example.org
|
|
358
|
-
else if (chr === '"' && (!val || quoted)) {
|
|
359
|
-
quoted = !quoted
|
|
360
|
-
}
|
|
361
|
-
else if (chr === '\\') {
|
|
362
|
-
escaped = true
|
|
363
|
-
}
|
|
364
|
-
else {
|
|
365
|
-
val += chr
|
|
366
|
-
}
|
|
367
|
-
chr = next()
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
if (quoted || escaped) {
|
|
371
|
-
throw new Error(`Unexpected line break at ${val}`)
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
return val.trim()
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
function comment(): Comment {
|
|
378
|
-
const type = LineType.COMMENT
|
|
379
|
-
let content = ''
|
|
380
|
-
|
|
381
|
-
while (chr && !RE_LINE_BREAK.test(chr)) {
|
|
382
|
-
content += chr
|
|
383
|
-
chr = next()
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
return { type, content, before: '', after: '' }
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
// Host *.co.uk
|
|
390
|
-
// Host * !local.dev
|
|
391
|
-
// Host "foo bar"
|
|
392
|
-
function values() {
|
|
393
|
-
const results: string[] = []
|
|
394
|
-
let val = ''
|
|
395
|
-
let quoted = false
|
|
396
|
-
let escaped = false
|
|
397
|
-
|
|
398
|
-
while (chr && !RE_LINE_BREAK.test(chr)) {
|
|
399
|
-
if (escaped) {
|
|
400
|
-
val += chr === '"' ? chr : `\\${chr}`
|
|
401
|
-
escaped = false
|
|
402
|
-
}
|
|
403
|
-
else if (chr === '"') {
|
|
404
|
-
quoted = !quoted
|
|
405
|
-
}
|
|
406
|
-
else if (chr === '\\') {
|
|
407
|
-
escaped = true
|
|
408
|
-
}
|
|
409
|
-
else if (quoted) {
|
|
410
|
-
val += chr
|
|
411
|
-
}
|
|
412
|
-
else if (/[ \t]/.test(chr)) {
|
|
413
|
-
if (val) {
|
|
414
|
-
results.push(val)
|
|
415
|
-
val = ''
|
|
416
|
-
}
|
|
417
|
-
// otherwise ignore the space
|
|
418
|
-
}
|
|
419
|
-
else {
|
|
420
|
-
val += chr
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
chr = next()
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
if (quoted || escaped) {
|
|
427
|
-
throw new Error(`Unexpected line break at ${results.concat(val).join(' ')}`)
|
|
428
|
-
}
|
|
429
|
-
if (val) results.push(val)
|
|
430
|
-
return results.length > 1 ? results : results[0]
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
function directive() {
|
|
434
|
-
const type = LineType.DIRECTIVE
|
|
435
|
-
const param = parameter()
|
|
436
|
-
// Host "foo bar" baz
|
|
437
|
-
const multiple = RE_MULTI_VALUE_DIRECTIVE.test(param)
|
|
438
|
-
const result: Directive = {
|
|
439
|
-
type,
|
|
440
|
-
param,
|
|
441
|
-
separator: separator(),
|
|
442
|
-
quoted: !multiple && chr === '"',
|
|
443
|
-
value: multiple ? values() : value(),
|
|
444
|
-
before: '',
|
|
445
|
-
after: '',
|
|
446
|
-
}
|
|
447
|
-
if (!result.quoted) delete result.quoted
|
|
448
|
-
if (/^Match$/i.test(param)) {
|
|
449
|
-
const criteria = {}
|
|
450
|
-
for (let i = 0; i < result.value.length; i += 2) {
|
|
451
|
-
const keyword = result.value[i]
|
|
452
|
-
const value = result.value[ i + 1]
|
|
453
|
-
criteria[keyword] = value
|
|
454
|
-
}
|
|
455
|
-
(result as Match).criteria = criteria
|
|
456
|
-
}
|
|
457
|
-
return result
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
function line() {
|
|
461
|
-
const before = space()
|
|
462
|
-
const node = chr === '#' ? comment() : directive()
|
|
463
|
-
const after = linebreak()
|
|
464
|
-
|
|
465
|
-
node.before = before
|
|
466
|
-
node.after = after
|
|
467
|
-
|
|
468
|
-
return node
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
while (chr) {
|
|
472
|
-
let node = line()
|
|
473
|
-
|
|
474
|
-
if (node.type === LineType.DIRECTIVE && RE_SECTION_DIRECTIVE.test(node.param)) {
|
|
475
|
-
config = configWas
|
|
476
|
-
config.push(node)
|
|
477
|
-
config = (node as Section).config = new SSHConfig()
|
|
478
|
-
}
|
|
479
|
-
else if (node.type === LineType.DIRECTIVE && !node.param) {
|
|
480
|
-
// blank lines at file end
|
|
481
|
-
config[config.length - 1].after += node.before
|
|
482
|
-
}
|
|
483
|
-
else {
|
|
484
|
-
config.push(node)
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
return configWas
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
/**
|
|
492
|
-
* Stringify structured object into ssh config text
|
|
493
|
-
*/
|
|
494
|
-
export function stringify(config: SSHConfig): string {
|
|
495
|
-
let str = ''
|
|
496
|
-
|
|
497
|
-
function formatValue(value: string | string[] | Record<string, any>, quoted: boolean) {
|
|
498
|
-
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
499
|
-
const result: string[] = []
|
|
500
|
-
for (const key in value) result.push(key, value[key])
|
|
501
|
-
value = result
|
|
502
|
-
}
|
|
503
|
-
if (Array.isArray(value)) {
|
|
504
|
-
return value.map(chunk => formatValue(chunk, RE_SPACE.test(chunk))).join(' ')
|
|
505
|
-
}
|
|
506
|
-
return quoted ? `"${value}"` : value
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
function formatDirective(line) {
|
|
510
|
-
const quoted = line.quoted
|
|
511
|
-
|| (RE_QUOTE_DIRECTIVE.test(line.param) && RE_SPACE.test(line.value))
|
|
512
|
-
const value = formatValue(line.value, quoted)
|
|
513
|
-
return `${line.param}${line.separator}${value}`
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
const format = line => {
|
|
517
|
-
str += line.before
|
|
518
|
-
|
|
519
|
-
if (line.type === LineType.COMMENT) {
|
|
520
|
-
str += line.content
|
|
521
|
-
}
|
|
522
|
-
else if (line.type === LineType.DIRECTIVE && MULTIPLE_VALUE_PROPS.includes(line.param)) {
|
|
523
|
-
[].concat(line.value).forEach(function (value, i, values) {
|
|
524
|
-
str += formatDirective({ ...line, value })
|
|
525
|
-
if (i < values.length - 1) str += `\n${line.before}`
|
|
526
|
-
})
|
|
527
|
-
}
|
|
528
|
-
else if (line.type === LineType.DIRECTIVE) {
|
|
529
|
-
str += formatDirective(line)
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
str += line.after
|
|
533
|
-
|
|
534
|
-
if (line.config) {
|
|
535
|
-
line.config.forEach(format)
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
config.forEach(format)
|
|
540
|
-
|
|
541
|
-
return str
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
export default Object.assign(SSHConfig, { parse, stringify })
|