ssh-config 4.0.5 → 4.1.2

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/History.md CHANGED
@@ -1,8 +1,47 @@
1
+ 4.1.2 / 2022-01-20
2
+ ==================
3
+
4
+ ## What's Changed
5
+ * docs: types field in package.json by @cyjake in https://github.com/cyjake/ssh-config/pull/50
6
+
7
+
8
+ **Full Changelog**: https://github.com/cyjake/ssh-config/compare/v4.1.1...v4.1.2
9
+
10
+ 4.1.1 / 2021-10-21
11
+ ==================
12
+
13
+ ## What's Changed
14
+ * docs: `.prepend` and type definitions by @cyjake in https://github.com/cyjake/ssh-config/pull/47
15
+ * fix: improper parsing of ProxyCommand with quotation marks by @tanhakabir in https://github.com/cyjake/ssh-config/pull/48
16
+
17
+
18
+ **Full Changelog**: https://github.com/cyjake/ssh-config/compare/v4.1.0...v4.1.1
19
+
20
+ 4.1.0 / 2021-10-20
21
+ ==================
22
+
23
+ ## What's Changed
24
+ * test: switching to github actions by @cyjake in https://github.com/cyjake/ssh-config/pull/44
25
+ * feat: add prepend function to prepend options onto config by @tanhakabir in https://github.com/cyjake/ssh-config/pull/45
26
+ * build: switch to codecov by @cyjake in https://github.com/cyjake/ssh-config/pull/46
27
+
28
+ ## New Contributors
29
+ * @tanhakabir made her first contribution in https://github.com/cyjake/ssh-config/pull/45
30
+
31
+ **Full Changelog**: https://github.com/cyjake/ssh-config/compare/v4.0.6...v4.1.0
32
+
33
+ 4.0.6 / 2021-05-11
34
+ ==================
35
+
36
+ * fix: IdentityFile parameter value should be quoted if contains space
37
+
38
+
1
39
  4.0.5 / 2021-01-08
2
40
  ==================
3
41
 
4
42
  * fix: multiple LocalForward values should be formartted into multiple lines
5
43
 
44
+
6
45
  4.0.4 / 2020-09-01
7
46
  ==================
8
47
 
package/Readme.md CHANGED
@@ -3,7 +3,8 @@
3
3
  [![NPM Downloads](https://img.shields.io/npm/dm/ssh-config.svg?style=flat)](https://www.npmjs.com/package/ssh-config)
4
4
  [![NPM Version](http://img.shields.io/npm/v/ssh-config.svg?style=flat)](https://www.npmjs.com/package/ssh-config)
5
5
  [![Build Status](https://travis-ci.org/cyjake/ssh-config.svg)](https://travis-ci.org/cyjake/ssh-config)
6
- [![Coverage Status](https://coveralls.io/repos/github/cyjake/ssh-config/badge.svg?branch=master)](https://coveralls.io/github/cyjake/ssh-config?branch=master)
6
+ [![Node CI](https://github.com/cyjake/ssh-config/actions/workflows/nodejs.yml/badge.svg)](https://github.com/cyjake/ssh-config/actions/workflows/nodejs.yml)
7
+ [![codecov](https://codecov.io/gh/cyjake/ssh-config/branch/master/graph/badge.svg?token=RMyTgcL8Kg)](https://codecov.io/gh/cyjake/ssh-config)
7
8
 
8
9
  ## Usage
9
10
 
@@ -153,6 +154,62 @@ SSHConfig.stringify(config)
153
154
  // User dinosaur
154
155
  ```
155
156
 
157
+ ### `.prepend` sections
158
+
159
+ But appending options to the end of the config isn't very effective if your config is organizated per the recommendations of ssh_config(5) that the generic options are at at the end of the config, such as:
160
+
161
+ ```
162
+ Host ness
163
+ HostName lochness.com
164
+ User dinosaur
165
+
166
+ IdentityFile ~/.ssh/id_rsa
167
+ ```
168
+
169
+ The config could get messy if you put new options after the line of `IdentityFile`. To work around this issue, it is recommended that `.prepend` should be used instead. For the example above, we can prepend new options at the beginning of the config:
170
+
171
+ ```js
172
+ config.prepend({
173
+ Host: 'tahoe',
174
+ HostName 'tahoe.com',
175
+ })
176
+ ```
177
+
178
+ The result would be:
179
+
180
+ ```
181
+ Host tahoe
182
+ HostName tahoe.com
183
+
184
+ Host ness
185
+ HostName lochness.com
186
+ User dinosaur
187
+
188
+ IdentityFile ~/.ssh/id_rsa
189
+ ```
190
+
191
+ If there are generic options at the beginning of the config, and you'd like the prepended section put before the first existing section, please turn on the second argument of `.prepend`:
192
+
193
+ ```js
194
+ config.prepend({
195
+ Host: 'tahoe',
196
+ HostName 'tahoe.com',
197
+ }, true)
198
+ ```
199
+
200
+ The result would be like:
201
+
202
+ ```
203
+ IdentityFile ~/.ssh/id_rsa
204
+
205
+ Host tahoe
206
+ HostName tahoe.com
207
+
208
+ Host ness
209
+ HostName lochness.com
210
+ User dinosaur
211
+ ```
212
+
156
213
  ## References
157
214
 
158
215
  - [ssh_config(5)][ssh_config]
package/index.js CHANGED
@@ -5,16 +5,13 @@ const glob = require('./src/glob')
5
5
  const RE_SPACE = /\s/
6
6
  const RE_LINE_BREAK = /\r|\n/
7
7
  const RE_SECTION_DIRECTIVE = /^(Host|Match)$/i
8
- const RE_MULTI_VALUE_DIRECTIVE = /^(GlobalKnownHostsFile|Host|IPQoS|SendEnv|UserKnownHostsFile)$/i
9
- const RE_QUOTE_DIRECTIVE = /^(?:CertificateFile|IdentifyFile|User)$/i
8
+ const RE_MULTI_VALUE_DIRECTIVE = /^(GlobalKnownHostsFile|Host|IPQoS|SendEnv|UserKnownHostsFile|ProxyCommand)$/i
9
+ const RE_QUOTE_DIRECTIVE = /^(?:CertificateFile|IdentityFile|User)$/i
10
+ const RE_SINGLE_LINE_DIRECTIVE = /^(Include|IdentityFile)$/i
10
11
 
11
12
  const DIRECTIVE = 1
12
13
  const COMMENT = 2
13
14
 
14
- function compare(line, opts) {
15
- return opts.hasOwnProperty(line.param) && opts[line.param] === line.value
16
- }
17
-
18
15
  const MULTIPLE_VALUE_PROPS = [
19
16
  'IdentityFile',
20
17
  'LocalForward',
@@ -23,6 +20,24 @@ const MULTIPLE_VALUE_PROPS = [
23
20
  'CertificateFile'
24
21
  ]
25
22
 
23
+ function compare(line, opts) {
24
+ return opts.hasOwnProperty(line.param) && opts[line.param] === line.value
25
+ }
26
+
27
+ function getIndent(config) {
28
+ for (const line of config) {
29
+ if (RE_SECTION_DIRECTIVE.test(line.param)) {
30
+ for (const subline of line.config) {
31
+ if (subline.before) {
32
+ return subline.before
33
+ }
34
+ }
35
+ }
36
+ }
37
+
38
+ return ' '
39
+ }
40
+
26
41
  class SSHConfig extends Array {
27
42
  /**
28
43
  * Query ssh config by host.
@@ -105,20 +120,7 @@ class SSHConfig extends Array {
105
120
  * @param {Object} opts
106
121
  */
107
122
  append(opts) {
108
- let indent = ' '
109
-
110
- outer:
111
- for (const line of this) {
112
- if (RE_SECTION_DIRECTIVE.test(line.param)) {
113
- for (const subline of line.config) {
114
- if (subline.before) {
115
- indent = subline.before
116
- break outer
117
- }
118
- }
119
- }
120
- }
121
-
123
+ const indent = getIndent(this)
122
124
  const lastEntry = this.length > 0 ? this[this.length - 1] : null
123
125
  let config = lastEntry && lastEntry.config || this
124
126
  let configWas = this
@@ -153,6 +155,71 @@ class SSHConfig extends Array {
153
155
  return configWas
154
156
  }
155
157
 
158
+ /**
159
+ * Prepend new section to existing ssh config.
160
+ * @param {Object} opts
161
+ */
162
+ prepend(opts, beforeFirstSection = false) {
163
+ const indent = getIndent(this)
164
+ let config = this
165
+ let i = 0
166
+
167
+ // insert above known sections
168
+ if (beforeFirstSection) {
169
+ while (i < this.length && !RE_SECTION_DIRECTIVE.test(this[i].param)) {
170
+ i += 1
171
+ }
172
+
173
+ if (i >= this.length) { // No sections in original config
174
+ return this.append(opts)
175
+ }
176
+ }
177
+
178
+ // Prepend new section above the first section
179
+ let sectionLineFound = false
180
+ let processedLines = 0
181
+
182
+ for (const param in opts) {
183
+ processedLines += 1
184
+ const line = {
185
+ type: DIRECTIVE,
186
+ param,
187
+ separator: ' ',
188
+ value: opts[param],
189
+ before: '',
190
+ after: '\n'
191
+ }
192
+
193
+ if (RE_SECTION_DIRECTIVE.test(param)) {
194
+ config.splice(i, 0, line)
195
+ config = line.config = new SSHConfig()
196
+ sectionLineFound = true
197
+ continue
198
+ }
199
+
200
+ // separate from previous sections with an extra newline
201
+ if (processedLines === Object.keys(opts).length) {
202
+ line.after += '\n'
203
+ }
204
+
205
+ if (!sectionLineFound) {
206
+ config.splice(i, 0, line)
207
+ i += 1
208
+
209
+ // Add an extra newline if a single line directive like Include
210
+ if (RE_SINGLE_LINE_DIRECTIVE.test(param)) {
211
+ line.after += '\n'
212
+ }
213
+ continue
214
+ }
215
+
216
+ line.before = indent
217
+ config.push(line)
218
+ }
219
+
220
+ return config
221
+ }
222
+
156
223
  /**
157
224
  * Stringify structured object into ssh config text
158
225
  * @param {SSHConfig} config
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.0.5",
4
+ "version": "4.1.2",
5
5
  "author": "Chen Yangjian (https://www.cyj.me)",
6
6
  "repository": {
7
7
  "type": "git",
@@ -9,7 +9,8 @@
9
9
  },
10
10
  "files": [
11
11
  "index.js",
12
- "src"
12
+ "src",
13
+ "types"
13
14
  ],
14
15
  "devDependencies": {
15
16
  "eslint": "^7.17.0",
@@ -20,10 +21,11 @@
20
21
  "scripts": {
21
22
  "lint": "eslint .",
22
23
  "test": "mocha --exit",
23
- "coveralls": "nyc mocha --exit && nyc report --reporter=text-lcov | coveralls"
24
+ "test:coverage": "nyc mocha --exit && nyc report --reporter=lcov"
24
25
  },
25
26
  "engine": {
26
- "node": ">= 6.0.0"
27
+ "node": ">= 10.0.0"
27
28
  },
29
+ "types": "types/index.d.ts",
28
30
  "license": "MIT"
29
31
  }
@@ -0,0 +1,41 @@
1
+ declare enum ELine {
2
+ DIRECTIVE = 1,
3
+ COMMENT = 2,
4
+ }
5
+
6
+ interface Directive {
7
+ type: ELine.DIRECTIVE;
8
+ before: string;
9
+ after: string;
10
+ param: string;
11
+ separator: ' ' | '=';
12
+ value: string;
13
+ }
14
+
15
+ interface Section extends Directive {
16
+ config: SSHConfig;
17
+ }
18
+
19
+ interface Comment {
20
+ type: ELine.COMMENT;
21
+ content: string;
22
+ }
23
+
24
+ type Line = Directive | Comment;
25
+
26
+ export default class SSHConfig extends Array {
27
+ static parse(text: string): SSHConfig;
28
+ static stringify(config: SSHConfig): string;
29
+
30
+ toString(): string;
31
+
32
+ compute(host: string): Record<string, string>;
33
+
34
+ find(predicate: (value: any, index: number, obj: any[]) => any);
35
+ find(options: Record<string, string>): Line | Section;
36
+
37
+ remove(options: Record<string, string>): Line | Section;
38
+
39
+ append(options: Record<string, string>): SSHConfig;
40
+ prepend(options: Record<string, string>): SSHConfig;
41
+ }
@@ -0,0 +1,10 @@
1
+ import SSHConfig from './index';
2
+
3
+ const config = SSHConfig.parse(`
4
+ IdentityFile ~/.ssh/id_rsa
5
+
6
+ Host ness
7
+ HostName lochness.com
8
+ `);
9
+
10
+ console.log(config.toString());