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,413 @@
1
+ SFTP events
2
+ -----------
3
+
4
+ **Client/Server events**
5
+
6
+ * **ready**() - Emitted after initial protocol version check has passed.
7
+
8
+ **Server-only events**
9
+
10
+ _Responses to these client requests are sent using one of the methods listed further in this document under `Server-only methods`. The valid response(s) for each request are documented below._
11
+
12
+ * **OPEN**(< _integer_ >reqID, < _string_ >filename, < _integer_ >flags, < _ATTRS_ >attrs)
13
+
14
+ `flags` is a bitfield containing any of the flags defined in `OPEN_MODE`.
15
+ Use the static method `flagsToString()` to convert the value to a mode
16
+ string to be used by `fs.open()` (e.g. `'r'`).
17
+
18
+ Respond using one of the following:
19
+
20
+ * `handle()` - This indicates a successful opening of the file and passes
21
+ the given handle back to the client to use to refer to this open file for
22
+ future operations (e.g. reading, writing, closing).
23
+
24
+ * `status()` - Use this to indicate a failure to open the requested file.
25
+
26
+ * **READ**(< _integer_ >reqID, < _Buffer_ >handle, < _integer_ >offset, < _integer_ >length)
27
+
28
+ Respond using one of the following:
29
+
30
+ * `data()` - Use this to send the requested chunk of data back to the client.
31
+ The amount of data sent is allowed to be less than the `length` requested,
32
+ for example if the file ends between `offset` and `offset + length`.
33
+
34
+ * `status()` - Use this to indicate either end of file (`STATUS_CODE.EOF`)
35
+ has been reached (`offset` is past the end of the file) or if an error
36
+ occurred while reading the requested part of the file.
37
+
38
+ * **WRITE**(< _integer_ >reqID, < _Buffer_ >handle, < _integer_ >offset, < _Buffer_ >data)
39
+
40
+ Respond using:
41
+
42
+ * `status()` - Use this to indicate success/failure of the write to the file.
43
+
44
+ * **FSTAT**(< _integer_ >reqID, < _Buffer_ >handle)
45
+
46
+ Respond using one of the following:
47
+
48
+ * `attrs()` - Use this to send the attributes for the requested
49
+ file/directory back to the client.
50
+
51
+ * `status()` - Use this to indicate an error occurred while accessing the
52
+ file/directory.
53
+
54
+ * **FSETSTAT**(< _integer_ >reqID, < _Buffer_ >handle, < _ATTRS_ >attrs)
55
+
56
+ Respond using:
57
+
58
+ * `status()` - Use this to indicates success/failure of the setting of the
59
+ given file/directory attributes.
60
+
61
+ * **CLOSE**(< _integer_ >reqID, < _Buffer_ >handle)
62
+
63
+ Respond using:
64
+
65
+ * `status()` - Use this to indicate success (`STATUS_CODE.OK`) or failure of
66
+ the closing of the file identified by `handle`.
67
+
68
+ * **OPENDIR**(< _integer_ >reqID, < _string_ >path)
69
+
70
+ Respond using one of the following:
71
+
72
+ * `handle()` - This indicates a successful opening of the directory and
73
+ passes the given handle back to the client to use to refer to this open
74
+ directory for future operations (e.g. reading directory contents, closing).
75
+
76
+ * `status()` - Use this to indicate a failure to open the requested
77
+ directory.
78
+
79
+ * **READDIR**(< _integer_ >reqID, < _Buffer_ >handle)
80
+
81
+ Respond using one of the following:
82
+
83
+ * `name()` - Use this to send one or more directory listings for the open
84
+ directory back to the client.
85
+
86
+ * `status()` - Use this to indicate either end of directory contents
87
+ (`STATUS_CODE.EOF`) or if an error occurred while reading the directory
88
+ contents.
89
+
90
+ * **LSTAT**(< _integer_ >reqID, < _string_ >path)
91
+
92
+ Respond using one of the following:
93
+
94
+ * `attrs()` - Use this to send the attributes for the requested
95
+ file/directory back to the client.
96
+
97
+ * `status()` - Use this to indicate an error occurred while accessing the
98
+ file/directory.
99
+
100
+ * **STAT**(< _integer_ >reqID, < _string_ >path)
101
+
102
+ Respond using one of the following:
103
+
104
+ * `attrs()` - Use this to send the attributes for the requested
105
+ file/directory back to the client.
106
+
107
+ * `status()` - Use this to indicate an error occurred while accessing the
108
+ file/directory.
109
+
110
+ * **REMOVE**(< _integer_ >reqID, < _string_ >path)
111
+
112
+ Respond using:
113
+
114
+ * `status()` - Use this to indicate success/failure of the removal of the
115
+ file at `path`.
116
+
117
+ * **RMDIR**(< _integer_ >reqID, < _string_ >path)
118
+
119
+ Respond using:
120
+
121
+ * `status()` - Use this to indicate success/failure of the removal of the
122
+ directory at `path`.
123
+
124
+ * **REALPATH**(< _integer_ >reqID, < _string_ >path)
125
+
126
+ Respond using one of the following:
127
+
128
+ * `name()` - Use this to respond with a normalized version of `path`.
129
+ No file/directory attributes are required to be sent in this response.
130
+
131
+ * `status()` - Use this to indicate a failure in normalizing `path`.
132
+
133
+ * **READLINK**(< _integer_ >reqID, < _string_ >path)
134
+
135
+ Respond using one of the following:
136
+
137
+ * `name()` - Use this to respond with the target of the symlink at `path`.
138
+ No file/directory attributes are required to be sent in this response.
139
+
140
+ * `status()` - Use this to indicate a failure in reading the symlink at
141
+ `path`.
142
+
143
+ * **SETSTAT**(< _integer_ >reqID, < _string_ >path, < _ATTRS_ >attrs)
144
+
145
+ Respond using:
146
+
147
+ * `status()` - Use this to indicates success/failure of the setting of the
148
+ given file/directory attributes.
149
+
150
+ * **MKDIR**(< _integer_ >reqID, < _string_ >path, < _ATTRS_ >attrs)
151
+
152
+ Respond using:
153
+
154
+ * `status()` - Use this to indicate success/failure of the creation of the
155
+ directory at `path`.
156
+
157
+ * **RENAME**(< _integer_ >reqID, < _string_ >oldPath, < _string_ >newPath)
158
+
159
+ Respond using:
160
+
161
+ * `status()` - Use this to indicate success/failure of the renaming of the
162
+ file/directory at `oldPath` to `newPath`.
163
+
164
+ * **SYMLINK**(< _integer_ >reqID, < _string_ >linkPath, < _string_ >targetPath)
165
+
166
+ Respond using:
167
+
168
+ * `status()` - Use this to indicate success/failure of the symlink creation.
169
+
170
+
171
+ Useful standalone data structures
172
+ ---------------------------------
173
+
174
+ * **STATUS_CODE** - _object_ - Contains the various status codes (for use especially with `status()`):
175
+
176
+ * `OK`
177
+
178
+ * `EOF`
179
+
180
+ * `NO_SUCH_FILE`
181
+
182
+ * `PERMISSION_DENIED`
183
+
184
+ * `FAILURE`
185
+
186
+ * `BAD_MESSAGE`
187
+
188
+ * `OP_UNSUPPORTED`
189
+
190
+ * **OPEN_MODE** - _object_ - Contains the various open file flags:
191
+
192
+ * `READ`
193
+
194
+ * `WRITE`
195
+
196
+ * `APPEND`
197
+
198
+ * `CREAT`
199
+
200
+ * `TRUNC`
201
+
202
+ * `EXCL`
203
+
204
+
205
+ Useful standalone methods
206
+ -------------------------
207
+
208
+ * **stringToFlags**(< _string_ >flagsStr) - _integer_ - Converts string flags (e.g. `'r'`, `'a+'`, etc.) to the appropriate `OPEN_MODE` flag mask. Returns `null` if conversion failed.
209
+
210
+ * **flagsToString**(< _integer_ >flagsMask) - _string_ - Converts flag mask (e.g. number containing `OPEN_MODE` values) to the appropriate string value. Returns `null` if conversion failed.
211
+
212
+
213
+ SFTP methods
214
+ ------------
215
+
216
+ * **(constructor)**(< _object_ >config[, < _string_ >remoteIdentRaw]) - Creates and returns a new SFTP instance. `remoteIdentRaw` can be the raw SSH identification string of the remote party. This is used to change internal behavior based on particular SFTP implementations. `config` can contain:
217
+
218
+ * **server** - _boolean_ - Set to `true` to create an instance in server mode. **Default:** `false`
219
+
220
+ * **debug** - _function_ - Set this to a function that receives a single string argument to get detailed (local) debug information. **Default:** (none)
221
+
222
+
223
+
224
+ **Client-only methods**
225
+
226
+ * **fastGet**(< _string_ >remotePath, < _string_ >localPath[, < _object_ >options], < _function_ >callback) - _(void)_ - Downloads a file at `remotePath` to `localPath` using parallel reads for faster throughput. `options` can have the following properties:
227
+
228
+ * **concurrency** - _integer_ - Number of concurrent reads **Default:** `64`
229
+
230
+ * **chunkSize** - _integer_ - Size of each read in bytes **Default:** `32768`
231
+
232
+ * **step** - _function_(< _integer_ >total_transferred, < _integer_ >chunk, < _integer_ >total) - Called every time a part of a file was transferred
233
+
234
+ `callback` has 1 parameter: < _Error_ >err.
235
+
236
+ * **fastPut**(< _string_ >localPath, < _string_ >remotePath[, < _object_ >options], < _function_ >callback) - _(void)_ - Uploads a file from `localPath` to `remotePath` using parallel reads for faster throughput. `options` can have the following properties:
237
+
238
+ * **concurrency** - _integer_ - Number of concurrent reads **Default:** `64`
239
+
240
+ * **chunkSize** - _integer_ - Size of each read in bytes **Default:** `32768`
241
+
242
+ * **step** - _function_(< _integer_ >total_transferred, < _integer_ >chunk, < _integer_ >total) - Called every time a part of a file was transferred
243
+
244
+ * **mode** - _mixed_ - Integer or string representing the file mode to set for the uploaded file.
245
+
246
+ `callback` has 1 parameter: < _Error_ >err.
247
+
248
+ * **createReadStream**(< _string_ >path[, < _object_ >options]) - _ReadStream_ - Returns a new readable stream for `path`. `options` has the following defaults:
249
+
250
+ ```javascript
251
+ { flags: 'r',
252
+ encoding: null,
253
+ handle: null,
254
+ mode: 0o666,
255
+ autoClose: true
256
+ }
257
+ ```
258
+
259
+ `options` can include `start` and `end` values to read a range of bytes from the file instead of the entire file. Both `start` and `end` are inclusive and start at 0. The `encoding` can be `'utf8'`, `'ascii'`, or `'base64'`.
260
+
261
+ If `autoClose` is false, then the file handle won't be closed, even if there's an error. It is your responsibility to close it and make sure there's no file handle leak. If `autoClose` is set to true (default behavior), on `error` or `end` the file handle will be closed automatically.
262
+
263
+ An example to read the last 10 bytes of a file which is 100 bytes long:
264
+
265
+ ```javascript
266
+ sftp.createReadStream('sample.txt', {start: 90, end: 99});
267
+ ```
268
+
269
+ * **createWriteStream**(< _string_ >path[, < _object_ >options]) - _WriteStream_ - Returns a new writable stream for `path`. `options` has the following defaults:
270
+
271
+ ```javascript
272
+ {
273
+ flags: 'w',
274
+ encoding: null,
275
+ mode: 0o666,
276
+ autoClose: true
277
+ }
278
+ ```
279
+
280
+ `options` may also include a `start` option to allow writing data at some position past the beginning of the file. Modifying a file rather than replacing it may require a flags mode of 'r+' rather than the default mode 'w'.
281
+
282
+ If 'autoClose' is set to false and you pipe to this stream, this stream will not automatically close after there is no more data upstream -- allowing future pipes and/or manual writes.
283
+
284
+ * **open**(< _string_ >filename, < _string_ >flags, [< _mixed_ >attrs_mode, ]< _function_ >callback) - _(void)_ - Opens a file `filename` with `flags` with optional _ATTRS_ object or file mode `attrs_mode`. `flags` is any of the flags supported by `fs.open` (except sync flag). `callback` has 2 parameters: < _Error_ >err, < _Buffer_ >handle.
285
+
286
+ * **close**(< _Buffer_ >handle, < _function_ >callback) - _(void)_ - Closes the resource associated with `handle` given by open() or opendir(). `callback` has 1 parameter: < _Error_ >err.
287
+
288
+ * **read**(< _Buffer_ >handle, < _Buffer_ >buffer, < _integer_ >offset, < _integer_ >length, < _integer_ >position, < _function_ >callback) - _(void)_ - Reads `length` bytes from the resource associated with `handle` starting at `position` and stores the bytes in `buffer` starting at `offset`. `callback` has 4 parameters: < _Error_ >err, < _integer_ >bytesRead, < _Buffer_ >buffer (offset adjusted), < _integer_ >position.
289
+
290
+ * **write**(< _Buffer_ >handle, < _Buffer_ >buffer, < _integer_ >offset, < _integer_ >length, < _integer_ >position, < _function_ >callback) - _(void)_ - Writes `length` bytes from `buffer` starting at `offset` to the resource associated with `handle` starting at `position`. `callback` has 1 parameter: < _Error_ >err.
291
+
292
+ * **fstat**(< _Buffer_ >handle, < _function_ >callback) - _(void)_ - Retrieves attributes for the resource associated with `handle`. `callback` has 2 parameters: < _Error_ >err, < _Stats_ >stats.
293
+
294
+ * **fsetstat**(< _Buffer_ >handle, < _ATTRS_ >attributes, < _function_ >callback) - _(void)_ - Sets the attributes defined in `attributes` for the resource associated with `handle`. `callback` has 1 parameter: < _Error_ >err.
295
+
296
+ * **futimes**(< _Buffer_ >handle, < _mixed_ >atime, < _mixed_ >mtime, < _function_ >callback) - _(void)_ - Sets the access time and modified time for the resource associated with `handle`. `atime` and `mtime` can be Date instances or UNIX timestamps. `callback` has 1 parameter: < _Error_ >err.
297
+
298
+ * **fchown**(< _Buffer_ >handle, < _integer_ >uid, < _integer_ >gid, < _function_ >callback) - _(void)_ - Sets the owner for the resource associated with `handle`. `callback` has 1 parameter: < _Error_ >err.
299
+
300
+ * **fchmod**(< _Buffer_ >handle, < _mixed_ >mode, < _function_ >callback) - _(void)_ - Sets the mode for the resource associated with `handle`. `mode` can be an integer or a string containing an octal number. `callback` has 1 parameter: < _Error_ >err.
301
+
302
+ * **opendir**(< _string_ >path, < _function_ >callback) - _(void)_ - Opens a directory `path`. `callback` has 2 parameters: < _Error_ >err, < _Buffer_ >handle.
303
+
304
+ * **readdir**(< _mixed_ >location, < _function_ >callback) - _(void)_ - Retrieves a directory listing. `location` can either be a _Buffer_ containing a valid directory handle from opendir() or a _string_ containing the path to a directory. `callback` has 2 parameters: < _Error_ >err, < _mixed_ >list. `list` is an _Array_ of `{ filename: 'foo', longname: '....', attrs: {...} }` style objects (attrs is of type _ATTR_). If `location` is a directory handle, this function may need to be called multiple times until `list` is boolean false, which indicates that no more directory entries are available for that directory handle.
305
+
306
+ * **unlink**(< _string_ >path, < _function_ >callback) - _(void)_ - Removes the file/symlink at `path`. `callback` has 1 parameter: < _Error_ >err.
307
+
308
+ * **rename**(< _string_ >srcPath, < _string_ >destPath, < _function_ >callback) - _(void)_ - Renames/moves `srcPath` to `destPath`. `callback` has 1 parameter: < _Error_ >err.
309
+
310
+ * **mkdir**(< _string_ >path, [< _ATTRS_ >attributes, ]< _function_ >callback) - _(void)_ - Creates a new directory `path`. `callback` has 1 parameter: < _Error_ >err.
311
+
312
+ * **rmdir**(< _string_ >path, < _function_ >callback) - _(void)_ - Removes the directory at `path`. `callback` has 1 parameter: < _Error_ >err.
313
+
314
+ * **stat**(< _string_ >path, < _function_ >callback) - _(void)_ - Retrieves attributes for `path`. `callback` has 2 parameter: < _Error_ >err, < _Stats_ >stats.
315
+
316
+ * **lstat**(< _string_ >path, < _function_ >callback) - _(void)_ - Retrieves attributes for `path`. If `path` is a symlink, the link itself is stat'ed instead of the resource it refers to. `callback` has 2 parameters: < _Error_ >err, < _Stats_ >stats.
317
+
318
+ * **setstat**(< _string_ >path, < _ATTRS_ >attributes, < _function_ >callback) - _(void)_ - Sets the attributes defined in `attributes` for `path`. `callback` has 1 parameter: < _Error_ >err.
319
+
320
+ * **utimes**(< _string_ >path, < _mixed_ >atime, < _mixed_ >mtime, < _function_ >callback) - _(void)_ - Sets the access time and modified time for `path`. `atime` and `mtime` can be Date instances or UNIX timestamps. `callback` has 1 parameter: < _Error_ >err.
321
+
322
+ * **chown**(< _string_ >path, < _integer_ >uid, < _integer_ >gid, < _function_ >callback) - _(void)_ - Sets the owner for `path`. `callback` has 1 parameter: < _Error_ >err.
323
+
324
+ * **chmod**(< _string_ >path, < _mixed_ >mode, < _function_ >callback) - _(void)_ - Sets the mode for `path`. `mode` can be an integer or a string containing an octal number. `callback` has 1 parameter: < _Error_ >err.
325
+
326
+ * **readlink**(< _string_ >path, < _function_ >callback) - _(void)_ - Retrieves the target for a symlink at `path`. `callback` has 2 parameters: < _Error_ >err, < _string_ >target.
327
+
328
+ * **symlink**(< _string_ >targetPath, < _string_ >linkPath, < _function_ >callback) - _(void)_ - Creates a symlink at `linkPath` to `targetPath`. `callback` has 1 parameter: < _Error_ >err.
329
+
330
+ * **realpath**(< _string_ >path, < _function_ >callback) - _(void)_ - Resolves `path` to an absolute path. `callback` has 2 parameters: < _Error_ >err, < _string_ >absPath.
331
+
332
+ * **ext_openssh_rename**(< _string_ >srcPath, < _string_ >destPath, < _function_ >callback) - _(void)_ - **OpenSSH extension** Performs POSIX rename(3) from `srcPath` to `destPath`. `callback` has 1 parameter: < _Error_ >err.
333
+
334
+ * **ext_openssh_statvfs**(< _string_ >path, < _function_ >callback) - _(void)_ - **OpenSSH extension** Performs POSIX statvfs(2) on `path`. `callback` has 2 parameters: < _Error_ >err, < _object_ >fsInfo. `fsInfo` contains the information as found in the [statvfs struct](http://linux.die.net/man/2/statvfs).
335
+
336
+ * **ext_openssh_fstatvfs**(< _Buffer_ >handle, < _function_ >callback) - _(void)_ - **OpenSSH extension** Performs POSIX fstatvfs(2) on open handle `handle`. `callback` has 2 parameters: < _Error_ >err, < _object_ >fsInfo. `fsInfo` contains the information as found in the [statvfs struct](http://linux.die.net/man/2/statvfs).
337
+
338
+ * **ext_openssh_hardlink**(< _string_ >targetPath, < _string_ >linkPath, < _function_ >callback) - _(void)_ - **OpenSSH extension** Performs POSIX link(2) to create a hard link to `targetPath` at `linkPath`. `callback` has 1 parameter: < _Error_ >err.
339
+
340
+ * **ext_openssh_fsync**(< _Buffer_ >handle, < _function_ >callback) - _(void)_ - **OpenSSH extension** Performs POSIX fsync(3) on the open handle `handle`. `callback` has 1 parameter: < _Error_ >err.
341
+
342
+ * **ext_openssh_lsetstat**(< _string_ >path, < _ATTRS_ >attributes, < _function_ >callback) - _(void)_ - **OpenSSH extension** Similar to `setstat()`, but instead sets attributes on symlinks. `callback` has 1 parameter: < _Error_ >err.
343
+
344
+ * **ext_openssh_expandPath**(< _string_ >path, < _function_ >callback) - _(void)_ - **OpenSSH extension** Similar to `realpath()`, but supports tilde-expansion, i.e. "\~", "\~/..." and "\~user/...". These paths are expanded using shell-like rules. `callback` has 2 parameters: < _Error_ >err, < _string_ >expandedPath.
345
+
346
+ * **ext_copy_data**(< _Buffer_ >srcHandle, < _number_ >srcOffset, < _number_ >length, < _Buffer_ >dstHandle, < _number_ >dstOffset, < _function_ >callback) - _(void)_ - Performs a remote file copy. If `length` is 0, then the server will read from `srcHandle` until EOF is reached. `callback` has 1 parameter: < _Error_ >err.
347
+
348
+ * **ext_home_dir**(< _string_ >username, < _function_ >callback) - _(void)_ - Retrieves the home directory of the user identified by `username`. Use an empty string to refer to the current user. `callback` has 2 parameters: < _Error_ >err, < _string_ >homeDirectory.
349
+
350
+ * **ext_users_groups**(< _array_ >uids, < _array_ >gids, < _function_ >callback) - _(void)_ - Retrieves the user names and group names associated with the user IDs in `uids` and group IDs in `gids` respectively. Either array can be empty or contain one or more 32-bit unsigned integers. The retrieved user names and group names match the same order as the IDs in `uids` and `gids` respectively. If the server was unable to find a name for a given ID, it will use an empty string. `callback` has 3 parameters: < _Error_ >err, < _array_ >userNames, < _array_ >groupNames.
351
+
352
+
353
+ **Server-only methods**
354
+
355
+ * **status**(< _integer_ >reqID, < _integer_ >statusCode[, < _string_ >message]) - _(void)_ - Sends a status response for the request identified by `id`.
356
+
357
+ * **handle**(< _integer_ >reqID, < _Buffer_ >handle) - _(void)_ - Sends a handle response for the request identified by `id`. `handle` must be less than 256 bytes and is an opaque value that could merely contain the value of a backing file descriptor or some other unique, custom value.
358
+
359
+ * **data**(< _integer_ >reqID, < _mixed_ >data[, < _string_ >encoding]) - _(void)_ - Sends a data response for the request identified by `id`. `data` can be a _Buffer_ or _string_. If `data` is a string, `encoding` is the encoding of `data`.
360
+
361
+ * **name**(< _integer_ >reqID, < _array_ >names) - _(void)_ - Sends a name response for the request identified by `id`. `names` must be an _array_ of _object_ where each _object_ can contain:
362
+
363
+ * **filename** - _string_ - The entry's name.
364
+
365
+ * **longname** - _string_ - This is the `ls -l`-style format for the entry (e.g. `-rwxr--r-- 1 bar bar 718 Dec 8 2009 foo`)
366
+
367
+ * **attrs** - _ATTRS_ - This is an optional _ATTRS_ object that contains requested/available attributes for the entry.
368
+
369
+ * **attrs**(< _integer_ >reqID, < _ATTRS_ >attrs) - _(void)_ - Sends an attrs response for the request identified by `id`. `attrs` contains the requested/available attributes.
370
+
371
+
372
+ ATTRS
373
+ -----
374
+
375
+ An object with the following valid properties:
376
+
377
+ * **mode** - _integer_ - Mode/permissions for the resource.
378
+
379
+ * **uid** - _integer_ - User ID of the resource.
380
+
381
+ * **gid** - _integer_ - Group ID of the resource.
382
+
383
+ * **size** - _integer_ - Resource size in bytes.
384
+
385
+ * **atime** - _integer_ - UNIX timestamp of the access time of the resource.
386
+
387
+ * **mtime** - _integer_ - UNIX timestamp of the modified time of the resource.
388
+
389
+ When supplying an ATTRS object to one of the SFTP methods:
390
+
391
+ * `atime` and `mtime` can be either a Date instance or a UNIX timestamp.
392
+
393
+ * `mode` can either be an integer or a string containing an octal number.
394
+
395
+
396
+ Stats
397
+ -----
398
+
399
+ An object with the same attributes as an ATTRS object with the addition of the following methods:
400
+
401
+ * `stats.isDirectory()`
402
+
403
+ * `stats.isFile()`
404
+
405
+ * `stats.isBlockDevice()`
406
+
407
+ * `stats.isCharacterDevice()`
408
+
409
+ * `stats.isSymbolicLink()`
410
+
411
+ * `stats.isFIFO()`
412
+
413
+ * `stats.isSocket()`
@@ -0,0 +1,238 @@
1
+ // **BEFORE RUNNING THIS SCRIPT:**
2
+ // 1. The server portion is best run on non-Windows systems because they have
3
+ // terminfo databases which are needed to properly work with different
4
+ // terminal types of client connections
5
+ // 2. Install `blessed`: `npm install blessed`
6
+ // 3. Create a server host key in this same directory and name it `host.key`
7
+ 'use strict';
8
+
9
+ const { readFileSync } = require('fs');
10
+
11
+ const blessed = require('blessed');
12
+ const { Server } = require('ssh2');
13
+
14
+ const RE_SPECIAL =
15
+ // eslint-disable-next-line no-control-regex
16
+ /[\x00-\x1F\x7F]+|(?:\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K])/g;
17
+ const MAX_MSG_LEN = 128;
18
+ const MAX_NAME_LEN = 10;
19
+ const PROMPT_NAME = `Enter a nickname to use (max ${MAX_NAME_LEN} chars): `;
20
+
21
+ const users = [];
22
+
23
+ function formatMessage(msg, output) {
24
+ output.parseTags = true;
25
+ msg = output._parseTags(msg);
26
+ output.parseTags = false;
27
+ return msg;
28
+ }
29
+
30
+ function userBroadcast(msg, source) {
31
+ const sourceMsg = `> ${msg}`;
32
+ const name = `{cyan-fg}{bold}${source.name}{/}`;
33
+ msg = `: ${msg}`;
34
+ for (const user of users) {
35
+ const output = user.output;
36
+ if (source === user)
37
+ output.add(sourceMsg);
38
+ else
39
+ output.add(formatMessage(name, output) + msg);
40
+ }
41
+ }
42
+
43
+ function localMessage(msg, source) {
44
+ const output = source.output;
45
+ output.add(formatMessage(msg, output));
46
+ }
47
+
48
+ function noop(v) {}
49
+
50
+ new Server({
51
+ hostKeys: [readFileSync('host.key')],
52
+ }, (client) => {
53
+ let stream;
54
+ let name;
55
+
56
+ client.on('authentication', (ctx) => {
57
+ let nick = ctx.username;
58
+ let prompt = PROMPT_NAME;
59
+ let lowered;
60
+
61
+ // Try to use username as nickname
62
+ if (nick.length > 0 && nick.length <= MAX_NAME_LEN) {
63
+ lowered = nick.toLowerCase();
64
+ let ok = true;
65
+ for (const user of users) {
66
+ if (user.name.toLowerCase() === lowered) {
67
+ ok = false;
68
+ prompt = `That nickname is already in use.\n${PROMPT_NAME}`;
69
+ break;
70
+ }
71
+ }
72
+ if (ok) {
73
+ name = nick;
74
+ return ctx.accept();
75
+ }
76
+ } else if (nick.length === 0) {
77
+ prompt = 'A nickname is required.\n' + PROMPT_NAME;
78
+ } else {
79
+ prompt = 'That nickname is too long.\n' + PROMPT_NAME;
80
+ }
81
+
82
+ if (ctx.method !== 'keyboard-interactive')
83
+ return ctx.reject(['keyboard-interactive']);
84
+
85
+ ctx.prompt(prompt, function retryPrompt(answers) {
86
+ if (answers.length === 0)
87
+ return ctx.reject(['keyboard-interactive']);
88
+ nick = answers[0];
89
+ if (nick.length > MAX_NAME_LEN) {
90
+ return ctx.prompt(`That nickname is too long.\n${PROMPT_NAME}`,
91
+ retryPrompt);
92
+ } else if (nick.length === 0) {
93
+ return ctx.prompt(`A nickname is required.\n${PROMPT_NAME}`,
94
+ retryPrompt);
95
+ }
96
+ lowered = nick.toLowerCase();
97
+ for (const user of users) {
98
+ if (user.name.toLowerCase() === lowered) {
99
+ return ctx.prompt(`That nickname is already in use.\n${PROMPT_NAME}`,
100
+ retryPrompt);
101
+ }
102
+ }
103
+ name = nick;
104
+ ctx.accept();
105
+ });
106
+ }).on('ready', () => {
107
+ let rows;
108
+ let cols;
109
+ let term;
110
+ client.once('session', (accept, reject) => {
111
+ accept().once('pty', (accept, reject, info) => {
112
+ rows = info.rows;
113
+ cols = info.cols;
114
+ term = info.term;
115
+ accept && accept();
116
+ }).on('window-change', (accept, reject, info) => {
117
+ rows = info.rows;
118
+ cols = info.cols;
119
+ if (stream) {
120
+ stream.rows = rows;
121
+ stream.columns = cols;
122
+ stream.emit('resize');
123
+ }
124
+ accept && accept();
125
+ }).once('shell', (accept, reject) => {
126
+ stream = accept();
127
+ users.push(stream);
128
+
129
+ stream.name = name;
130
+ stream.rows = rows || 24;
131
+ stream.columns = cols || 80;
132
+ stream.isTTY = true;
133
+ stream.setRawMode = noop;
134
+ stream.on('error', noop);
135
+
136
+ const screen = new blessed.screen({
137
+ autoPadding: true,
138
+ smartCSR: true,
139
+ program: new blessed.program({
140
+ input: stream,
141
+ output: stream
142
+ }),
143
+ terminal: term || 'ansi'
144
+ });
145
+
146
+ screen.title = 'SSH Chatting as ' + name;
147
+ // Disable local echo
148
+ screen.program.attr('invisible', true);
149
+
150
+ const output = stream.output = new blessed.log({
151
+ screen: screen,
152
+ top: 0,
153
+ left: 0,
154
+ width: '100%',
155
+ bottom: 2,
156
+ scrollOnInput: true
157
+ });
158
+ screen.append(output);
159
+
160
+ screen.append(new blessed.box({
161
+ screen: screen,
162
+ height: 1,
163
+ bottom: 1,
164
+ left: 0,
165
+ width: '100%',
166
+ type: 'line',
167
+ ch: '='
168
+ }));
169
+
170
+ const input = new blessed.textbox({
171
+ screen: screen,
172
+ bottom: 0,
173
+ height: 1,
174
+ width: '100%',
175
+ inputOnFocus: true
176
+ });
177
+ screen.append(input);
178
+
179
+ input.focus();
180
+
181
+ // Local greetings
182
+ localMessage('{blue-bg}{white-fg}{bold}Welcome to SSH Chat!{/}\n'
183
+ + 'There are {bold}'
184
+ + (users.length - 1)
185
+ + '{/} other user(s) connected.\n'
186
+ + 'Type /quit or /exit to exit the chat.',
187
+ stream);
188
+
189
+ // Let everyone else know that this user just joined
190
+ for (const user of users) {
191
+ const output = user.output;
192
+ if (user === stream)
193
+ continue;
194
+ output.add(formatMessage('{green-fg}*** {bold}', output)
195
+ + name
196
+ + formatMessage('{/bold} has joined the chat{/}', output));
197
+ }
198
+
199
+ screen.render();
200
+ // XXX This fake resize event is needed for some terminals in order to
201
+ // have everything display correctly
202
+ screen.program.emit('resize');
203
+
204
+ // Read a line of input from the user
205
+ input.on('submit', (line) => {
206
+ input.clearValue();
207
+ screen.render();
208
+ if (!input.focused)
209
+ input.focus();
210
+ line = line.replace(RE_SPECIAL, '').trim();
211
+ if (line.length > MAX_MSG_LEN)
212
+ line = line.substring(0, MAX_MSG_LEN);
213
+ if (line.length > 0) {
214
+ if (line === '/quit' || line === '/exit')
215
+ stream.end();
216
+ else
217
+ userBroadcast(line, stream);
218
+ }
219
+ });
220
+ });
221
+ });
222
+ }).on('close', () => {
223
+ if (stream !== undefined) {
224
+ users.splice(users.indexOf(stream), 1);
225
+ // Let everyone else know that this user just left
226
+ for (const user of users) {
227
+ const output = user.output;
228
+ output.add(formatMessage('{magenta-fg}*** {bold}', output)
229
+ + name
230
+ + formatMessage('{/bold} has left the chat{/}', output));
231
+ }
232
+ }
233
+ }).on('error', (err) => {
234
+ // Ignore errors
235
+ });
236
+ }).listen(0, function() {
237
+ console.log('Listening on port ' + this.address().port);
238
+ });