dsh-remote 0.8.46 → 0.8.47

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 (391) hide show
  1. package/LICENSE +21 -21
  2. package/README.en.md +361 -361
  3. package/README.md +368 -368
  4. package/cordis.patch.yml +9 -9
  5. package/lib/binding.js +172 -172
  6. package/lib/client.js +3637 -3637
  7. package/lib/credential.js +177 -177
  8. package/lib/deploy-tasks.js +142 -142
  9. package/lib/errors.js +87 -87
  10. package/lib/file-reference.js +457 -457
  11. package/lib/forwards.js +258 -258
  12. package/lib/hostkey.js +108 -108
  13. package/lib/http-transport.js +196 -196
  14. package/lib/ignore.js +156 -156
  15. package/lib/index.js +3771 -3747
  16. package/lib/openssh.js +838 -838
  17. package/lib/paths.js +225 -225
  18. package/lib/pool.js +757 -757
  19. package/lib/registry.js +95 -95
  20. package/lib/remote-fs.js +148 -143
  21. package/lib/routes-fs.js +233 -233
  22. package/lib/search.js +230 -230
  23. package/lib/sftp-surface.js +76 -76
  24. package/lib/sshconfig.js +454 -454
  25. package/lib/sync.js +275 -275
  26. package/lib/tasks.js +95 -95
  27. package/lib/telemetry.js +213 -213
  28. package/lib/update.js +472 -472
  29. package/lib/web-attach.js +850 -850
  30. package/lib/web-deploy-skill.js +205 -205
  31. package/lib/web-deploy.js +694 -694
  32. package/node_modules/asn1/Jenkinsfile +65 -0
  33. package/node_modules/asn1/LICENSE +19 -0
  34. package/node_modules/asn1/README.md +50 -0
  35. package/node_modules/asn1/lib/ber/errors.js +13 -0
  36. package/node_modules/asn1/lib/ber/index.js +27 -0
  37. package/node_modules/asn1/lib/ber/reader.js +262 -0
  38. package/node_modules/asn1/lib/ber/types.js +36 -0
  39. package/node_modules/asn1/lib/ber/writer.js +317 -0
  40. package/node_modules/asn1/lib/index.js +20 -0
  41. package/node_modules/asn1/package.json +31 -0
  42. package/node_modules/bcrypt-pbkdf/CONTRIBUTING.md +13 -0
  43. package/node_modules/bcrypt-pbkdf/LICENSE +66 -0
  44. package/node_modules/bcrypt-pbkdf/README.md +45 -0
  45. package/node_modules/bcrypt-pbkdf/index.js +556 -0
  46. package/node_modules/bcrypt-pbkdf/package.json +15 -0
  47. package/node_modules/buildcheck/.eslintrc.js +5 -0
  48. package/node_modules/buildcheck/.github/workflows/ci.yml +88 -0
  49. package/node_modules/buildcheck/.github/workflows/lint.yml +27 -0
  50. package/node_modules/buildcheck/.npmignore +3 -0
  51. package/node_modules/buildcheck/LICENSE +19 -0
  52. package/node_modules/buildcheck/README.md +106 -0
  53. package/node_modules/buildcheck/deps/Find-VisualStudio.cs +250 -0
  54. package/node_modules/buildcheck/lib/findvs.js +361 -0
  55. package/node_modules/buildcheck/lib/index.js +738 -0
  56. package/node_modules/buildcheck/package.json +36 -0
  57. package/node_modules/buildcheck/test/test.js +8 -0
  58. package/node_modules/cpu-features/.eslintrc.js +5 -0
  59. package/node_modules/cpu-features/.github/workflows/ci.yml +74 -0
  60. package/node_modules/cpu-features/.github/workflows/lint.yml +27 -0
  61. package/node_modules/cpu-features/LICENSE +19 -0
  62. package/node_modules/cpu-features/README.md +59 -0
  63. package/node_modules/cpu-features/binding.gyp +16 -0
  64. package/node_modules/cpu-features/buildcheck.js +32 -0
  65. package/node_modules/cpu-features/deps/cpu_features/.clang-format +4 -0
  66. package/node_modules/cpu-features/deps/cpu_features/.dockerignore +31 -0
  67. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/Dockerfile +5 -0
  68. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/aarch64_linux_cmake.yml +30 -0
  69. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/amd64_freebsd_cmake.yml +22 -0
  70. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/amd64_linux_bazel.yml +26 -0
  71. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/amd64_linux_cmake.yml +31 -0
  72. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/amd64_macos_cmake.yml +43 -0
  73. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/amd64_windows_cmake.yml +25 -0
  74. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/arm_linux_cmake.yml +31 -0
  75. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/clang_format.yml +24 -0
  76. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/mips_linux_cmake.yml +30 -0
  77. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/power_linux_cmake.yml +29 -0
  78. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/riscv_linux_cmake.yml +28 -0
  79. package/node_modules/cpu-features/deps/cpu_features/.github/workflows/s390x_linux_cmake.yml +27 -0
  80. package/node_modules/cpu-features/deps/cpu_features/.grenrc.yml +21 -0
  81. package/node_modules/cpu-features/deps/cpu_features/BUILD.bazel +329 -0
  82. package/node_modules/cpu-features/deps/cpu_features/CMakeLists.txt +261 -0
  83. package/node_modules/cpu-features/deps/cpu_features/CONTRIBUTING.md +23 -0
  84. package/node_modules/cpu-features/deps/cpu_features/LICENSE +230 -0
  85. package/node_modules/cpu-features/deps/cpu_features/README.md +272 -0
  86. package/node_modules/cpu-features/deps/cpu_features/WORKSPACE +19 -0
  87. package/node_modules/cpu-features/deps/cpu_features/bazel/ci/README.md +5 -0
  88. package/node_modules/cpu-features/deps/cpu_features/bazel/platforms.bzl +11 -0
  89. package/node_modules/cpu-features/deps/cpu_features/cmake/CpuFeaturesConfig.cmake.in +3 -0
  90. package/node_modules/cpu-features/deps/cpu_features/cmake/CpuFeaturesNdkCompatConfig.cmake.in +3 -0
  91. package/node_modules/cpu-features/deps/cpu_features/cmake/README.md +30 -0
  92. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/Makefile +252 -0
  93. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/README.md +40 -0
  94. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/doc/docker.dot +64 -0
  95. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/doc/docker.svg +312 -0
  96. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/doc/generate_image.sh +7 -0
  97. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/docker/amd64/Dockerfile +48 -0
  98. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/docker/toolchain/Dockerfile +34 -0
  99. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/sample/CMakeLists.txt +22 -0
  100. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/sample/main.cpp +11 -0
  101. package/node_modules/cpu-features/deps/cpu_features/cmake/ci/vagrant/freebsd/Vagrantfile +107 -0
  102. package/node_modules/cpu-features/deps/cpu_features/cmake/googletest.CMakeLists.txt.in +15 -0
  103. package/node_modules/cpu-features/deps/cpu_features/cpu_features.gyp +105 -0
  104. package/node_modules/cpu-features/deps/cpu_features/include/cpu_features_cache_info.h +54 -0
  105. package/node_modules/cpu-features/deps/cpu_features/include/cpu_features_macros.h +384 -0
  106. package/node_modules/cpu-features/deps/cpu_features/include/cpuinfo_aarch64.h +259 -0
  107. package/node_modules/cpu-features/deps/cpu_features/include/cpuinfo_arm.h +121 -0
  108. package/node_modules/cpu-features/deps/cpu_features/include/cpuinfo_mips.h +74 -0
  109. package/node_modules/cpu-features/deps/cpu_features/include/cpuinfo_ppc.h +149 -0
  110. package/node_modules/cpu-features/deps/cpu_features/include/cpuinfo_riscv.h +72 -0
  111. package/node_modules/cpu-features/deps/cpu_features/include/cpuinfo_s390x.h +108 -0
  112. package/node_modules/cpu-features/deps/cpu_features/include/cpuinfo_x86.h +288 -0
  113. package/node_modules/cpu-features/deps/cpu_features/include/internal/bit_utils.h +40 -0
  114. package/node_modules/cpu-features/deps/cpu_features/include/internal/cpuid_x86.h +37 -0
  115. package/node_modules/cpu-features/deps/cpu_features/include/internal/filesystem.h +39 -0
  116. package/node_modules/cpu-features/deps/cpu_features/include/internal/hwcaps.h +240 -0
  117. package/node_modules/cpu-features/deps/cpu_features/include/internal/stack_line_reader.h +49 -0
  118. package/node_modules/cpu-features/deps/cpu_features/include/internal/string_view.h +110 -0
  119. package/node_modules/cpu-features/deps/cpu_features/include/internal/windows_utils.h +70 -0
  120. package/node_modules/cpu-features/deps/cpu_features/ndk_compat/CMakeLists.txt +60 -0
  121. package/node_modules/cpu-features/deps/cpu_features/ndk_compat/README.md +4 -0
  122. package/node_modules/cpu-features/deps/cpu_features/ndk_compat/cpu-features.c +205 -0
  123. package/node_modules/cpu-features/deps/cpu_features/ndk_compat/cpu-features.h +320 -0
  124. package/node_modules/cpu-features/deps/cpu_features/ndk_compat/ndk-compat-test.c +12 -0
  125. package/node_modules/cpu-features/deps/cpu_features/patches/0001-Add-Apple-Silicon-Support.patch +456 -0
  126. package/node_modules/cpu-features/deps/cpu_features/scripts/generate_badges.d +165 -0
  127. package/node_modules/cpu-features/deps/cpu_features/scripts/make_release.sh +75 -0
  128. package/node_modules/cpu-features/deps/cpu_features/scripts/run_integration.sh +490 -0
  129. package/node_modules/cpu-features/deps/cpu_features/scripts/test_integration.sh +79 -0
  130. package/node_modules/cpu-features/deps/cpu_features/src/copy.inl +19 -0
  131. package/node_modules/cpu-features/deps/cpu_features/src/define_introspection.inl +86 -0
  132. package/node_modules/cpu-features/deps/cpu_features/src/define_introspection_and_hwcaps.inl +26 -0
  133. package/node_modules/cpu-features/deps/cpu_features/src/equals.inl +22 -0
  134. package/node_modules/cpu-features/deps/cpu_features/src/filesystem.c +62 -0
  135. package/node_modules/cpu-features/deps/cpu_features/src/hwcaps.c +169 -0
  136. package/node_modules/cpu-features/deps/cpu_features/src/impl_aarch64__base_implementation.inl +88 -0
  137. package/node_modules/cpu-features/deps/cpu_features/src/impl_aarch64_linux_or_android.c +79 -0
  138. package/node_modules/cpu-features/deps/cpu_features/src/impl_aarch64_macos_or_iphone.c +82 -0
  139. package/node_modules/cpu-features/deps/cpu_features/src/impl_aarch64_windows.c +138 -0
  140. package/node_modules/cpu-features/deps/cpu_features/src/impl_arm_linux_or_android.c +212 -0
  141. package/node_modules/cpu-features/deps/cpu_features/src/impl_mips_linux_or_android.c +93 -0
  142. package/node_modules/cpu-features/deps/cpu_features/src/impl_ppc_linux.c +163 -0
  143. package/node_modules/cpu-features/deps/cpu_features/src/impl_riscv_linux.c +111 -0
  144. package/node_modules/cpu-features/deps/cpu_features/src/impl_s390x_linux.c +120 -0
  145. package/node_modules/cpu-features/deps/cpu_features/src/impl_x86__base_implementation.inl +2055 -0
  146. package/node_modules/cpu-features/deps/cpu_features/src/impl_x86_freebsd.c +68 -0
  147. package/node_modules/cpu-features/deps/cpu_features/src/impl_x86_linux_or_android.c +58 -0
  148. package/node_modules/cpu-features/deps/cpu_features/src/impl_x86_macos.c +57 -0
  149. package/node_modules/cpu-features/deps/cpu_features/src/impl_x86_windows.c +58 -0
  150. package/node_modules/cpu-features/deps/cpu_features/src/stack_line_reader.c +132 -0
  151. package/node_modules/cpu-features/deps/cpu_features/src/string_view.c +192 -0
  152. package/node_modules/cpu-features/deps/cpu_features/src/utils/list_cpu_features.c +461 -0
  153. package/node_modules/cpu-features/deps/cpu_features/test/CMakeLists.txt +114 -0
  154. package/node_modules/cpu-features/deps/cpu_features/test/bit_utils_test.cc +53 -0
  155. package/node_modules/cpu-features/deps/cpu_features/test/cpuinfo_aarch64_test.cc +396 -0
  156. package/node_modules/cpu-features/deps/cpu_features/test/cpuinfo_arm_test.cc +384 -0
  157. package/node_modules/cpu-features/deps/cpu_features/test/cpuinfo_mips_test.cc +176 -0
  158. package/node_modules/cpu-features/deps/cpu_features/test/cpuinfo_ppc_test.cc +131 -0
  159. package/node_modules/cpu-features/deps/cpu_features/test/cpuinfo_riscv_test.cc +180 -0
  160. package/node_modules/cpu-features/deps/cpu_features/test/cpuinfo_s390x_test.cc +82 -0
  161. package/node_modules/cpu-features/deps/cpu_features/test/cpuinfo_x86_test.cc +1729 -0
  162. package/node_modules/cpu-features/deps/cpu_features/test/filesystem_for_testing.cc +103 -0
  163. package/node_modules/cpu-features/deps/cpu_features/test/filesystem_for_testing.h +61 -0
  164. package/node_modules/cpu-features/deps/cpu_features/test/hwcaps_for_testing.cc +52 -0
  165. package/node_modules/cpu-features/deps/cpu_features/test/hwcaps_for_testing.h +31 -0
  166. package/node_modules/cpu-features/deps/cpu_features/test/stack_line_reader_test.cc +132 -0
  167. package/node_modules/cpu-features/deps/cpu_features/test/string_view_test.cc +202 -0
  168. package/node_modules/cpu-features/lib/index.js +5 -0
  169. package/node_modules/cpu-features/package.json +40 -0
  170. package/node_modules/cpu-features/src/binding.cc +151 -0
  171. package/node_modules/cpu-features/test/test.js +12 -0
  172. package/node_modules/nan/.github/workflows/ci.yml +46 -0
  173. package/node_modules/nan/.pre-commit-config.yaml +8 -0
  174. package/node_modules/nan/CHANGELOG.md +605 -0
  175. package/node_modules/nan/CMakeLists.txt +138 -0
  176. package/node_modules/nan/LICENSE.md +9 -0
  177. package/node_modules/nan/README.md +457 -0
  178. package/node_modules/nan/doc/asyncworker.md +146 -0
  179. package/node_modules/nan/doc/buffers.md +54 -0
  180. package/node_modules/nan/doc/callback.md +76 -0
  181. package/node_modules/nan/doc/converters.md +41 -0
  182. package/node_modules/nan/doc/errors.md +226 -0
  183. package/node_modules/nan/doc/json.md +62 -0
  184. package/node_modules/nan/doc/maybe_types.md +583 -0
  185. package/node_modules/nan/doc/methods.md +689 -0
  186. package/node_modules/nan/doc/new.md +147 -0
  187. package/node_modules/nan/doc/node_misc.md +123 -0
  188. package/node_modules/nan/doc/object_wrappers.md +263 -0
  189. package/node_modules/nan/doc/persistent.md +296 -0
  190. package/node_modules/nan/doc/scopes.md +73 -0
  191. package/node_modules/nan/doc/script.md +58 -0
  192. package/node_modules/nan/doc/string_bytes.md +81 -0
  193. package/node_modules/nan/doc/v8_internals.md +211 -0
  194. package/node_modules/nan/doc/v8_misc.md +85 -0
  195. package/node_modules/nan/include_dirs.js +1 -0
  196. package/node_modules/nan/nan.h +3202 -0
  197. package/node_modules/nan/nan_callbacks.h +141 -0
  198. package/node_modules/nan/nan_callbacks_12_inl.h +730 -0
  199. package/node_modules/nan/nan_callbacks_pre_12_inl.h +528 -0
  200. package/node_modules/nan/nan_converters.h +72 -0
  201. package/node_modules/nan/nan_converters_43_inl.h +68 -0
  202. package/node_modules/nan/nan_converters_pre_43_inl.h +42 -0
  203. package/node_modules/nan/nan_define_own_property_helper.h +29 -0
  204. package/node_modules/nan/nan_implementation_12_inl.h +446 -0
  205. package/node_modules/nan/nan_implementation_pre_12_inl.h +263 -0
  206. package/node_modules/nan/nan_json.h +166 -0
  207. package/node_modules/nan/nan_maybe_43_inl.h +360 -0
  208. package/node_modules/nan/nan_maybe_pre_43_inl.h +268 -0
  209. package/node_modules/nan/nan_new.h +340 -0
  210. package/node_modules/nan/nan_object_wrap.h +156 -0
  211. package/node_modules/nan/nan_persistent_12_inl.h +132 -0
  212. package/node_modules/nan/nan_persistent_pre_12_inl.h +242 -0
  213. package/node_modules/nan/nan_private.h +73 -0
  214. package/node_modules/nan/nan_scriptorigin.h +97 -0
  215. package/node_modules/nan/nan_string_bytes.h +305 -0
  216. package/node_modules/nan/nan_typedarray_contents.h +96 -0
  217. package/node_modules/nan/nan_weak.h +453 -0
  218. package/node_modules/nan/package.json +38 -0
  219. package/node_modules/nan/tools/1to2.js +412 -0
  220. package/node_modules/nan/tools/README.md +14 -0
  221. package/node_modules/nan/tools/package.json +19 -0
  222. package/node_modules/safer-buffer/LICENSE +21 -0
  223. package/node_modules/safer-buffer/Porting-Buffer.md +268 -0
  224. package/node_modules/safer-buffer/Readme.md +156 -0
  225. package/node_modules/safer-buffer/dangerous.js +58 -0
  226. package/node_modules/safer-buffer/package.json +34 -0
  227. package/node_modules/safer-buffer/safer.js +77 -0
  228. package/node_modules/safer-buffer/tests.js +406 -0
  229. package/node_modules/ssh2/.eslintignore +4 -0
  230. package/node_modules/ssh2/.eslintrc.js +5 -0
  231. package/node_modules/ssh2/.github/workflows/ci.yml +110 -0
  232. package/node_modules/ssh2/.github/workflows/lint.yml +27 -0
  233. package/node_modules/ssh2/LICENSE +19 -0
  234. package/node_modules/ssh2/README.md +1529 -0
  235. package/node_modules/ssh2/SFTP.md +413 -0
  236. package/node_modules/ssh2/examples/server-chat.js +238 -0
  237. package/node_modules/ssh2/examples/sftp-server-download-only.js +134 -0
  238. package/node_modules/ssh2/install.js +27 -0
  239. package/node_modules/ssh2/lib/Channel.js +295 -0
  240. package/node_modules/ssh2/lib/agent.js +1123 -0
  241. package/node_modules/ssh2/lib/client.js +2176 -0
  242. package/node_modules/ssh2/lib/http-agents.js +84 -0
  243. package/node_modules/ssh2/lib/index.js +44 -0
  244. package/node_modules/ssh2/lib/keygen.js +582 -0
  245. package/node_modules/ssh2/lib/protocol/Protocol.js +2136 -0
  246. package/node_modules/ssh2/lib/protocol/SFTP.js +4052 -0
  247. package/node_modules/ssh2/lib/protocol/constants.js +356 -0
  248. package/node_modules/ssh2/lib/protocol/crypto/binding.gyp +23 -0
  249. package/node_modules/ssh2/lib/protocol/crypto/poly1305.js +43 -0
  250. package/node_modules/ssh2/lib/protocol/crypto/src/binding.cc +2300 -0
  251. package/node_modules/ssh2/lib/protocol/crypto.js +1602 -0
  252. package/node_modules/ssh2/lib/protocol/handlers.js +16 -0
  253. package/node_modules/ssh2/lib/protocol/handlers.misc.js +1285 -0
  254. package/node_modules/ssh2/lib/protocol/kex.js +1908 -0
  255. package/node_modules/ssh2/lib/protocol/keyParser.js +1484 -0
  256. package/node_modules/ssh2/lib/protocol/node-fs-compat.js +115 -0
  257. package/node_modules/ssh2/lib/protocol/utils.js +356 -0
  258. package/node_modules/ssh2/lib/protocol/zlib.js +255 -0
  259. package/node_modules/ssh2/lib/server.js +1380 -0
  260. package/node_modules/ssh2/lib/utils.js +336 -0
  261. package/node_modules/ssh2/package.json +49 -0
  262. package/node_modules/ssh2/test/common.js +316 -0
  263. package/node_modules/ssh2/test/fixtures/bad_rsa_private_key +26 -0
  264. package/node_modules/ssh2/test/fixtures/https_cert.pem +33 -0
  265. package/node_modules/ssh2/test/fixtures/https_key.pem +52 -0
  266. package/node_modules/ssh2/test/fixtures/id_dsa +12 -0
  267. package/node_modules/ssh2/test/fixtures/id_ecdsa +5 -0
  268. package/node_modules/ssh2/test/fixtures/id_rsa +15 -0
  269. package/node_modules/ssh2/test/fixtures/id_rsa.ppk +26 -0
  270. package/node_modules/ssh2/test/fixtures/id_rsa_enc +30 -0
  271. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa +21 -0
  272. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.pub +1 -0
  273. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.pub.result +7 -0
  274. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.result +7 -0
  275. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc +22 -0
  276. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.pub +1 -0
  277. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.pub.result +7 -0
  278. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.result +7 -0
  279. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm +23 -0
  280. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.pub +1 -0
  281. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.pub.result +7 -0
  282. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.result +7 -0
  283. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa +9 -0
  284. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.pub +1 -0
  285. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.pub.result +7 -0
  286. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.result +7 -0
  287. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc +10 -0
  288. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.pub +1 -0
  289. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.pub.result +8 -0
  290. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.result +7 -0
  291. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm +10 -0
  292. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.pub +1 -0
  293. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.pub.result +8 -0
  294. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.result +7 -0
  295. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519 +7 -0
  296. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.pub +1 -0
  297. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.pub.result +7 -0
  298. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.result +7 -0
  299. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa +27 -0
  300. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.pub +1 -0
  301. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.pub.result +7 -0
  302. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.result +7 -0
  303. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc +28 -0
  304. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.pub +1 -0
  305. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.pub.result +8 -0
  306. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.result +7 -0
  307. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm +29 -0
  308. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.pub +1 -0
  309. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.pub.result +8 -0
  310. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.result +7 -0
  311. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa +12 -0
  312. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.pub +1 -0
  313. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.pub.result +7 -0
  314. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.result +7 -0
  315. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc +15 -0
  316. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.pub +1 -0
  317. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.pub.result +8 -0
  318. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.result +7 -0
  319. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa +5 -0
  320. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.pub +1 -0
  321. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.pub.result +7 -0
  322. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.result +7 -0
  323. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc +8 -0
  324. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.pub +1 -0
  325. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.pub.result +8 -0
  326. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.result +7 -0
  327. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa +27 -0
  328. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.pub +1 -0
  329. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.pub.result +7 -0
  330. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.result +7 -0
  331. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc +30 -0
  332. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.pub +1 -0
  333. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.pub.result +8 -0
  334. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.result +7 -0
  335. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256 +54 -0
  336. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.pub +1 -0
  337. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.pub.result +6 -0
  338. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.result +6 -0
  339. package/node_modules/ssh2/test/fixtures/keyParser/ppk_dsa_enc +17 -0
  340. package/node_modules/ssh2/test/fixtures/keyParser/ppk_dsa_enc.result +7 -0
  341. package/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa +26 -0
  342. package/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa.result +7 -0
  343. package/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa_enc +18 -0
  344. package/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa_enc.result +7 -0
  345. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa.pub +9 -0
  346. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa.pub.result +7 -0
  347. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa2.pub +10 -0
  348. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa2.pub.result +7 -0
  349. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa3.pub +11 -0
  350. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa3.pub.result +7 -0
  351. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa4.pub +11 -0
  352. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa4.pub.result +7 -0
  353. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa5.pub +8 -0
  354. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa5.pub.result +7 -0
  355. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa6.pub +13 -0
  356. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa6.pub.result +7 -0
  357. package/node_modules/ssh2/test/fixtures/openssh_new_rsa +27 -0
  358. package/node_modules/ssh2/test/fixtures/ssh_host_dsa_key +12 -0
  359. package/node_modules/ssh2/test/fixtures/ssh_host_ecdsa_key +5 -0
  360. package/node_modules/ssh2/test/fixtures/ssh_host_rsa_key +15 -0
  361. package/node_modules/ssh2/test/test-exec.js +578 -0
  362. package/node_modules/ssh2/test/test-integration-openssh.js +486 -0
  363. package/node_modules/ssh2/test/test-keygen.js +60 -0
  364. package/node_modules/ssh2/test/test-misc-client-server.js +1460 -0
  365. package/node_modules/ssh2/test/test-openssh.js +261 -0
  366. package/node_modules/ssh2/test/test-protocol-crypto.js +631 -0
  367. package/node_modules/ssh2/test/test-protocol-keyparser.js +177 -0
  368. package/node_modules/ssh2/test/test-server-hostkeys.js +138 -0
  369. package/node_modules/ssh2/test/test-sftp.js +842 -0
  370. package/node_modules/ssh2/test/test-shell.js +109 -0
  371. package/node_modules/ssh2/test/test-userauth-agent-openssh.js +110 -0
  372. package/node_modules/ssh2/test/test-userauth-agent.js +171 -0
  373. package/node_modules/ssh2/test/test-userauth.js +611 -0
  374. package/node_modules/ssh2/test/test-worker-imports.js +25 -0
  375. package/node_modules/ssh2/test/test.js +20 -0
  376. package/node_modules/ssh2/util/build_pagent.bat +2 -0
  377. package/node_modules/ssh2/util/pagent.c +88 -0
  378. package/node_modules/ssh2/util/pagent.exe +0 -0
  379. package/node_modules/tweetnacl/.npmignore +4 -0
  380. package/node_modules/tweetnacl/AUTHORS.md +28 -0
  381. package/node_modules/tweetnacl/CHANGELOG.md +221 -0
  382. package/node_modules/tweetnacl/LICENSE +24 -0
  383. package/node_modules/tweetnacl/PULL_REQUEST_TEMPLATE.md +20 -0
  384. package/node_modules/tweetnacl/README.md +459 -0
  385. package/node_modules/tweetnacl/nacl-fast.js +2388 -0
  386. package/node_modules/tweetnacl/nacl-fast.min.js +2 -0
  387. package/node_modules/tweetnacl/nacl.d.ts +98 -0
  388. package/node_modules/tweetnacl/nacl.js +1175 -0
  389. package/node_modules/tweetnacl/nacl.min.js +1 -0
  390. package/node_modules/tweetnacl/package.json +58 -0
  391. package/package.json +95 -89
package/lib/forwards.js CHANGED
@@ -1,258 +1,258 @@
1
- // dsh-remote — SSH port forwarding manager (local & reverse tunnels).
2
- //
3
- // Local forward: listen on 127.0.0.1:<listenPort> → every connection is
4
- // piped through the SSH channel to <targetHost>:<targetPort> on the remote.
5
- // Reverse forward: ask the remote to listen on 127.0.0.1:<listenPort> and pipe
6
- // incoming connections back to <targetHost>:<targetPort> on the LOCAL side
7
- // (ssh2 `forwardIn` + the client `tcpip` event; requires AllowTcpForwarding on
8
- // the remote sshd).
9
- //
10
- // Definitions persist in forwards.json; forwards become active only while the
11
- // SSH connection is up (auto-restart on connect when `autoStart: true`), and
12
- // every tunnel is torn down when the pool disconnects — reverse tunnels are
13
- // never auto-restarted (they would re-expose a local port without asking).
14
- import net from 'node:net'
15
- import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'
16
- import path from 'node:path'
17
- import { forwardOutChannel } from './pool.js'
18
-
19
- export class ForwardManager {
20
- /** @param {object} pool SshPool (needs .connect() returning the ssh2 client).
21
- * @param {object} [opts] - `file` (persistence) and `net` (a `node:net`
22
- * compatible module, so the listener's connection handler — the path the
23
- * issue #54 crash travelled — can be driven from a unit test without
24
- * binding a real port). */
25
- constructor(pool, { file, net: netModule } = {}) {
26
- this.pool = pool
27
- this.net = netModule || net
28
- this.file = file || null
29
- this.defs = this._load()
30
- this.servers = new Map() // id → { server | remoteListen, sockets:Set, client }
31
- this.client = null
32
- this.onTcpip = null
33
- this.onClose = null
34
- this.attach = this.attach.bind(this)
35
- }
36
-
37
- _load() {
38
- if (!this.file) return []
39
- try {
40
- const j = JSON.parse(readFileSync(this.file, 'utf8'))
41
- if (Array.isArray(j.defs)) return j.defs
42
- } catch {}
43
- return []
44
- }
45
-
46
- _save() {
47
- if (!this.file) return
48
- try {
49
- mkdirSync(path.dirname(this.file), { recursive: true })
50
- writeFileSync(this.file, JSON.stringify({ defs: this.defs }, null, 2))
51
- } catch {}
52
- }
53
-
54
- /** Called by the pool after a successful connect: restore autoStart tunnels. */
55
- attach(client) {
56
- if (this.client === client) return
57
- this.client = client
58
- this.onTcpip = (info, accept, reject) => this._handleTcpip(info, accept, reject)
59
- client.on('tcpip', this.onTcpip)
60
- this.onClose = () => this.stopAll()
61
- client.on('close', this.onClose)
62
- for (const d of this.defs) {
63
- if (d.autoStart && d.direction === 'local' && !this.servers.has(d.id)) {
64
- this.start(d).catch(() => {})
65
- }
66
- }
67
- }
68
-
69
- detach() {
70
- this.stopAll()
71
- if (this.client) {
72
- if (this.onTcpip) this.client.removeListener('tcpip', this.onTcpip)
73
- if (this.onClose) this.client.removeListener('close', this.onClose)
74
- }
75
- this.client = null
76
- this.onTcpip = null
77
- this.onClose = null
78
- }
79
-
80
- list() {
81
- return this.defs.map((d) => ({
82
- id: d.id,
83
- direction: d.direction,
84
- listenPort: d.listenPort,
85
- targetHost: d.targetHost,
86
- targetPort: d.targetPort,
87
- machineId: d.machineId || null,
88
- autoStart: !!d.autoStart,
89
- active: this.servers.has(d.id),
90
- }))
91
- }
92
-
93
- _defId() {
94
- return 'fwd-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2, 6)
95
- }
96
-
97
- /** Create a forward definition (persisted). Does NOT start it. */
98
- define({ direction = 'local', listenPort, targetHost, targetPort, autoStart = false, machineId } = {}) {
99
- const d = {
100
- id: this._defId(),
101
- direction: direction === 'reverse' ? 'reverse' : 'local',
102
- listenPort: Number(listenPort),
103
- targetHost: String(targetHost || '127.0.0.1'),
104
- targetPort: Number(targetPort),
105
- autoStart: !!autoStart,
106
- machineId: machineId || null,
107
- }
108
- this.defs.push(d)
109
- this._save()
110
- return d
111
- }
112
-
113
- remove(id) {
114
- this.stop(id)
115
- const i = this.defs.findIndex((d) => d.id === id)
116
- if (i >= 0) { this.defs.splice(i, 1); this._save(); return true }
117
- return false
118
- }
119
-
120
- async start(def) {
121
- const d = this.defs.find((x) => x.id === def.id) || def
122
- if (this.servers.has(d.id)) return { ok: true, active: true }
123
- let client = await this.pool.connect()
124
- if (!this.client) this.attach(client)
125
- if (this.client !== client) {
126
- // The pool reconnected while we were connecting — retry on the live client.
127
- client = this.client
128
- }
129
- try {
130
- if (d.direction === 'reverse') {
131
- await this._startReverse(d, client)
132
- } else {
133
- await this._startLocal(d, client)
134
- }
135
- return { ok: true, active: true }
136
- } catch (err) {
137
- return { ok: false, error: String((err && err.message) || err) }
138
- }
139
- }
140
-
141
- _startLocal(d, client) {
142
- return new Promise((resolve, reject) => {
143
- const server = this.net.createServer((socket) => {
144
- // ssh2's forwardOut reports a dead connection by THROWING
145
- // (`if (!this._sock || !isWritable(this._sock)) throw new Error('Not
146
- // connected')`) and never calls the callback, so a callback-only error
147
- // path cannot guard this call. Uncaught, the throw escapes net.Server's
148
- // connection handler and kills the whole host process — the exact fatal
149
- // stack of issue #54, found in WebAttach and reachable here too for a
150
- // user-defined local forward. `attach()` does register a `close`
151
- // listener that calls stopAll(), but a request can arrive in the window
152
- // between the connection dying and that event.
153
- forwardOutChannel(client, { dstHost: d.targetHost, dstPort: d.targetPort }).then((channel) => {
154
- socket.pipe(channel)
155
- channel.pipe(socket)
156
- const kill = () => { try { socket.destroy() } catch {}; try { channel.close() } catch {} }
157
- socket.on('error', kill)
158
- channel.on('error', kill)
159
- socket.on('close', kill)
160
- channel.on('close', kill)
161
- }).catch(() => {
162
- // A dead tunnel is a UI state, not a reason to exit.
163
- try { socket.destroy() } catch { /* already gone */ }
164
- })
165
- })
166
- server.on('error', (e) => reject(new Error(`本地转发 ${d.listenPort} 启动失败: ${e.message}`)))
167
- server.listen(d.listenPort, '127.0.0.1', () => {
168
- this.servers.set(d.id, { kind: 'local', server, sockets: new Set(), client })
169
- resolve()
170
- })
171
- })
172
- }
173
-
174
- _startReverse(d, client) {
175
- // The system-OpenSSH backend (issue #51) cannot do ssh2's two-phase
176
- // `forwardIn` + `tcpip`: the `ssh -R` CLI needs the final target as an
177
- // argument, so it exposes `reverseForward()` instead. Prefer it when
178
- // present — otherwise every reverse tunnel would fail on that backend.
179
- if (typeof client.reverseForward === 'function') {
180
- return client.reverseForward({
181
- bindHost: '127.0.0.1',
182
- listenPort: d.listenPort,
183
- targetHost: d.targetHost,
184
- targetPort: d.targetPort,
185
- }).then((handle) => {
186
- this.servers.set(d.id, { kind: 'reverse-cli', handle, client })
187
- }).catch((err) => {
188
- throw new Error(`远端监听 ${d.listenPort} 失败: ${(err && err.message) || err}`)
189
- })
190
- }
191
- return new Promise((resolve, reject) => {
192
- // ssh2 calls the remote TCP listen API `forwardIn` (NOT openssh_forwardIn,
193
- // which in ssh2 >= 1.16 is stream-local only).
194
- if (typeof client.forwardIn !== 'function') {
195
- return reject(new Error('此 ssh2 版本不支持反向转发 (forwardIn)'))
196
- }
197
- client.forwardIn('127.0.0.1', d.listenPort, (err) => {
198
- if (err) return reject(new Error(`远端监听 ${d.listenPort} 失败: ${(err && err.message) || err}`))
199
- this.servers.set(d.id, { kind: 'reverse', sockets: new Set(), client })
200
- resolve()
201
- })
202
- })
203
- }
204
-
205
- _handleTcpip(info, accept, reject) {
206
- // Only the ssh2 backend reaches here: `ssh -R` handles the remote listener
207
- // and its targets entirely inside the CLI, so a 'reverse-cli' entry never
208
- // produces a 'tcpip' event.
209
- for (const entry of this.servers.values()) {
210
- if (entry.kind === 'reverse' && Number(info.destPort) === Number(this._defFor(entry).listenPort)) {
211
- const channel = accept()
212
- const socket = this.net.connect({ host: this._defFor(entry).targetHost, port: this._defFor(entry).targetPort })
213
- socket.pipe(channel)
214
- channel.pipe(socket)
215
- entry.sockets.add(socket)
216
- const kill = () => {
217
- try { socket.destroy() } catch {}
218
- try { channel.close() } catch {}
219
- entry.sockets.delete(socket)
220
- }
221
- socket.on('error', kill)
222
- channel.on('error', kill)
223
- socket.on('close', kill)
224
- return
225
- }
226
- }
227
- reject()
228
- }
229
-
230
- _defFor(entry) {
231
- for (const d of this.defs) {
232
- if (this.servers.has(d.id) && this.servers.get(d.id) === entry) return d
233
- }
234
- return { listenPort: 0, targetHost: '127.0.0.1', targetPort: 0 }
235
- }
236
-
237
- stop(id) {
238
- const entry = this.servers.get(id)
239
- if (!entry) return
240
- try {
241
- if (entry.kind === 'local') {
242
- entry.server.close()
243
- for (const s of entry.sockets) { try { s.destroy() } catch {} }
244
- } else if (entry.kind === 'reverse-cli') {
245
- // The `ssh -R` child IS the tunnel: killing it closes the remote listener.
246
- if (entry.handle && typeof entry.handle.close === 'function') entry.handle.close()
247
- } else if (entry.client && typeof entry.client.unforwardIn === 'function') {
248
- const d = this._defFor(entry)
249
- entry.client.unforwardIn('127.0.0.1', d.listenPort, () => {})
250
- }
251
- } catch {}
252
- this.servers.delete(id)
253
- }
254
-
255
- stopAll() {
256
- for (const id of [...this.servers.keys()]) this.stop(id)
257
- }
258
- }
1
+ // dsh-remote — SSH port forwarding manager (local & reverse tunnels).
2
+ //
3
+ // Local forward: listen on 127.0.0.1:<listenPort> → every connection is
4
+ // piped through the SSH channel to <targetHost>:<targetPort> on the remote.
5
+ // Reverse forward: ask the remote to listen on 127.0.0.1:<listenPort> and pipe
6
+ // incoming connections back to <targetHost>:<targetPort> on the LOCAL side
7
+ // (ssh2 `forwardIn` + the client `tcpip` event; requires AllowTcpForwarding on
8
+ // the remote sshd).
9
+ //
10
+ // Definitions persist in forwards.json; forwards become active only while the
11
+ // SSH connection is up (auto-restart on connect when `autoStart: true`), and
12
+ // every tunnel is torn down when the pool disconnects — reverse tunnels are
13
+ // never auto-restarted (they would re-expose a local port without asking).
14
+ import net from 'node:net'
15
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'
16
+ import path from 'node:path'
17
+ import { forwardOutChannel } from './pool.js'
18
+
19
+ export class ForwardManager {
20
+ /** @param {object} pool SshPool (needs .connect() returning the ssh2 client).
21
+ * @param {object} [opts] - `file` (persistence) and `net` (a `node:net`
22
+ * compatible module, so the listener's connection handler — the path the
23
+ * issue #54 crash travelled — can be driven from a unit test without
24
+ * binding a real port). */
25
+ constructor(pool, { file, net: netModule } = {}) {
26
+ this.pool = pool
27
+ this.net = netModule || net
28
+ this.file = file || null
29
+ this.defs = this._load()
30
+ this.servers = new Map() // id → { server | remoteListen, sockets:Set, client }
31
+ this.client = null
32
+ this.onTcpip = null
33
+ this.onClose = null
34
+ this.attach = this.attach.bind(this)
35
+ }
36
+
37
+ _load() {
38
+ if (!this.file) return []
39
+ try {
40
+ const j = JSON.parse(readFileSync(this.file, 'utf8'))
41
+ if (Array.isArray(j.defs)) return j.defs
42
+ } catch {}
43
+ return []
44
+ }
45
+
46
+ _save() {
47
+ if (!this.file) return
48
+ try {
49
+ mkdirSync(path.dirname(this.file), { recursive: true })
50
+ writeFileSync(this.file, JSON.stringify({ defs: this.defs }, null, 2))
51
+ } catch {}
52
+ }
53
+
54
+ /** Called by the pool after a successful connect: restore autoStart tunnels. */
55
+ attach(client) {
56
+ if (this.client === client) return
57
+ this.client = client
58
+ this.onTcpip = (info, accept, reject) => this._handleTcpip(info, accept, reject)
59
+ client.on('tcpip', this.onTcpip)
60
+ this.onClose = () => this.stopAll()
61
+ client.on('close', this.onClose)
62
+ for (const d of this.defs) {
63
+ if (d.autoStart && d.direction === 'local' && !this.servers.has(d.id)) {
64
+ this.start(d).catch(() => {})
65
+ }
66
+ }
67
+ }
68
+
69
+ detach() {
70
+ this.stopAll()
71
+ if (this.client) {
72
+ if (this.onTcpip) this.client.removeListener('tcpip', this.onTcpip)
73
+ if (this.onClose) this.client.removeListener('close', this.onClose)
74
+ }
75
+ this.client = null
76
+ this.onTcpip = null
77
+ this.onClose = null
78
+ }
79
+
80
+ list() {
81
+ return this.defs.map((d) => ({
82
+ id: d.id,
83
+ direction: d.direction,
84
+ listenPort: d.listenPort,
85
+ targetHost: d.targetHost,
86
+ targetPort: d.targetPort,
87
+ machineId: d.machineId || null,
88
+ autoStart: !!d.autoStart,
89
+ active: this.servers.has(d.id),
90
+ }))
91
+ }
92
+
93
+ _defId() {
94
+ return 'fwd-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2, 6)
95
+ }
96
+
97
+ /** Create a forward definition (persisted). Does NOT start it. */
98
+ define({ direction = 'local', listenPort, targetHost, targetPort, autoStart = false, machineId } = {}) {
99
+ const d = {
100
+ id: this._defId(),
101
+ direction: direction === 'reverse' ? 'reverse' : 'local',
102
+ listenPort: Number(listenPort),
103
+ targetHost: String(targetHost || '127.0.0.1'),
104
+ targetPort: Number(targetPort),
105
+ autoStart: !!autoStart,
106
+ machineId: machineId || null,
107
+ }
108
+ this.defs.push(d)
109
+ this._save()
110
+ return d
111
+ }
112
+
113
+ remove(id) {
114
+ this.stop(id)
115
+ const i = this.defs.findIndex((d) => d.id === id)
116
+ if (i >= 0) { this.defs.splice(i, 1); this._save(); return true }
117
+ return false
118
+ }
119
+
120
+ async start(def) {
121
+ const d = this.defs.find((x) => x.id === def.id) || def
122
+ if (this.servers.has(d.id)) return { ok: true, active: true }
123
+ let client = await this.pool.connect()
124
+ if (!this.client) this.attach(client)
125
+ if (this.client !== client) {
126
+ // The pool reconnected while we were connecting — retry on the live client.
127
+ client = this.client
128
+ }
129
+ try {
130
+ if (d.direction === 'reverse') {
131
+ await this._startReverse(d, client)
132
+ } else {
133
+ await this._startLocal(d, client)
134
+ }
135
+ return { ok: true, active: true }
136
+ } catch (err) {
137
+ return { ok: false, error: String((err && err.message) || err) }
138
+ }
139
+ }
140
+
141
+ _startLocal(d, client) {
142
+ return new Promise((resolve, reject) => {
143
+ const server = this.net.createServer((socket) => {
144
+ // ssh2's forwardOut reports a dead connection by THROWING
145
+ // (`if (!this._sock || !isWritable(this._sock)) throw new Error('Not
146
+ // connected')`) and never calls the callback, so a callback-only error
147
+ // path cannot guard this call. Uncaught, the throw escapes net.Server's
148
+ // connection handler and kills the whole host process — the exact fatal
149
+ // stack of issue #54, found in WebAttach and reachable here too for a
150
+ // user-defined local forward. `attach()` does register a `close`
151
+ // listener that calls stopAll(), but a request can arrive in the window
152
+ // between the connection dying and that event.
153
+ forwardOutChannel(client, { dstHost: d.targetHost, dstPort: d.targetPort }).then((channel) => {
154
+ socket.pipe(channel)
155
+ channel.pipe(socket)
156
+ const kill = () => { try { socket.destroy() } catch {}; try { channel.close() } catch {} }
157
+ socket.on('error', kill)
158
+ channel.on('error', kill)
159
+ socket.on('close', kill)
160
+ channel.on('close', kill)
161
+ }).catch(() => {
162
+ // A dead tunnel is a UI state, not a reason to exit.
163
+ try { socket.destroy() } catch { /* already gone */ }
164
+ })
165
+ })
166
+ server.on('error', (e) => reject(new Error(`本地转发 ${d.listenPort} 启动失败: ${e.message}`)))
167
+ server.listen(d.listenPort, '127.0.0.1', () => {
168
+ this.servers.set(d.id, { kind: 'local', server, sockets: new Set(), client })
169
+ resolve()
170
+ })
171
+ })
172
+ }
173
+
174
+ _startReverse(d, client) {
175
+ // The system-OpenSSH backend (issue #51) cannot do ssh2's two-phase
176
+ // `forwardIn` + `tcpip`: the `ssh -R` CLI needs the final target as an
177
+ // argument, so it exposes `reverseForward()` instead. Prefer it when
178
+ // present — otherwise every reverse tunnel would fail on that backend.
179
+ if (typeof client.reverseForward === 'function') {
180
+ return client.reverseForward({
181
+ bindHost: '127.0.0.1',
182
+ listenPort: d.listenPort,
183
+ targetHost: d.targetHost,
184
+ targetPort: d.targetPort,
185
+ }).then((handle) => {
186
+ this.servers.set(d.id, { kind: 'reverse-cli', handle, client })
187
+ }).catch((err) => {
188
+ throw new Error(`远端监听 ${d.listenPort} 失败: ${(err && err.message) || err}`)
189
+ })
190
+ }
191
+ return new Promise((resolve, reject) => {
192
+ // ssh2 calls the remote TCP listen API `forwardIn` (NOT openssh_forwardIn,
193
+ // which in ssh2 >= 1.16 is stream-local only).
194
+ if (typeof client.forwardIn !== 'function') {
195
+ return reject(new Error('此 ssh2 版本不支持反向转发 (forwardIn)'))
196
+ }
197
+ client.forwardIn('127.0.0.1', d.listenPort, (err) => {
198
+ if (err) return reject(new Error(`远端监听 ${d.listenPort} 失败: ${(err && err.message) || err}`))
199
+ this.servers.set(d.id, { kind: 'reverse', sockets: new Set(), client })
200
+ resolve()
201
+ })
202
+ })
203
+ }
204
+
205
+ _handleTcpip(info, accept, reject) {
206
+ // Only the ssh2 backend reaches here: `ssh -R` handles the remote listener
207
+ // and its targets entirely inside the CLI, so a 'reverse-cli' entry never
208
+ // produces a 'tcpip' event.
209
+ for (const entry of this.servers.values()) {
210
+ if (entry.kind === 'reverse' && Number(info.destPort) === Number(this._defFor(entry).listenPort)) {
211
+ const channel = accept()
212
+ const socket = this.net.connect({ host: this._defFor(entry).targetHost, port: this._defFor(entry).targetPort })
213
+ socket.pipe(channel)
214
+ channel.pipe(socket)
215
+ entry.sockets.add(socket)
216
+ const kill = () => {
217
+ try { socket.destroy() } catch {}
218
+ try { channel.close() } catch {}
219
+ entry.sockets.delete(socket)
220
+ }
221
+ socket.on('error', kill)
222
+ channel.on('error', kill)
223
+ socket.on('close', kill)
224
+ return
225
+ }
226
+ }
227
+ reject()
228
+ }
229
+
230
+ _defFor(entry) {
231
+ for (const d of this.defs) {
232
+ if (this.servers.has(d.id) && this.servers.get(d.id) === entry) return d
233
+ }
234
+ return { listenPort: 0, targetHost: '127.0.0.1', targetPort: 0 }
235
+ }
236
+
237
+ stop(id) {
238
+ const entry = this.servers.get(id)
239
+ if (!entry) return
240
+ try {
241
+ if (entry.kind === 'local') {
242
+ entry.server.close()
243
+ for (const s of entry.sockets) { try { s.destroy() } catch {} }
244
+ } else if (entry.kind === 'reverse-cli') {
245
+ // The `ssh -R` child IS the tunnel: killing it closes the remote listener.
246
+ if (entry.handle && typeof entry.handle.close === 'function') entry.handle.close()
247
+ } else if (entry.client && typeof entry.client.unforwardIn === 'function') {
248
+ const d = this._defFor(entry)
249
+ entry.client.unforwardIn('127.0.0.1', d.listenPort, () => {})
250
+ }
251
+ } catch {}
252
+ this.servers.delete(id)
253
+ }
254
+
255
+ stopAll() {
256
+ for (const id of [...this.servers.keys()]) this.stop(id)
257
+ }
258
+ }