ssh-config 4.2.0 → 4.3.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 ADDED
@@ -0,0 +1,3 @@
1
+ import SSHConfig from './src/ssh-config';
2
+ export * from './src/ssh-config';
3
+ export default SSHConfig;
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.2.0",
4
+ "version": "4.3.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
- "src"
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,88 @@
1
+ declare enum LineType {
2
+ DIRECTIVE = 1,
3
+ COMMENT = 2
4
+ }
5
+ type Separator = ' ' | '=' | '\t';
6
+ 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
+ interface Section extends Directive {
16
+ config: SSHConfig;
17
+ }
18
+ interface Match extends Section {
19
+ criteria: Record<string, string | string[]>;
20
+ }
21
+ interface Comment {
22
+ type: LineType.COMMENT;
23
+ before: string;
24
+ after: string;
25
+ content: string;
26
+ }
27
+ type Line = Match | Section | Directive | Comment;
28
+ interface FindOptions {
29
+ Host?: string;
30
+ }
31
+ interface MatchOptions {
32
+ Host: string;
33
+ User?: string;
34
+ }
35
+ declare class SSHConfig extends Array<Line> {
36
+ static readonly DIRECTIVE: LineType.DIRECTIVE;
37
+ static readonly COMMENT: LineType.COMMENT;
38
+ /**
39
+ * Query SSH config by host.
40
+ */
41
+ compute(host: string): Record<string, string | string[]>;
42
+ /**
43
+ * Query SSH config by host and user.
44
+ */
45
+ compute(opts: MatchOptions): Record<string, string | string[]>;
46
+ /**
47
+ * Find by Host or Match.
48
+ */
49
+ find(opts: FindOptions): Line | undefined;
50
+ /**
51
+ * Find by search function.
52
+ * @param predicate Function to check against each line; should return a truthy value when a
53
+ * matching line is given.
54
+ */
55
+ find(predicate: (line: Line, index: number, config: Line[]) => unknown): Line | undefined;
56
+ /**
57
+ * Remove section by Host or Match.
58
+ */
59
+ remove(opts: FindOptions): Line[] | undefined;
60
+ /**
61
+ * Remove section by search function.
62
+ * @param predicate Function to check against each line; should return a truthy value when a
63
+ * matching line is given.
64
+ */
65
+ remove(predicate: (line: Line, index: number, config: Line[]) => unknown): Line[] | undefined;
66
+ toString(): string;
67
+ /**
68
+ * Append new section to existing SSH config.
69
+ */
70
+ append(opts: Record<string, string | string[]>): SSHConfig;
71
+ /**
72
+ * Prepend new section to existing SSH config.
73
+ */
74
+ prepend(opts: Record<string, string | string[]>, beforeFirstSection?: boolean): SSHConfig;
75
+ }
76
+ /**
77
+ * Parse SSH config text into structured object.
78
+ */
79
+ export declare function parse(text: string): SSHConfig;
80
+ /**
81
+ * Stringify structured object into SSH config text.
82
+ */
83
+ export declare function stringify(config: SSHConfig): string;
84
+ declare const _default: typeof SSHConfig & {
85
+ parse: typeof parse;
86
+ stringify: typeof stringify;
87
+ };
88
+ export default _default;
package/src/ssh-config.js CHANGED
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.stringify = exports.parse = 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;
@@ -39,37 +40,56 @@ function getIndent(config) {
39
40
  }
40
41
  return ' ';
41
42
  }
42
- function capitalize(str) {
43
- if (typeof str !== 'string')
44
- return str;
45
- return str[0].toUpperCase() + str.slice(1);
46
- }
47
- function match(criteria, params) {
48
- for (const key in criteria) {
49
- const criterion = criteria[key];
50
- const keyword = key.toLowerCase();
51
- if (keyword === 'exec') {
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
- else if (!(0, glob_1.default)(criterion, params[capitalize(keyword)])) {
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
  }
64
76
  return true;
65
77
  }
66
78
  class SSHConfig extends Array {
67
- /**
68
- * Query ssh config by host.
69
- */
70
- compute(params) {
71
- if (typeof params === 'string')
72
- params = { Host: params };
79
+ compute(opts) {
80
+ if (typeof opts === 'string')
81
+ opts = { Host: opts };
82
+ const context = {
83
+ params: {
84
+ Host: opts.Host,
85
+ HostName: opts.Host,
86
+ OriginalHost: opts.Host,
87
+ User: os_1.default.userInfo().username,
88
+ LocalUser: os_1.default.userInfo().username,
89
+ },
90
+ inFinalPass: false,
91
+ doFinalPass: false,
92
+ };
73
93
  const obj = {};
74
94
  const setProperty = (name, value) => {
75
95
  if (MULTIPLE_VALUE_PROPS.includes(name)) {
@@ -77,36 +97,50 @@ class SSHConfig extends Array {
77
97
  list.push(value);
78
98
  }
79
99
  else if (obj[name] == null) {
100
+ if (name === "HostName") {
101
+ context.params.HostName = value;
102
+ }
103
+ else if (name === "User") {
104
+ context.params.User = value;
105
+ }
80
106
  obj[name] = value;
81
107
  }
82
108
  };
83
- for (const line of this) {
84
- if (line.type !== LineType.DIRECTIVE)
85
- continue;
86
- if (line.param === 'Host' && (0, glob_1.default)(line.value, params.Host)) {
87
- setProperty(line.param, line.value);
88
- for (const subline of line.config) {
89
- if (subline.type === LineType.DIRECTIVE) {
90
- setProperty(subline.param, subline.value);
109
+ if (opts.User !== undefined) {
110
+ setProperty("User", opts.User);
111
+ }
112
+ const doPass = () => {
113
+ for (const line of this) {
114
+ if (line.type !== LineType.DIRECTIVE)
115
+ continue;
116
+ if (line.param === 'Host' && (0, glob_1.default)(line.value, context.params.Host)) {
117
+ setProperty(line.param, line.value);
118
+ for (const subline of line.config) {
119
+ if (subline.type === LineType.DIRECTIVE) {
120
+ setProperty(subline.param, subline.value);
121
+ }
91
122
  }
92
123
  }
93
- }
94
- else if (line.param === 'Match' && 'criteria' in line && match(line.criteria, params)) {
95
- for (const subline of line.config) {
96
- if (subline.type === LineType.DIRECTIVE) {
97
- setProperty(subline.param, subline.value);
124
+ else if (line.param === 'Match' && 'criteria' in line && match(line.criteria, context)) {
125
+ for (const subline of line.config) {
126
+ if (subline.type === LineType.DIRECTIVE) {
127
+ setProperty(subline.param, subline.value);
128
+ }
98
129
  }
99
130
  }
131
+ else if (line.param !== 'Host' && line.param !== 'Match') {
132
+ setProperty(line.param, line.value);
133
+ }
100
134
  }
101
- else {
102
- setProperty(line.param, line.value);
103
- }
135
+ };
136
+ doPass();
137
+ if (context.doFinalPass) {
138
+ context.inFinalPass = true;
139
+ context.params.Host = context.params.HostName;
140
+ doPass();
104
141
  }
105
142
  return obj;
106
143
  }
107
- /**
108
- * find section by Host / Match or function
109
- */
110
144
  find(opts) {
111
145
  if (typeof opts === 'function')
112
146
  return super.find(opts);
@@ -115,9 +149,6 @@ class SSHConfig extends Array {
115
149
  }
116
150
  return super.find(line => compare(line, opts));
117
151
  }
118
- /**
119
- * Remove section by Host / Match or function
120
- */
121
152
  remove(opts) {
122
153
  let index;
123
154
  if (typeof opts === 'function') {
@@ -136,8 +167,7 @@ class SSHConfig extends Array {
136
167
  return stringify(this);
137
168
  }
138
169
  /**
139
- * Append new section to existing ssh config.
140
- * @param {Object} opts
170
+ * Append new section to existing SSH config.
141
171
  */
142
172
  append(opts) {
143
173
  const indent = getIndent(this);
@@ -177,8 +207,7 @@ class SSHConfig extends Array {
177
207
  return configWas;
178
208
  }
179
209
  /**
180
- * Prepend new section to existing ssh config.
181
- * @param {Object} opts
210
+ * Prepend new section to existing SSH config.
182
211
  */
183
212
  prepend(opts, beforeFirstSection = false) {
184
213
  const indent = getIndent(this);
@@ -236,7 +265,7 @@ class SSHConfig extends Array {
236
265
  SSHConfig.DIRECTIVE = LineType.DIRECTIVE;
237
266
  SSHConfig.COMMENT = LineType.COMMENT;
238
267
  /**
239
- * Parse ssh config text into structured object.
268
+ * Parse SSH config text into structured object.
240
269
  */
241
270
  function parse(text) {
242
271
  let i = 0;
@@ -373,10 +402,27 @@ function parse(text) {
373
402
  delete result.quoted;
374
403
  if (/^Match$/i.test(param)) {
375
404
  const criteria = {};
376
- for (let i = 0; i < result.value.length; i += 2) {
405
+ if (typeof result.value === "string") {
406
+ result.value = [result.value];
407
+ }
408
+ let i = 0;
409
+ while (i < result.value.length) {
377
410
  const keyword = result.value[i];
378
- const value = result.value[i + 1];
379
- criteria[keyword] = value;
411
+ switch (keyword.toLowerCase()) {
412
+ case "all":
413
+ case "canonical":
414
+ case "final":
415
+ criteria[keyword] = [];
416
+ i += 1;
417
+ break;
418
+ default:
419
+ if (i + 1 >= result.value.length) {
420
+ throw new Error(`Missing value for match criteria ${keyword}`);
421
+ }
422
+ criteria[keyword] = result.value[i + 1];
423
+ i += 2;
424
+ break;
425
+ }
380
426
  }
381
427
  result.criteria = criteria;
382
428
  }
@@ -399,7 +445,12 @@ function parse(text) {
399
445
  }
400
446
  else if (node.type === LineType.DIRECTIVE && !node.param) {
401
447
  // blank lines at file end
402
- config[config.length - 1].after += node.before;
448
+ if (config.length === 0) {
449
+ configWas[configWas.length - 1].after += node.before;
450
+ }
451
+ else {
452
+ config[config.length - 1].after += node.before;
453
+ }
403
454
  }
404
455
  else {
405
456
  config.push(node);
@@ -409,17 +460,11 @@ function parse(text) {
409
460
  }
410
461
  exports.parse = parse;
411
462
  /**
412
- * Stringify structured object into ssh config text
463
+ * Stringify structured object into SSH config text.
413
464
  */
414
465
  function stringify(config) {
415
466
  let str = '';
416
467
  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
468
  if (Array.isArray(value)) {
424
469
  return value.map(chunk => formatValue(chunk, RE_SPACE.test(chunk))).join(' ');
425
470
  }
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
@@ -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 {
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 })