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 +39 -0
- package/Readme.md +58 -1
- package/index.js +87 -20
- package/package.json +6 -4
- package/types/index.d.ts +41 -0
- package/types/ssh-config-tests.ts +10 -0
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
|
[](https://www.npmjs.com/package/ssh-config)
|
|
4
4
|
[](https://www.npmjs.com/package/ssh-config)
|
|
5
5
|
[](https://travis-ci.org/cyjake/ssh-config)
|
|
6
|
-
[](https://github.com/cyjake/ssh-config/actions/workflows/nodejs.yml)
|
|
7
|
+
[](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|
|
|
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
|
-
|
|
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.
|
|
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
|
-
"
|
|
24
|
+
"test:coverage": "nyc mocha --exit && nyc report --reporter=lcov"
|
|
24
25
|
},
|
|
25
26
|
"engine": {
|
|
26
|
-
"node": ">=
|
|
27
|
+
"node": ">= 10.0.0"
|
|
27
28
|
},
|
|
29
|
+
"types": "types/index.d.ts",
|
|
28
30
|
"license": "MIT"
|
|
29
31
|
}
|
package/types/index.d.ts
ADDED
|
@@ -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
|
+
}
|