bdy 1.23.6-dev → 1.23.7-dev

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.
Files changed (205) hide show
  1. package/distTs/package.json +10 -2
  2. package/distTs/src/agent/linux.js +53 -3
  3. package/distTs/src/agent/manager.js +3 -6
  4. package/distTs/src/agent/osx.js +51 -3
  5. package/distTs/src/agent/system.js +400 -21
  6. package/distTs/src/agent/windows.js +4 -7
  7. package/distTs/src/command/agent/debug.js +2 -2
  8. package/distTs/src/command/agent/install.js +37 -10
  9. package/distTs/src/command/agent/restart.js +2 -2
  10. package/distTs/src/command/agent/run.js +3 -0
  11. package/distTs/src/command/agent/start.js +2 -2
  12. package/distTs/src/command/agent/status.js +19 -0
  13. package/distTs/src/command/agent/stop.js +2 -2
  14. package/distTs/src/command/agent/uninstall.js +5 -8
  15. package/distTs/src/command/agent/update.js +2 -2
  16. package/distTs/src/command/artifact/publish.js +3 -1
  17. package/distTs/src/command/version.js +13 -5
  18. package/distTs/src/logger.js +40 -4
  19. package/distTs/src/texts.js +35 -19
  20. package/distTs/src/utils.js +98 -3
  21. package/node_modules/asn1/Jenkinsfile +65 -0
  22. package/node_modules/asn1/LICENSE +19 -0
  23. package/node_modules/asn1/README.md +50 -0
  24. package/node_modules/asn1/lib/ber/errors.js +13 -0
  25. package/node_modules/asn1/lib/ber/index.js +27 -0
  26. package/node_modules/asn1/lib/ber/reader.js +262 -0
  27. package/node_modules/asn1/lib/ber/types.js +36 -0
  28. package/node_modules/asn1/lib/ber/writer.js +317 -0
  29. package/node_modules/asn1/lib/index.js +20 -0
  30. package/node_modules/asn1/package.json +31 -0
  31. package/node_modules/bcrypt-pbkdf/CONTRIBUTING.md +13 -0
  32. package/node_modules/bcrypt-pbkdf/LICENSE +66 -0
  33. package/node_modules/bcrypt-pbkdf/README.md +45 -0
  34. package/node_modules/bcrypt-pbkdf/index.js +556 -0
  35. package/node_modules/bcrypt-pbkdf/package.json +15 -0
  36. package/node_modules/safer-buffer/LICENSE +21 -0
  37. package/node_modules/safer-buffer/Porting-Buffer.md +268 -0
  38. package/node_modules/safer-buffer/Readme.md +156 -0
  39. package/node_modules/safer-buffer/dangerous.js +58 -0
  40. package/node_modules/safer-buffer/package.json +34 -0
  41. package/node_modules/safer-buffer/safer.js +77 -0
  42. package/node_modules/safer-buffer/tests.js +406 -0
  43. package/node_modules/ssh2/.eslintignore +4 -0
  44. package/node_modules/ssh2/.eslintrc.js +5 -0
  45. package/node_modules/ssh2/.github/workflows/ci.yml +110 -0
  46. package/node_modules/ssh2/.github/workflows/lint.yml +27 -0
  47. package/node_modules/ssh2/LICENSE +19 -0
  48. package/node_modules/ssh2/README.md +1529 -0
  49. package/node_modules/ssh2/SFTP.md +413 -0
  50. package/node_modules/ssh2/examples/server-chat.js +238 -0
  51. package/node_modules/ssh2/examples/sftp-server-download-only.js +134 -0
  52. package/node_modules/ssh2/install.js +27 -0
  53. package/node_modules/ssh2/lib/Channel.js +295 -0
  54. package/node_modules/ssh2/lib/agent.js +1123 -0
  55. package/node_modules/ssh2/lib/client.js +2176 -0
  56. package/node_modules/ssh2/lib/http-agents.js +84 -0
  57. package/node_modules/ssh2/lib/index.js +44 -0
  58. package/node_modules/ssh2/lib/keygen.js +582 -0
  59. package/node_modules/ssh2/lib/protocol/Protocol.js +2136 -0
  60. package/node_modules/ssh2/lib/protocol/SFTP.js +4052 -0
  61. package/node_modules/ssh2/lib/protocol/constants.js +356 -0
  62. package/node_modules/ssh2/lib/protocol/crypto/binding.gyp +23 -0
  63. package/node_modules/ssh2/lib/protocol/crypto/poly1305.js +43 -0
  64. package/node_modules/ssh2/lib/protocol/crypto/src/binding.cc +2300 -0
  65. package/node_modules/ssh2/lib/protocol/crypto.js +1602 -0
  66. package/node_modules/ssh2/lib/protocol/handlers.js +16 -0
  67. package/node_modules/ssh2/lib/protocol/handlers.misc.js +1285 -0
  68. package/node_modules/ssh2/lib/protocol/kex.js +1908 -0
  69. package/node_modules/ssh2/lib/protocol/keyParser.js +1484 -0
  70. package/node_modules/ssh2/lib/protocol/node-fs-compat.js +115 -0
  71. package/node_modules/ssh2/lib/protocol/utils.js +356 -0
  72. package/node_modules/ssh2/lib/protocol/zlib.js +255 -0
  73. package/node_modules/ssh2/lib/server.js +1380 -0
  74. package/node_modules/ssh2/lib/utils.js +336 -0
  75. package/node_modules/ssh2/package.json +49 -0
  76. package/node_modules/ssh2/test/common.js +316 -0
  77. package/node_modules/ssh2/test/fixtures/bad_rsa_private_key +26 -0
  78. package/node_modules/ssh2/test/fixtures/https_cert.pem +33 -0
  79. package/node_modules/ssh2/test/fixtures/https_key.pem +52 -0
  80. package/node_modules/ssh2/test/fixtures/id_dsa +12 -0
  81. package/node_modules/ssh2/test/fixtures/id_ecdsa +5 -0
  82. package/node_modules/ssh2/test/fixtures/id_rsa +15 -0
  83. package/node_modules/ssh2/test/fixtures/id_rsa.ppk +26 -0
  84. package/node_modules/ssh2/test/fixtures/id_rsa_enc +30 -0
  85. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa +21 -0
  86. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.pub +1 -0
  87. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.pub.result +7 -0
  88. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.result +7 -0
  89. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc +22 -0
  90. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.pub +1 -0
  91. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.pub.result +7 -0
  92. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.result +7 -0
  93. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm +23 -0
  94. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.pub +1 -0
  95. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.pub.result +7 -0
  96. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.result +7 -0
  97. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa +9 -0
  98. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.pub +1 -0
  99. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.pub.result +7 -0
  100. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.result +7 -0
  101. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc +10 -0
  102. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.pub +1 -0
  103. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.pub.result +8 -0
  104. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.result +7 -0
  105. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm +10 -0
  106. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.pub +1 -0
  107. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.pub.result +8 -0
  108. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.result +7 -0
  109. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519 +7 -0
  110. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.pub +1 -0
  111. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.pub.result +7 -0
  112. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.result +7 -0
  113. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa +27 -0
  114. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.pub +1 -0
  115. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.pub.result +7 -0
  116. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.result +7 -0
  117. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc +28 -0
  118. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.pub +1 -0
  119. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.pub.result +8 -0
  120. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.result +7 -0
  121. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm +29 -0
  122. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.pub +1 -0
  123. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.pub.result +8 -0
  124. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.result +7 -0
  125. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa +12 -0
  126. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.pub +1 -0
  127. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.pub.result +7 -0
  128. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.result +7 -0
  129. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc +15 -0
  130. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.pub +1 -0
  131. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.pub.result +8 -0
  132. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.result +7 -0
  133. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa +5 -0
  134. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.pub +1 -0
  135. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.pub.result +7 -0
  136. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.result +7 -0
  137. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc +8 -0
  138. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.pub +1 -0
  139. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.pub.result +8 -0
  140. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.result +7 -0
  141. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa +27 -0
  142. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.pub +1 -0
  143. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.pub.result +7 -0
  144. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.result +7 -0
  145. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc +30 -0
  146. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.pub +1 -0
  147. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.pub.result +8 -0
  148. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.result +7 -0
  149. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256 +54 -0
  150. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.pub +1 -0
  151. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.pub.result +6 -0
  152. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.result +6 -0
  153. package/node_modules/ssh2/test/fixtures/keyParser/ppk_dsa_enc +17 -0
  154. package/node_modules/ssh2/test/fixtures/keyParser/ppk_dsa_enc.result +7 -0
  155. package/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa +26 -0
  156. package/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa.result +7 -0
  157. package/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa_enc +18 -0
  158. package/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa_enc.result +7 -0
  159. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa.pub +9 -0
  160. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa.pub.result +7 -0
  161. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa2.pub +10 -0
  162. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa2.pub.result +7 -0
  163. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa3.pub +11 -0
  164. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa3.pub.result +7 -0
  165. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa4.pub +11 -0
  166. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa4.pub.result +7 -0
  167. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa5.pub +8 -0
  168. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa5.pub.result +7 -0
  169. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa6.pub +13 -0
  170. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa6.pub.result +7 -0
  171. package/node_modules/ssh2/test/fixtures/openssh_new_rsa +27 -0
  172. package/node_modules/ssh2/test/fixtures/ssh_host_dsa_key +12 -0
  173. package/node_modules/ssh2/test/fixtures/ssh_host_ecdsa_key +5 -0
  174. package/node_modules/ssh2/test/fixtures/ssh_host_rsa_key +15 -0
  175. package/node_modules/ssh2/test/test-exec.js +578 -0
  176. package/node_modules/ssh2/test/test-integration-openssh.js +486 -0
  177. package/node_modules/ssh2/test/test-keygen.js +60 -0
  178. package/node_modules/ssh2/test/test-misc-client-server.js +1460 -0
  179. package/node_modules/ssh2/test/test-openssh.js +261 -0
  180. package/node_modules/ssh2/test/test-protocol-crypto.js +631 -0
  181. package/node_modules/ssh2/test/test-protocol-keyparser.js +177 -0
  182. package/node_modules/ssh2/test/test-server-hostkeys.js +138 -0
  183. package/node_modules/ssh2/test/test-sftp.js +842 -0
  184. package/node_modules/ssh2/test/test-shell.js +109 -0
  185. package/node_modules/ssh2/test/test-userauth-agent-openssh.js +110 -0
  186. package/node_modules/ssh2/test/test-userauth-agent.js +171 -0
  187. package/node_modules/ssh2/test/test-userauth.js +611 -0
  188. package/node_modules/ssh2/test/test-worker-imports.js +25 -0
  189. package/node_modules/ssh2/test/test.js +20 -0
  190. package/node_modules/ssh2/util/build_pagent.bat +2 -0
  191. package/node_modules/ssh2/util/pagent.c +88 -0
  192. package/node_modules/ssh2/util/pagent.exe +0 -0
  193. package/node_modules/tweetnacl/.npmignore +4 -0
  194. package/node_modules/tweetnacl/AUTHORS.md +28 -0
  195. package/node_modules/tweetnacl/CHANGELOG.md +221 -0
  196. package/node_modules/tweetnacl/LICENSE +24 -0
  197. package/node_modules/tweetnacl/PULL_REQUEST_TEMPLATE.md +20 -0
  198. package/node_modules/tweetnacl/README.md +459 -0
  199. package/node_modules/tweetnacl/nacl-fast.js +2388 -0
  200. package/node_modules/tweetnacl/nacl-fast.min.js +2 -0
  201. package/node_modules/tweetnacl/nacl.d.ts +98 -0
  202. package/node_modules/tweetnacl/nacl.js +1175 -0
  203. package/node_modules/tweetnacl/nacl.min.js +1 -0
  204. package/node_modules/tweetnacl/package.json +58 -0
  205. package/package.json +10 -2
@@ -0,0 +1,1123 @@
1
+ 'use strict';
2
+
3
+ const { Socket } = require('net');
4
+ const { Duplex } = require('stream');
5
+ const { resolve } = require('path');
6
+ const { readFile } = require('fs');
7
+ const { execFile, spawn } = require('child_process');
8
+
9
+ const { isParsedKey, parseKey } = require('./protocol/keyParser.js');
10
+
11
+ const {
12
+ makeBufferParser,
13
+ readUInt32BE,
14
+ writeUInt32BE,
15
+ writeUInt32LE,
16
+ } = require('./protocol/utils.js');
17
+
18
+ function once(cb) {
19
+ let called = false;
20
+ return (...args) => {
21
+ if (called)
22
+ return;
23
+ called = true;
24
+ cb(...args);
25
+ };
26
+ }
27
+
28
+ function concat(buf1, buf2) {
29
+ const combined = Buffer.allocUnsafe(buf1.length + buf2.length);
30
+ buf1.copy(combined, 0);
31
+ buf2.copy(combined, buf1.length);
32
+ return combined;
33
+ }
34
+
35
+ function noop() {}
36
+
37
+ const EMPTY_BUF = Buffer.alloc(0);
38
+
39
+ const binaryParser = makeBufferParser();
40
+
41
+ class BaseAgent {
42
+ getIdentities(cb) {
43
+ cb(new Error('Missing getIdentities() implementation'));
44
+ }
45
+ sign(pubKey, data, options, cb) {
46
+ if (typeof options === 'function')
47
+ cb = options;
48
+ cb(new Error('Missing sign() implementation'));
49
+ }
50
+ }
51
+
52
+ class OpenSSHAgent extends BaseAgent {
53
+ constructor(socketPath) {
54
+ super();
55
+ this.socketPath = socketPath;
56
+ }
57
+
58
+ getStream(cb) {
59
+ cb = once(cb);
60
+ const sock = new Socket();
61
+ sock.on('connect', () => {
62
+ cb(null, sock);
63
+ });
64
+ sock.on('close', onFail)
65
+ .on('end', onFail)
66
+ .on('error', onFail);
67
+ sock.connect(this.socketPath);
68
+
69
+ function onFail() {
70
+ try {
71
+ sock.destroy();
72
+ } catch {}
73
+
74
+ cb(new Error('Failed to connect to agent'));
75
+ }
76
+ }
77
+
78
+ getIdentities(cb) {
79
+ cb = once(cb);
80
+ this.getStream((err, stream) => {
81
+ function onFail(err) {
82
+ if (stream) {
83
+ try {
84
+ stream.destroy();
85
+ } catch {}
86
+ }
87
+ if (!err)
88
+ err = new Error('Failed to retrieve identities from agent');
89
+ cb(err);
90
+ }
91
+
92
+ if (err)
93
+ return onFail(err);
94
+
95
+ const protocol = new AgentProtocol(true);
96
+ protocol.on('error', onFail);
97
+ protocol.pipe(stream).pipe(protocol);
98
+
99
+ stream.on('close', onFail)
100
+ .on('end', onFail)
101
+ .on('error', onFail);
102
+
103
+ protocol.getIdentities((err, keys) => {
104
+ if (err)
105
+ return onFail(err);
106
+ try {
107
+ stream.destroy();
108
+ } catch {}
109
+ cb(null, keys);
110
+ });
111
+ });
112
+ }
113
+
114
+ sign(pubKey, data, options, cb) {
115
+ if (typeof options === 'function') {
116
+ cb = options;
117
+ options = undefined;
118
+ } else if (typeof options !== 'object' || options === null) {
119
+ options = undefined;
120
+ }
121
+
122
+ cb = once(cb);
123
+ this.getStream((err, stream) => {
124
+ function onFail(err) {
125
+ if (stream) {
126
+ try {
127
+ stream.destroy();
128
+ } catch {}
129
+ }
130
+ if (!err)
131
+ err = new Error('Failed to sign data with agent');
132
+ cb(err);
133
+ }
134
+
135
+ if (err)
136
+ return onFail(err);
137
+
138
+ const protocol = new AgentProtocol(true);
139
+ protocol.on('error', onFail);
140
+ protocol.pipe(stream).pipe(protocol);
141
+
142
+ stream.on('close', onFail)
143
+ .on('end', onFail)
144
+ .on('error', onFail);
145
+
146
+ protocol.sign(pubKey, data, options, (err, sig) => {
147
+ if (err)
148
+ return onFail(err);
149
+
150
+ try {
151
+ stream.destroy();
152
+ } catch {}
153
+
154
+ cb(null, sig);
155
+ });
156
+ });
157
+ }
158
+ }
159
+
160
+ const PageantAgent = (() => {
161
+ const RET_ERR_BADARGS = 10;
162
+ const RET_ERR_UNAVAILABLE = 11;
163
+ const RET_ERR_NOMAP = 12;
164
+ const RET_ERR_BINSTDIN = 13;
165
+ const RET_ERR_BINSTDOUT = 14;
166
+ const RET_ERR_BADLEN = 15;
167
+
168
+ const EXEPATH = resolve(__dirname, '..', 'util/pagent.exe');
169
+ const ERROR = {
170
+ [RET_ERR_BADARGS]: new Error('Invalid pagent.exe arguments'),
171
+ [RET_ERR_UNAVAILABLE]: new Error('Pageant is not running'),
172
+ [RET_ERR_NOMAP]: new Error('pagent.exe could not create an mmap'),
173
+ [RET_ERR_BINSTDIN]: new Error('pagent.exe could not set mode for stdin'),
174
+ [RET_ERR_BINSTDOUT]: new Error('pagent.exe could not set mode for stdout'),
175
+ [RET_ERR_BADLEN]:
176
+ new Error('pagent.exe did not get expected input payload'),
177
+ };
178
+
179
+ function destroy(stream) {
180
+ stream.buffer = null;
181
+ if (stream.proc) {
182
+ stream.proc.kill();
183
+ stream.proc = undefined;
184
+ }
185
+ }
186
+
187
+ class PageantSocket extends Duplex {
188
+ constructor() {
189
+ super();
190
+ this.proc = undefined;
191
+ this.buffer = null;
192
+ }
193
+ _read(n) {}
194
+ _write(data, encoding, cb) {
195
+ if (this.buffer === null) {
196
+ this.buffer = data;
197
+ } else {
198
+ const newBuffer = Buffer.allocUnsafe(this.buffer.length + data.length);
199
+ this.buffer.copy(newBuffer, 0);
200
+ data.copy(newBuffer, this.buffer.length);
201
+ this.buffer = newBuffer;
202
+ }
203
+ // Wait for at least all length bytes
204
+ if (this.buffer.length < 4)
205
+ return cb();
206
+
207
+ const len = readUInt32BE(this.buffer, 0);
208
+ // Make sure we have a full message before querying pageant
209
+ if ((this.buffer.length - 4) < len)
210
+ return cb();
211
+
212
+ data = this.buffer.slice(0, 4 + len);
213
+ if (this.buffer.length > (4 + len))
214
+ return cb(new Error('Unexpected multiple agent requests'));
215
+ this.buffer = null;
216
+
217
+ let error;
218
+ const proc = this.proc = spawn(EXEPATH, [ data.length ]);
219
+ proc.stdout.on('data', (data) => {
220
+ this.push(data);
221
+ });
222
+ proc.on('error', (err) => {
223
+ error = err;
224
+ cb(error);
225
+ });
226
+ proc.on('close', (code) => {
227
+ this.proc = undefined;
228
+ if (!error) {
229
+ if (error = ERROR[code])
230
+ return cb(error);
231
+ cb();
232
+ }
233
+ });
234
+ proc.stdin.end(data);
235
+ }
236
+ _final(cb) {
237
+ destroy(this);
238
+ cb();
239
+ }
240
+ _destroy(err, cb) {
241
+ destroy(this);
242
+ cb();
243
+ }
244
+ }
245
+
246
+ return class PageantAgent extends OpenSSHAgent {
247
+ getStream(cb) {
248
+ cb(null, new PageantSocket());
249
+ }
250
+ };
251
+ })();
252
+
253
+ const CygwinAgent = (() => {
254
+ const RE_CYGWIN_SOCK = /^!<socket >(\d+) s ([A-Z0-9]{8}-[A-Z0-9]{8}-[A-Z0-9]{8}-[A-Z0-9]{8})/;
255
+
256
+ return class CygwinAgent extends OpenSSHAgent {
257
+ getStream(cb) {
258
+ cb = once(cb);
259
+
260
+ // The cygwin ssh-agent connection process looks like this:
261
+ // 1. Read the "socket" as a file to get the underlying TCP port and a
262
+ // special "secret" that must be sent to the TCP server.
263
+ // 2. Connect to the server listening on localhost at the TCP port.
264
+ // 3. Send the "secret" to the server.
265
+ // 4. The server sends back the same "secret".
266
+ // 5. Send three 32-bit integer values of zero. This is ordinarily the
267
+ // pid, uid, and gid of this process, but cygwin will actually
268
+ // send us the correct values as a response.
269
+ // 6. The server sends back the pid, uid, gid.
270
+ // 7. Disconnect.
271
+ // 8. Repeat steps 2-6, except send the received pid, uid, and gid in
272
+ // step 5 instead of zeroes.
273
+ // 9. Connection is ready to be used.
274
+
275
+ let socketPath = this.socketPath;
276
+ let triedCygpath = false;
277
+ readFile(socketPath, function readCygsocket(err, data) {
278
+ if (err) {
279
+ if (triedCygpath)
280
+ return cb(new Error('Invalid cygwin unix socket path'));
281
+
282
+ // Try using `cygpath` to convert a possible *nix-style path to the
283
+ // real Windows path before giving up ...
284
+ execFile('cygpath', ['-w', socketPath], (err, stdout, stderr) => {
285
+ if (err || stdout.length === 0)
286
+ return cb(new Error('Invalid cygwin unix socket path'));
287
+
288
+ triedCygpath = true;
289
+ socketPath = stdout.toString().replace(/[\r\n]/g, '');
290
+ readFile(socketPath, readCygsocket);
291
+ });
292
+ return;
293
+ }
294
+
295
+ const m = RE_CYGWIN_SOCK.exec(data.toString('ascii'));
296
+ if (!m)
297
+ return cb(new Error('Malformed cygwin unix socket file'));
298
+
299
+ let state;
300
+ let bc = 0;
301
+ let isRetrying = false;
302
+ const inBuf = [];
303
+ let sock;
304
+
305
+ // Use 0 for pid, uid, and gid to ensure we get an error and also
306
+ // a valid uid and gid from cygwin so that we don't have to figure it
307
+ // out ourselves
308
+ let credsBuf = Buffer.alloc(12);
309
+
310
+ // Parse cygwin unix socket file contents
311
+ const port = parseInt(m[1], 10);
312
+ const secret = m[2].replace(/-/g, '');
313
+ const secretBuf = Buffer.allocUnsafe(16);
314
+ for (let i = 0, j = 0; j < 32; ++i, j += 2)
315
+ secretBuf[i] = parseInt(secret.substring(j, j + 2), 16);
316
+
317
+ // Convert to host order (always LE for Windows)
318
+ for (let i = 0; i < 16; i += 4)
319
+ writeUInt32LE(secretBuf, readUInt32BE(secretBuf, i), i);
320
+
321
+ tryConnect();
322
+
323
+ function _onconnect() {
324
+ bc = 0;
325
+ state = 'secret';
326
+ sock.write(secretBuf);
327
+ }
328
+
329
+ function _ondata(data) {
330
+ bc += data.length;
331
+
332
+ if (state === 'secret') {
333
+ // The secret we sent is echoed back to us by cygwin, not sure of
334
+ // the reason for that, but we ignore it nonetheless ...
335
+ if (bc === 16) {
336
+ bc = 0;
337
+ state = 'creds';
338
+ sock.write(credsBuf);
339
+ }
340
+ return;
341
+ }
342
+
343
+ if (state === 'creds') {
344
+ // If this is the first attempt, make sure to gather the valid
345
+ // uid and gid for our next attempt
346
+ if (!isRetrying)
347
+ inBuf.push(data);
348
+
349
+ if (bc === 12) {
350
+ sock.removeListener('connect', _onconnect);
351
+ sock.removeListener('data', _ondata);
352
+ sock.removeListener('error', onFail);
353
+ sock.removeListener('end', onFail);
354
+ sock.removeListener('close', onFail);
355
+
356
+ if (isRetrying)
357
+ return cb(null, sock);
358
+
359
+ isRetrying = true;
360
+ credsBuf = Buffer.concat(inBuf);
361
+ writeUInt32LE(credsBuf, process.pid, 0);
362
+ sock.on('error', () => {});
363
+ sock.destroy();
364
+
365
+ tryConnect();
366
+ }
367
+ }
368
+ }
369
+
370
+ function onFail() {
371
+ cb(new Error('Problem negotiating cygwin unix socket security'));
372
+ }
373
+
374
+ function tryConnect() {
375
+ sock = new Socket();
376
+ sock.on('connect', _onconnect);
377
+ sock.on('data', _ondata);
378
+ sock.on('error', onFail);
379
+ sock.on('end', onFail);
380
+ sock.on('close', onFail);
381
+ sock.connect(port);
382
+ }
383
+ });
384
+ }
385
+ };
386
+ })();
387
+
388
+ // Format of `//./pipe/ANYTHING`, with forward slashes and backward slashes
389
+ // being interchangeable
390
+ const WINDOWS_PIPE_REGEX = /^[/\\][/\\]\.[/\\]pipe[/\\].+/;
391
+ function createAgent(path) {
392
+ if (process.platform === 'win32' && !WINDOWS_PIPE_REGEX.test(path)) {
393
+ return (path === 'pageant'
394
+ ? new PageantAgent()
395
+ : new CygwinAgent(path));
396
+ }
397
+ return new OpenSSHAgent(path);
398
+ }
399
+
400
+ const AgentProtocol = (() => {
401
+ // Client->Server messages
402
+ const SSH_AGENTC_REQUEST_IDENTITIES = 11;
403
+ const SSH_AGENTC_SIGN_REQUEST = 13;
404
+ // const SSH_AGENTC_ADD_IDENTITY = 17;
405
+ // const SSH_AGENTC_REMOVE_IDENTITY = 18;
406
+ // const SSH_AGENTC_REMOVE_ALL_IDENTITIES = 19;
407
+ // const SSH_AGENTC_ADD_SMARTCARD_KEY = 20;
408
+ // const SSH_AGENTC_REMOVE_SMARTCARD_KEY = 21;
409
+ // const SSH_AGENTC_LOCK = 22;
410
+ // const SSH_AGENTC_UNLOCK = 23;
411
+ // const SSH_AGENTC_ADD_ID_CONSTRAINED = 25;
412
+ // const SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED = 26;
413
+ // const SSH_AGENTC_EXTENSION = 27;
414
+ // Server->Client messages
415
+ const SSH_AGENT_FAILURE = 5;
416
+ // const SSH_AGENT_SUCCESS = 6;
417
+ const SSH_AGENT_IDENTITIES_ANSWER = 12;
418
+ const SSH_AGENT_SIGN_RESPONSE = 14;
419
+ // const SSH_AGENT_EXTENSION_FAILURE = 28;
420
+
421
+ // const SSH_AGENT_CONSTRAIN_LIFETIME = 1;
422
+ // const SSH_AGENT_CONSTRAIN_CONFIRM = 2;
423
+ // const SSH_AGENT_CONSTRAIN_EXTENSION = 255;
424
+
425
+ const SSH_AGENT_RSA_SHA2_256 = (1 << 1);
426
+ const SSH_AGENT_RSA_SHA2_512 = (1 << 2);
427
+
428
+ const ROLE_CLIENT = 0;
429
+ const ROLE_SERVER = 1;
430
+
431
+ // Ensures that responses get sent back in the same order the requests were
432
+ // received
433
+ function processResponses(protocol) {
434
+ let ret;
435
+ while (protocol[SYM_REQS].length) {
436
+ const nextResponse = protocol[SYM_REQS][0][SYM_RESP];
437
+ if (nextResponse === undefined)
438
+ break;
439
+
440
+ protocol[SYM_REQS].shift();
441
+ ret = protocol.push(nextResponse);
442
+ }
443
+ return ret;
444
+ }
445
+
446
+ const SYM_TYPE = Symbol('Inbound Request Type');
447
+ const SYM_RESP = Symbol('Inbound Request Response');
448
+ const SYM_CTX = Symbol('Inbound Request Context');
449
+ class AgentInboundRequest {
450
+ constructor(type, ctx) {
451
+ this[SYM_TYPE] = type;
452
+ this[SYM_RESP] = undefined;
453
+ this[SYM_CTX] = ctx;
454
+ }
455
+ hasResponded() {
456
+ return (this[SYM_RESP] !== undefined);
457
+ }
458
+ getType() {
459
+ return this[SYM_TYPE];
460
+ }
461
+ getContext() {
462
+ return this[SYM_CTX];
463
+ }
464
+ }
465
+ function respond(protocol, req, data) {
466
+ req[SYM_RESP] = data;
467
+ return processResponses(protocol);
468
+ }
469
+
470
+ function cleanup(protocol) {
471
+ protocol[SYM_BUFFER] = null;
472
+ if (protocol[SYM_MODE] === ROLE_CLIENT) {
473
+ const reqs = protocol[SYM_REQS];
474
+ if (reqs && reqs.length) {
475
+ protocol[SYM_REQS] = [];
476
+ for (const req of reqs)
477
+ req.cb(new Error('No reply from server'));
478
+ }
479
+ }
480
+
481
+ // Node streams hackery to make streams do the "right thing"
482
+ try {
483
+ protocol.end();
484
+ } catch {}
485
+ setImmediate(() => {
486
+ if (!protocol[SYM_ENDED])
487
+ protocol.emit('end');
488
+ if (!protocol[SYM_CLOSED])
489
+ protocol.emit('close');
490
+ });
491
+ }
492
+
493
+ function onClose() {
494
+ this[SYM_CLOSED] = true;
495
+ }
496
+
497
+ function onEnd() {
498
+ this[SYM_ENDED] = true;
499
+ }
500
+
501
+ const SYM_REQS = Symbol('Requests');
502
+ const SYM_MODE = Symbol('Agent Protocol Role');
503
+ const SYM_BUFFER = Symbol('Agent Protocol Buffer');
504
+ const SYM_MSGLEN = Symbol('Agent Protocol Current Message Length');
505
+ const SYM_CLOSED = Symbol('Agent Protocol Closed');
506
+ const SYM_ENDED = Symbol('Agent Protocol Ended');
507
+ // Implementation based on:
508
+ // https://tools.ietf.org/html/draft-miller-ssh-agent-04
509
+ return class AgentProtocol extends Duplex {
510
+ /*
511
+ Notes:
512
+ - `constraint` type consists of:
513
+ byte constraint_type
514
+ byte[] constraint_data
515
+ where `constraint_type` is one of:
516
+ * SSH_AGENT_CONSTRAIN_LIFETIME
517
+ - `constraint_data` consists of:
518
+ uint32 seconds
519
+ * SSH_AGENT_CONSTRAIN_CONFIRM
520
+ - `constraint_data` N/A
521
+ * SSH_AGENT_CONSTRAIN_EXTENSION
522
+ - `constraint_data` consists of:
523
+ string extension name
524
+ byte[] extension-specific details
525
+ */
526
+
527
+ constructor(isClient) {
528
+ super({ autoDestroy: true, emitClose: false });
529
+ this[SYM_MODE] = (isClient ? ROLE_CLIENT : ROLE_SERVER);
530
+ this[SYM_REQS] = [];
531
+ this[SYM_BUFFER] = null;
532
+ this[SYM_MSGLEN] = -1;
533
+ this.once('end', onEnd);
534
+ this.once('close', onClose);
535
+ }
536
+
537
+ _read(n) {}
538
+
539
+ _write(data, encoding, cb) {
540
+ /*
541
+ Messages are of the format:
542
+ uint32 message length
543
+ byte message type
544
+ byte[message length - 1] message contents
545
+ */
546
+ if (this[SYM_BUFFER] === null)
547
+ this[SYM_BUFFER] = data;
548
+ else
549
+ this[SYM_BUFFER] = concat(this[SYM_BUFFER], data);
550
+
551
+ let buffer = this[SYM_BUFFER];
552
+ let bufferLen = buffer.length;
553
+
554
+ let p = 0;
555
+ while (p < bufferLen) {
556
+ // Wait for length + type
557
+ if (bufferLen < 5)
558
+ break;
559
+
560
+ if (this[SYM_MSGLEN] === -1)
561
+ this[SYM_MSGLEN] = readUInt32BE(buffer, p);
562
+
563
+ // Check if we have the entire message
564
+ if (bufferLen < (4 + this[SYM_MSGLEN]))
565
+ break;
566
+
567
+ const msgType = buffer[p += 4];
568
+ ++p;
569
+
570
+ if (this[SYM_MODE] === ROLE_CLIENT) {
571
+ if (this[SYM_REQS].length === 0)
572
+ return cb(new Error('Received unexpected message from server'));
573
+
574
+ const req = this[SYM_REQS].shift();
575
+
576
+ switch (msgType) {
577
+ case SSH_AGENT_FAILURE:
578
+ req.cb(new Error('Agent responded with failure'));
579
+ break;
580
+ case SSH_AGENT_IDENTITIES_ANSWER: {
581
+ if (req.type !== SSH_AGENTC_REQUEST_IDENTITIES)
582
+ return cb(new Error('Agent responded with wrong message type'));
583
+
584
+ /*
585
+ byte SSH_AGENT_IDENTITIES_ANSWER
586
+ uint32 nkeys
587
+
588
+ where `nkeys` is 0 or more of:
589
+ string key blob
590
+ string comment
591
+ */
592
+
593
+ binaryParser.init(buffer, p);
594
+
595
+ const numKeys = binaryParser.readUInt32BE();
596
+
597
+ if (numKeys === undefined) {
598
+ binaryParser.clear();
599
+ return cb(new Error('Malformed agent response'));
600
+ }
601
+
602
+ const keys = [];
603
+ for (let i = 0; i < numKeys; ++i) {
604
+ let pubKey = binaryParser.readString();
605
+ if (pubKey === undefined) {
606
+ binaryParser.clear();
607
+ return cb(new Error('Malformed agent response'));
608
+ }
609
+
610
+ const comment = binaryParser.readString(true);
611
+ if (comment === undefined) {
612
+ binaryParser.clear();
613
+ return cb(new Error('Malformed agent response'));
614
+ }
615
+
616
+ pubKey = parseKey(pubKey);
617
+ // We continue parsing the packet if we encounter an error
618
+ // in case the error is due to the key being an unsupported
619
+ // type
620
+ if (pubKey instanceof Error)
621
+ continue;
622
+
623
+ pubKey.comment = pubKey.comment || comment;
624
+
625
+ keys.push(pubKey);
626
+ }
627
+ p = binaryParser.pos();
628
+ binaryParser.clear();
629
+
630
+ req.cb(null, keys);
631
+ break;
632
+ }
633
+ case SSH_AGENT_SIGN_RESPONSE: {
634
+ if (req.type !== SSH_AGENTC_SIGN_REQUEST)
635
+ return cb(new Error('Agent responded with wrong message type'));
636
+
637
+ /*
638
+ byte SSH_AGENT_SIGN_RESPONSE
639
+ string signature
640
+ */
641
+
642
+ binaryParser.init(buffer, p);
643
+ let signature = binaryParser.readString();
644
+ p = binaryParser.pos();
645
+ binaryParser.clear();
646
+
647
+ if (signature === undefined)
648
+ return cb(new Error('Malformed agent response'));
649
+
650
+ // We strip the algorithm from OpenSSH's output and assume it's
651
+ // using the algorithm we specified. This makes it easier on
652
+ // custom Agent implementations so they don't have to construct
653
+ // the correct binary format for a (OpenSSH-style) signature.
654
+
655
+ // TODO: verify signature type based on key and options used
656
+ // during initial sign request
657
+ binaryParser.init(signature, 0);
658
+ binaryParser.readString(true);
659
+ signature = binaryParser.readString();
660
+ binaryParser.clear();
661
+
662
+ if (signature === undefined)
663
+ return cb(new Error('Malformed OpenSSH signature format'));
664
+
665
+ req.cb(null, signature);
666
+ break;
667
+ }
668
+ default:
669
+ return cb(
670
+ new Error('Agent responded with unsupported message type')
671
+ );
672
+ }
673
+ } else {
674
+ switch (msgType) {
675
+ case SSH_AGENTC_REQUEST_IDENTITIES: {
676
+ const req = new AgentInboundRequest(msgType);
677
+ this[SYM_REQS].push(req);
678
+ /*
679
+ byte SSH_AGENTC_REQUEST_IDENTITIES
680
+ */
681
+ this.emit('identities', req);
682
+ break;
683
+ }
684
+ case SSH_AGENTC_SIGN_REQUEST: {
685
+ /*
686
+ byte SSH_AGENTC_SIGN_REQUEST
687
+ string key_blob
688
+ string data
689
+ uint32 flags
690
+ */
691
+ binaryParser.init(buffer, p);
692
+ let pubKey = binaryParser.readString();
693
+ const data = binaryParser.readString();
694
+ const flagsVal = binaryParser.readUInt32BE();
695
+ p = binaryParser.pos();
696
+ binaryParser.clear();
697
+ if (flagsVal === undefined) {
698
+ const req = new AgentInboundRequest(msgType);
699
+ this[SYM_REQS].push(req);
700
+ return this.failureReply(req);
701
+ }
702
+
703
+ pubKey = parseKey(pubKey);
704
+ if (pubKey instanceof Error) {
705
+ const req = new AgentInboundRequest(msgType);
706
+ this[SYM_REQS].push(req);
707
+ return this.failureReply(req);
708
+ }
709
+
710
+ const flags = {
711
+ hash: undefined,
712
+ };
713
+ let ctx;
714
+ if (pubKey.type === 'ssh-rsa') {
715
+ if (flagsVal & SSH_AGENT_RSA_SHA2_256) {
716
+ ctx = 'rsa-sha2-256';
717
+ flags.hash = 'sha256';
718
+ } else if (flagsVal & SSH_AGENT_RSA_SHA2_512) {
719
+ ctx = 'rsa-sha2-512';
720
+ flags.hash = 'sha512';
721
+ }
722
+ }
723
+ if (ctx === undefined)
724
+ ctx = pubKey.type;
725
+
726
+ const req = new AgentInboundRequest(msgType, ctx);
727
+ this[SYM_REQS].push(req);
728
+
729
+ this.emit('sign', req, pubKey, data, flags);
730
+ break;
731
+ }
732
+ default: {
733
+ const req = new AgentInboundRequest(msgType);
734
+ this[SYM_REQS].push(req);
735
+ this.failureReply(req);
736
+ }
737
+ }
738
+ }
739
+
740
+ // Get ready for next message
741
+ this[SYM_MSGLEN] = -1;
742
+ if (p === bufferLen) {
743
+ // Nothing left to process for now
744
+ this[SYM_BUFFER] = null;
745
+ break;
746
+ } else {
747
+ this[SYM_BUFFER] = buffer = buffer.slice(p);
748
+ bufferLen = buffer.length;
749
+ p = 0;
750
+ }
751
+ }
752
+
753
+ cb();
754
+ }
755
+
756
+ _destroy(err, cb) {
757
+ cleanup(this);
758
+ cb();
759
+ }
760
+
761
+ _final(cb) {
762
+ cleanup(this);
763
+ cb();
764
+ }
765
+
766
+ // Client->Server messages =================================================
767
+ sign(pubKey, data, options, cb) {
768
+ if (this[SYM_MODE] !== ROLE_CLIENT)
769
+ throw new Error('Client-only method called with server role');
770
+
771
+ if (typeof options === 'function') {
772
+ cb = options;
773
+ options = undefined;
774
+ } else if (typeof options !== 'object' || options === null) {
775
+ options = undefined;
776
+ }
777
+
778
+ let flags = 0;
779
+
780
+ pubKey = parseKey(pubKey);
781
+ if (pubKey instanceof Error)
782
+ throw new Error('Invalid public key argument');
783
+
784
+ if (pubKey.type === 'ssh-rsa' && options) {
785
+ switch (options.hash) {
786
+ case 'sha256':
787
+ flags = SSH_AGENT_RSA_SHA2_256;
788
+ break;
789
+ case 'sha512':
790
+ flags = SSH_AGENT_RSA_SHA2_512;
791
+ break;
792
+ }
793
+ }
794
+ pubKey = pubKey.getPublicSSH();
795
+
796
+ /*
797
+ byte SSH_AGENTC_SIGN_REQUEST
798
+ string key_blob
799
+ string data
800
+ uint32 flags
801
+ */
802
+ const type = SSH_AGENTC_SIGN_REQUEST;
803
+ const keyLen = pubKey.length;
804
+ const dataLen = data.length;
805
+ let p = 0;
806
+ const buf = Buffer.allocUnsafe(4 + 1 + 4 + keyLen + 4 + dataLen + 4);
807
+
808
+ writeUInt32BE(buf, buf.length - 4, p);
809
+
810
+ buf[p += 4] = type;
811
+
812
+ writeUInt32BE(buf, keyLen, ++p);
813
+ pubKey.copy(buf, p += 4);
814
+
815
+ writeUInt32BE(buf, dataLen, p += keyLen);
816
+ data.copy(buf, p += 4);
817
+
818
+ writeUInt32BE(buf, flags, p += dataLen);
819
+
820
+ if (typeof cb !== 'function')
821
+ cb = noop;
822
+
823
+ this[SYM_REQS].push({ type, cb });
824
+
825
+ return this.push(buf);
826
+ }
827
+ getIdentities(cb) {
828
+ if (this[SYM_MODE] !== ROLE_CLIENT)
829
+ throw new Error('Client-only method called with server role');
830
+
831
+ /*
832
+ byte SSH_AGENTC_REQUEST_IDENTITIES
833
+ */
834
+ const type = SSH_AGENTC_REQUEST_IDENTITIES;
835
+
836
+ let p = 0;
837
+ const buf = Buffer.allocUnsafe(4 + 1);
838
+
839
+ writeUInt32BE(buf, buf.length - 4, p);
840
+
841
+ buf[p += 4] = type;
842
+
843
+ if (typeof cb !== 'function')
844
+ cb = noop;
845
+
846
+ this[SYM_REQS].push({ type, cb });
847
+
848
+ return this.push(buf);
849
+ }
850
+
851
+ // Server->Client messages =================================================
852
+ failureReply(req) {
853
+ if (this[SYM_MODE] !== ROLE_SERVER)
854
+ throw new Error('Server-only method called with client role');
855
+
856
+ if (!(req instanceof AgentInboundRequest))
857
+ throw new Error('Wrong request argument');
858
+
859
+ if (req.hasResponded())
860
+ return true;
861
+
862
+ let p = 0;
863
+ const buf = Buffer.allocUnsafe(4 + 1);
864
+
865
+ writeUInt32BE(buf, buf.length - 4, p);
866
+
867
+ buf[p += 4] = SSH_AGENT_FAILURE;
868
+
869
+ return respond(this, req, buf);
870
+ }
871
+ getIdentitiesReply(req, keys) {
872
+ if (this[SYM_MODE] !== ROLE_SERVER)
873
+ throw new Error('Server-only method called with client role');
874
+
875
+ if (!(req instanceof AgentInboundRequest))
876
+ throw new Error('Wrong request argument');
877
+
878
+ if (req.hasResponded())
879
+ return true;
880
+
881
+ /*
882
+ byte SSH_AGENT_IDENTITIES_ANSWER
883
+ uint32 nkeys
884
+
885
+ where `nkeys` is 0 or more of:
886
+ string key blob
887
+ string comment
888
+ */
889
+
890
+ if (req.getType() !== SSH_AGENTC_REQUEST_IDENTITIES)
891
+ throw new Error('Invalid response to request');
892
+
893
+ if (!Array.isArray(keys))
894
+ throw new Error('Keys argument must be an array');
895
+
896
+ let totalKeysLen = 4; // Include `nkeys` size
897
+
898
+ const newKeys = [];
899
+ for (let i = 0; i < keys.length; ++i) {
900
+ const entry = keys[i];
901
+ if (typeof entry !== 'object' || entry === null)
902
+ throw new Error(`Invalid key entry: ${entry}`);
903
+
904
+ let pubKey;
905
+ let comment;
906
+ if (isParsedKey(entry)) {
907
+ pubKey = entry;
908
+ } else if (isParsedKey(entry.pubKey)) {
909
+ pubKey = entry.pubKey;
910
+ } else {
911
+ if (typeof entry.pubKey !== 'object' || entry.pubKey === null)
912
+ continue;
913
+ ({ pubKey, comment } = entry.pubKey);
914
+ pubKey = parseKey(pubKey);
915
+ if (pubKey instanceof Error)
916
+ continue; // TODO: add debug output
917
+ }
918
+ comment = pubKey.comment || comment;
919
+ pubKey = pubKey.getPublicSSH();
920
+
921
+ totalKeysLen += 4 + pubKey.length;
922
+
923
+ if (comment && typeof comment === 'string')
924
+ comment = Buffer.from(comment);
925
+ else if (!Buffer.isBuffer(comment))
926
+ comment = EMPTY_BUF;
927
+
928
+ totalKeysLen += 4 + comment.length;
929
+
930
+ newKeys.push({ pubKey, comment });
931
+ }
932
+
933
+ let p = 0;
934
+ const buf = Buffer.allocUnsafe(4 + 1 + totalKeysLen);
935
+
936
+ writeUInt32BE(buf, buf.length - 4, p);
937
+
938
+ buf[p += 4] = SSH_AGENT_IDENTITIES_ANSWER;
939
+
940
+ writeUInt32BE(buf, newKeys.length, ++p);
941
+ p += 4;
942
+ for (let i = 0; i < newKeys.length; ++i) {
943
+ const { pubKey, comment } = newKeys[i];
944
+
945
+ writeUInt32BE(buf, pubKey.length, p);
946
+ pubKey.copy(buf, p += 4);
947
+
948
+ writeUInt32BE(buf, comment.length, p += pubKey.length);
949
+ p += 4;
950
+ if (comment.length) {
951
+ comment.copy(buf, p);
952
+ p += comment.length;
953
+ }
954
+ }
955
+
956
+ return respond(this, req, buf);
957
+ }
958
+ signReply(req, signature) {
959
+ if (this[SYM_MODE] !== ROLE_SERVER)
960
+ throw new Error('Server-only method called with client role');
961
+
962
+ if (!(req instanceof AgentInboundRequest))
963
+ throw new Error('Wrong request argument');
964
+
965
+ if (req.hasResponded())
966
+ return true;
967
+
968
+ /*
969
+ byte SSH_AGENT_SIGN_RESPONSE
970
+ string signature
971
+ */
972
+
973
+ if (req.getType() !== SSH_AGENTC_SIGN_REQUEST)
974
+ throw new Error('Invalid response to request');
975
+
976
+ if (!Buffer.isBuffer(signature))
977
+ throw new Error('Signature argument must be a Buffer');
978
+
979
+ if (signature.length === 0)
980
+ throw new Error('Signature argument must be non-empty');
981
+
982
+ /*
983
+ OpenSSH agent signatures are encoded as:
984
+
985
+ string signature format identifier (as specified by the
986
+ public key/certificate format)
987
+ byte[n] signature blob in format specific encoding.
988
+ - This is actually a `string` for: rsa, dss, ecdsa, and ed25519
989
+ types
990
+ */
991
+
992
+ let p = 0;
993
+ const sigFormat = req.getContext();
994
+ const sigFormatLen = Buffer.byteLength(sigFormat);
995
+ const buf = Buffer.allocUnsafe(
996
+ 4 + 1 + 4 + 4 + sigFormatLen + 4 + signature.length
997
+ );
998
+
999
+ writeUInt32BE(buf, buf.length - 4, p);
1000
+
1001
+ buf[p += 4] = SSH_AGENT_SIGN_RESPONSE;
1002
+
1003
+ writeUInt32BE(buf, 4 + sigFormatLen + 4 + signature.length, ++p);
1004
+ writeUInt32BE(buf, sigFormatLen, p += 4);
1005
+ buf.utf8Write(sigFormat, p += 4, sigFormatLen);
1006
+ writeUInt32BE(buf, signature.length, p += sigFormatLen);
1007
+ signature.copy(buf, p += 4);
1008
+
1009
+ return respond(this, req, buf);
1010
+ }
1011
+ };
1012
+ })();
1013
+
1014
+ const SYM_AGENT = Symbol('Agent');
1015
+ const SYM_AGENT_KEYS = Symbol('Agent Keys');
1016
+ const SYM_AGENT_KEYS_IDX = Symbol('Agent Keys Index');
1017
+ const SYM_AGENT_CBS = Symbol('Agent Init Callbacks');
1018
+ class AgentContext {
1019
+ constructor(agent) {
1020
+ if (typeof agent === 'string')
1021
+ agent = createAgent(agent);
1022
+ else if (!isAgent(agent))
1023
+ throw new Error('Invalid agent argument');
1024
+ this[SYM_AGENT] = agent;
1025
+ this[SYM_AGENT_KEYS] = null;
1026
+ this[SYM_AGENT_KEYS_IDX] = -1;
1027
+ this[SYM_AGENT_CBS] = null;
1028
+ }
1029
+ init(cb) {
1030
+ if (typeof cb !== 'function')
1031
+ cb = noop;
1032
+
1033
+ if (this[SYM_AGENT_KEYS] === null) {
1034
+ if (this[SYM_AGENT_CBS] === null) {
1035
+ this[SYM_AGENT_CBS] = [cb];
1036
+
1037
+ const doCbs = (...args) => {
1038
+ process.nextTick(() => {
1039
+ const cbs = this[SYM_AGENT_CBS];
1040
+ this[SYM_AGENT_CBS] = null;
1041
+ for (const cb of cbs)
1042
+ cb(...args);
1043
+ });
1044
+ };
1045
+
1046
+ this[SYM_AGENT].getIdentities(once((err, keys) => {
1047
+ if (err)
1048
+ return doCbs(err);
1049
+
1050
+ if (!Array.isArray(keys)) {
1051
+ return doCbs(new Error(
1052
+ 'Agent implementation failed to provide keys'
1053
+ ));
1054
+ }
1055
+
1056
+ const newKeys = [];
1057
+ for (let key of keys) {
1058
+ key = parseKey(key);
1059
+ if (key instanceof Error) {
1060
+ // TODO: add debug output
1061
+ continue;
1062
+ }
1063
+ newKeys.push(key);
1064
+ }
1065
+
1066
+ this[SYM_AGENT_KEYS] = newKeys;
1067
+ this[SYM_AGENT_KEYS_IDX] = -1;
1068
+ doCbs();
1069
+ }));
1070
+ } else {
1071
+ this[SYM_AGENT_CBS].push(cb);
1072
+ }
1073
+ } else {
1074
+ process.nextTick(cb);
1075
+ }
1076
+ }
1077
+ nextKey() {
1078
+ if (this[SYM_AGENT_KEYS] === null
1079
+ || ++this[SYM_AGENT_KEYS_IDX] >= this[SYM_AGENT_KEYS].length) {
1080
+ return false;
1081
+ }
1082
+
1083
+ return this[SYM_AGENT_KEYS][this[SYM_AGENT_KEYS_IDX]];
1084
+ }
1085
+ currentKey() {
1086
+ if (this[SYM_AGENT_KEYS] === null
1087
+ || this[SYM_AGENT_KEYS_IDX] >= this[SYM_AGENT_KEYS].length) {
1088
+ return null;
1089
+ }
1090
+
1091
+ return this[SYM_AGENT_KEYS][this[SYM_AGENT_KEYS_IDX]];
1092
+ }
1093
+ pos() {
1094
+ if (this[SYM_AGENT_KEYS] === null
1095
+ || this[SYM_AGENT_KEYS_IDX] >= this[SYM_AGENT_KEYS].length) {
1096
+ return -1;
1097
+ }
1098
+
1099
+ return this[SYM_AGENT_KEYS_IDX];
1100
+ }
1101
+ reset() {
1102
+ this[SYM_AGENT_KEYS_IDX] = -1;
1103
+ }
1104
+
1105
+ sign(...args) {
1106
+ this[SYM_AGENT].sign(...args);
1107
+ }
1108
+ }
1109
+
1110
+ function isAgent(val) {
1111
+ return (val instanceof BaseAgent);
1112
+ }
1113
+
1114
+ module.exports = {
1115
+ AgentContext,
1116
+ AgentProtocol,
1117
+ BaseAgent,
1118
+ createAgent,
1119
+ CygwinAgent,
1120
+ isAgent,
1121
+ OpenSSHAgent,
1122
+ PageantAgent,
1123
+ };