harbr 0.2.10 → 2.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (179) hide show
  1. checksums.yaml +4 -4
  2. data/.DS_Store +0 -0
  3. data/exe/harbr +225 -150
  4. data/lib/examples/container.toml +13 -0
  5. data/lib/harbr/container.rb +14 -10
  6. data/lib/harbr/host.rb +21 -0
  7. data/lib/harbr/version.rb +1 -1
  8. data/lib/harbr.rb +21 -6
  9. data/vendor/bundle/ruby/3.2.0/cache/dddr-1.0.8.gem +0 -0
  10. data/vendor/bundle/ruby/3.2.0/cache/dddr-1.1.0.gem +0 -0
  11. data/vendor/bundle/ruby/3.2.0/cache/dddr-1.1.1.gem +0 -0
  12. data/vendor/bundle/ruby/3.2.0/cache/net-ssh-7.2.1.gem +0 -0
  13. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.0.8/.DS_Store +0 -0
  14. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.0.8/.rspec +3 -0
  15. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.0.8/.standard.yml +3 -0
  16. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.0.8/CHANGELOG.md +5 -0
  17. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.0.8/CODE_OF_CONDUCT.md +84 -0
  18. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.0.8/LICENSE.txt +21 -0
  19. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.0.8/README.md +96 -0
  20. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.0.8/Rakefile +10 -0
  21. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.0.8/hero.png +0 -0
  22. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.0.8/lib/dddr/version.rb +5 -0
  23. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.0.8/lib/dddr.rb +205 -0
  24. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.0.8/sig/dddr.rbs +4 -0
  25. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.0/.DS_Store +0 -0
  26. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.0/.rspec +3 -0
  27. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.0/.standard.yml +3 -0
  28. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.0/CHANGELOG.md +5 -0
  29. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.0/CODE_OF_CONDUCT.md +84 -0
  30. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.0/LICENSE.txt +21 -0
  31. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.0/README.md +96 -0
  32. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.0/Rakefile +10 -0
  33. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.0/hero.png +0 -0
  34. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.0/lib/dddr/version.rb +5 -0
  35. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.0/lib/dddr.rb +182 -0
  36. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.0/sig/dddr.rbs +4 -0
  37. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.1/.DS_Store +0 -0
  38. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.1/.rspec +3 -0
  39. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.1/.standard.yml +3 -0
  40. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.1/CHANGELOG.md +5 -0
  41. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.1/CODE_OF_CONDUCT.md +84 -0
  42. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.1/LICENSE.txt +21 -0
  43. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.1/README.md +96 -0
  44. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.1/Rakefile +10 -0
  45. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.1/hero.png +0 -0
  46. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.1/lib/dddr/version.rb +5 -0
  47. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.1/lib/dddr.rb +184 -0
  48. data/vendor/bundle/ruby/3.2.0/gems/dddr-1.1.1/sig/dddr.rbs +4 -0
  49. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/.dockerignore +6 -0
  50. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/.github/FUNDING.yml +1 -0
  51. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/.github/config/rubocop_linter_action.yml +4 -0
  52. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/.github/workflows/ci-with-docker.yml +44 -0
  53. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/.github/workflows/ci.yml +94 -0
  54. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/.github/workflows/rubocop.yml +16 -0
  55. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/.gitignore +15 -0
  56. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/.rubocop.yml +22 -0
  57. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/.rubocop_todo.yml +1081 -0
  58. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/CHANGES.txt +738 -0
  59. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/DEVELOPMENT.md +23 -0
  60. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/Dockerfile +29 -0
  61. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/Dockerfile.openssl3 +17 -0
  62. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/Gemfile +13 -0
  63. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/Gemfile.noed25519 +12 -0
  64. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/Gemfile.norbnacl +12 -0
  65. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/ISSUE_TEMPLATE.md +30 -0
  66. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/LICENSE.txt +19 -0
  67. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/Manifest +132 -0
  68. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/README.md +298 -0
  69. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/Rakefile +192 -0
  70. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/SECURITY.md +4 -0
  71. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/THANKS.txt +110 -0
  72. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/appveyor.yml +58 -0
  73. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/docker-compose.yml +25 -0
  74. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/authentication/agent.rb +284 -0
  75. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/authentication/certificate.rb +183 -0
  76. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/authentication/constants.rb +20 -0
  77. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/authentication/ed25519.rb +186 -0
  78. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
  79. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/authentication/key_manager.rb +327 -0
  80. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/authentication/methods/abstract.rb +79 -0
  81. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/authentication/methods/hostbased.rb +72 -0
  82. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/authentication/methods/keyboard_interactive.rb +77 -0
  83. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/authentication/methods/none.rb +34 -0
  84. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/authentication/methods/password.rb +80 -0
  85. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/authentication/methods/publickey.rb +137 -0
  86. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/authentication/pageant.rb +497 -0
  87. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
  88. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/authentication/session.rb +172 -0
  89. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/buffer.rb +449 -0
  90. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/buffered_io.rb +202 -0
  91. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/config.rb +406 -0
  92. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/connection/channel.rb +694 -0
  93. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/connection/constants.rb +33 -0
  94. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/connection/event_loop.rb +123 -0
  95. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/connection/keepalive.rb +59 -0
  96. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/connection/session.rb +712 -0
  97. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/connection/term.rb +180 -0
  98. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/errors.rb +106 -0
  99. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/key_factory.rb +218 -0
  100. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/known_hosts.rb +265 -0
  101. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/loggable.rb +62 -0
  102. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/packet.rb +106 -0
  103. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/prompt.rb +62 -0
  104. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/proxy/command.rb +123 -0
  105. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/proxy/errors.rb +16 -0
  106. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/proxy/http.rb +98 -0
  107. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/proxy/https.rb +50 -0
  108. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/proxy/jump.rb +54 -0
  109. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/proxy/socks4.rb +67 -0
  110. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/proxy/socks5.rb +140 -0
  111. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/service/forward.rb +426 -0
  112. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/test/channel.rb +147 -0
  113. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/test/extensions.rb +173 -0
  114. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/test/kex.rb +46 -0
  115. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/test/local_packet.rb +53 -0
  116. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/test/packet.rb +101 -0
  117. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/test/remote_packet.rb +40 -0
  118. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/test/script.rb +180 -0
  119. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/test/socket.rb +65 -0
  120. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/test.rb +94 -0
  121. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/algorithms.rb +524 -0
  122. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/chacha20_poly1305_cipher.rb +117 -0
  123. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb +17 -0
  124. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/cipher_factory.rb +128 -0
  125. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/constants.rb +40 -0
  126. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/ctr.rb +115 -0
  127. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/hmac/abstract.rb +97 -0
  128. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/hmac/md5.rb +10 -0
  129. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/hmac/md5_96.rb +9 -0
  130. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/hmac/none.rb +13 -0
  131. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/hmac/ripemd160.rb +11 -0
  132. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/hmac/sha1.rb +11 -0
  133. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/hmac/sha1_96.rb +9 -0
  134. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/hmac/sha2_256.rb +11 -0
  135. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/hmac/sha2_256_96.rb +9 -0
  136. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  137. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/hmac/sha2_512.rb +11 -0
  138. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/hmac/sha2_512_96.rb +9 -0
  139. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  140. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/hmac.rb +47 -0
  141. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/identity_cipher.rb +65 -0
  142. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/kex/abstract.rb +130 -0
  143. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  144. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  145. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  146. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +37 -0
  147. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  148. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +122 -0
  149. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +72 -0
  150. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +11 -0
  151. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +39 -0
  152. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +21 -0
  153. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +21 -0
  154. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/kex.rb +31 -0
  155. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/key_expander.rb +30 -0
  156. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/openssl.rb +274 -0
  157. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/openssl_cipher_extensions.rb +8 -0
  158. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/packet_stream.rb +301 -0
  159. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/server_version.rb +77 -0
  160. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/session.rb +354 -0
  161. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/transport/state.rb +208 -0
  162. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/verifiers/accept_new.rb +33 -0
  163. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
  164. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/verifiers/always.rb +58 -0
  165. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/verifiers/never.rb +19 -0
  166. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh/version.rb +68 -0
  167. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/lib/net/ssh.rb +338 -0
  168. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/net-ssh-public_cert.pem +20 -0
  169. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/net-ssh.gemspec +46 -0
  170. data/vendor/bundle/ruby/3.2.0/gems/net-ssh-7.2.1/support/ssh_tunnel_bug.rb +65 -0
  171. data/vendor/bundle/ruby/3.2.0/specifications/dddr-1.0.8.gemspec +27 -0
  172. data/vendor/bundle/ruby/3.2.0/specifications/dddr-1.1.0.gemspec +27 -0
  173. data/vendor/bundle/ruby/3.2.0/specifications/dddr-1.1.1.gemspec +27 -0
  174. data/vendor/bundle/ruby/3.2.0/specifications/net-ssh-7.2.1.gemspec +38 -0
  175. metadata +174 -9
  176. data/config/manifest.yml +0 -5
  177. data/lib/harbr/job.rb +0 -252
  178. data/lib/harbr/lxd/job.rb +0 -119
  179. data/lib/harbr/lxd/setup.rb +0 -45
@@ -0,0 +1,202 @@
1
+ require 'net/ssh/buffer'
2
+ require 'net/ssh/loggable'
3
+
4
+ module Net
5
+ module SSH
6
+ # This module is used to extend sockets and other IO objects, to allow
7
+ # them to be buffered for both read and write. This abstraction makes it
8
+ # quite easy to write a select-based event loop
9
+ # (see Net::SSH::Connection::Session#listen_to).
10
+ #
11
+ # The general idea is that instead of calling #read directly on an IO that
12
+ # has been extended with this module, you call #fill (to add pending input
13
+ # to the internal read buffer), and then #read_available (to read from that
14
+ # buffer). Likewise, you don't call #write directly, you call #enqueue to
15
+ # add data to the write buffer, and then #send_pending or #wait_for_pending_sends
16
+ # to actually send the data across the wire.
17
+ #
18
+ # In this way you can easily use the object as an argument to IO.select,
19
+ # calling #fill when it is available for read, or #send_pending when it is
20
+ # available for write, and then call #enqueue and #read_available during
21
+ # the idle times.
22
+ #
23
+ # socket = TCPSocket.new(address, port)
24
+ # socket.extend(Net::SSH::BufferedIo)
25
+ #
26
+ # ssh.listen_to(socket)
27
+ #
28
+ # ssh.loop do
29
+ # if socket.available > 0
30
+ # puts socket.read_available
31
+ # socket.enqueue("response\n")
32
+ # end
33
+ # end
34
+ #
35
+ # Note that this module must be used to extend an instance, and should not
36
+ # be included in a class. If you do want to use it via an include, then you
37
+ # must make sure to invoke the private #initialize_buffered_io method in
38
+ # your class' #initialize method:
39
+ #
40
+ # class Foo < IO
41
+ # include Net::SSH::BufferedIo
42
+ #
43
+ # def initialize
44
+ # initialize_buffered_io
45
+ # # ...
46
+ # end
47
+ # end
48
+ module BufferedIo
49
+ include Loggable
50
+
51
+ # Called when the #extend is called on an object, with this module as the
52
+ # argument. It ensures that the modules instance variables are all properly
53
+ # initialized.
54
+ def self.extended(object) # :nodoc:
55
+ # need to use __send__ because #send is overridden in Socket
56
+ object.__send__(:initialize_buffered_io)
57
+ end
58
+
59
+ # Tries to read up to +n+ bytes of data from the remote end, and appends
60
+ # the data to the input buffer. It returns the number of bytes read, or 0
61
+ # if no data was available to be read.
62
+ def fill(n = 8192)
63
+ input.consume!
64
+ data = recv(n) || ""
65
+ debug { "read #{data.length} bytes" }
66
+ input.append(data)
67
+ return data.length
68
+ rescue EOFError => e
69
+ @input_errors << e
70
+ return 0
71
+ end
72
+
73
+ # Read up to +length+ bytes from the input buffer. If +length+ is nil,
74
+ # all available data is read from the buffer. (See #available.)
75
+ def read_available(length = nil)
76
+ input.read(length || available)
77
+ end
78
+
79
+ # Returns the number of bytes available to be read from the input buffer.
80
+ # (See #read_available.)
81
+ def available
82
+ input.available
83
+ end
84
+
85
+ # Enqueues data in the output buffer, to be written when #send_pending
86
+ # is called. Note that the data is _not_ sent immediately by this method!
87
+ def enqueue(data)
88
+ output.append(data)
89
+ end
90
+
91
+ # Returns +true+ if there is data waiting in the output buffer, and
92
+ # +false+ otherwise.
93
+ def pending_write?
94
+ output.length > 0
95
+ end
96
+
97
+ # Sends as much of the pending output as possible. Returns +true+ if any
98
+ # data was sent, and +false+ otherwise.
99
+ def send_pending
100
+ if output.length > 0
101
+ sent = send(output.to_s, 0)
102
+ debug { "sent #{sent} bytes" }
103
+ output.consume!(sent)
104
+ return sent > 0
105
+ else
106
+ return false
107
+ end
108
+ end
109
+
110
+ # Calls #send_pending repeatedly, if necessary, blocking until the output
111
+ # buffer is empty.
112
+ def wait_for_pending_sends
113
+ send_pending
114
+ while output.length > 0
115
+ result = IO.select(nil, [self]) or next
116
+ next unless result[1].any?
117
+
118
+ send_pending
119
+ end
120
+ end
121
+
122
+ public # these methods are primarily for use in tests
123
+
124
+ def write_buffer # :nodoc:
125
+ output.to_s
126
+ end
127
+
128
+ def read_buffer # :nodoc:
129
+ input.to_s
130
+ end
131
+
132
+ private
133
+
134
+ #--
135
+ # Can't use attr_reader here (after +private+) without incurring the
136
+ # wrath of "ruby -w". We hates it.
137
+ #++
138
+
139
+ def input; @input; end
140
+
141
+ def output; @output; end
142
+
143
+ # Initializes the intput and output buffers for this object. This method
144
+ # is called automatically when the module is mixed into an object via
145
+ # Object#extend (see Net::SSH::BufferedIo.extended), but must be called
146
+ # explicitly in the +initialize+ method of any class that uses
147
+ # Module#include to add this module.
148
+ def initialize_buffered_io
149
+ @input = Net::SSH::Buffer.new
150
+ @input_errors = []
151
+ @output = Net::SSH::Buffer.new
152
+ @output_errors = []
153
+ end
154
+ end
155
+
156
+ # Fixes for two issues by Miklós Fazekas:
157
+ #
158
+ # * if client closes a forwarded connection, but the server is
159
+ # reading, net-ssh terminates with IOError socket closed.
160
+ # * if client force closes (RST) a forwarded connection, but
161
+ # server is reading, net-ssh terminates with [an exception]
162
+ #
163
+ # See:
164
+ #
165
+ # http://net-ssh.lighthouseapp.com/projects/36253/tickets/7
166
+ # http://github.com/net-ssh/net-ssh/tree/portfwfix
167
+ #
168
+ module ForwardedBufferedIo
169
+ def fill(n = 8192)
170
+ begin
171
+ super(n)
172
+ rescue Errno::ECONNRESET => e
173
+ debug { "connection was reset => shallowing exception:#{e}" }
174
+ return 0
175
+ rescue IOError => e
176
+ if e.message =~ /closed/ then
177
+ debug { "connection was reset => shallowing exception:#{e}" }
178
+ return 0
179
+ else
180
+ raise
181
+ end
182
+ end
183
+ end
184
+
185
+ def send_pending
186
+ begin
187
+ super
188
+ rescue Errno::ECONNRESET => e
189
+ debug { "connection was reset => shallowing exception:#{e}" }
190
+ return 0
191
+ rescue IOError => e
192
+ if e.message =~ /closed/ then
193
+ debug { "connection was reset => shallowing exception:#{e}" }
194
+ return 0
195
+ else
196
+ raise
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,406 @@
1
+ module Net
2
+ module SSH
3
+ # The Net::SSH::Config class is used to parse OpenSSH configuration files,
4
+ # and translates that syntax into the configuration syntax that Net::SSH
5
+ # understands. This lets Net::SSH scripts read their configuration (to
6
+ # some extent) from OpenSSH configuration files (~/.ssh/config, /etc/ssh_config,
7
+ # and so forth).
8
+ #
9
+ # Only a subset of OpenSSH configuration options are understood:
10
+ #
11
+ # * ChallengeResponseAuthentication => maps to the :auth_methods option challenge-response (then coleasced into keyboard-interactive)
12
+ # * KbdInteractiveAuthentication => maps to the :auth_methods keyboard-interactive
13
+ # * CertificateFile => maps to the :keycerts option
14
+ # * Ciphers => maps to the :encryption option
15
+ # * Compression => :compression
16
+ # * CompressionLevel => :compression_level
17
+ # * ConnectTimeout => maps to the :timeout option
18
+ # * ForwardAgent => :forward_agent
19
+ # * GlobalKnownHostsFile => :global_known_hosts_file
20
+ # * HostBasedAuthentication => maps to the :auth_methods option
21
+ # * HostKeyAlgorithms => maps to :host_key option
22
+ # * HostKeyAlias => :host_key_alias
23
+ # * HostName => :host_name
24
+ # * IdentityFile => maps to the :keys option
25
+ # * IdentityAgent => :identity_agent
26
+ # * IdentitiesOnly => :keys_only
27
+ # * CheckHostIP => :check_host_ip
28
+ # * Macs => maps to the :hmac option
29
+ # * PasswordAuthentication => maps to the :auth_methods option password
30
+ # * Port => :port
31
+ # * PreferredAuthentications => maps to the :auth_methods option
32
+ # * ProxyCommand => maps to the :proxy option
33
+ # * ProxyJump => maps to the :proxy option
34
+ # * PubKeyAuthentication => maps to the :auth_methods option
35
+ # * RekeyLimit => :rekey_limit
36
+ # * StrictHostKeyChecking => :verify_host_key
37
+ # * User => :user
38
+ # * UserKnownHostsFile => :user_known_hosts_file
39
+ # * NumberOfPasswordPrompts => :number_of_password_prompts
40
+ # * FingerprintHash => :fingerprint_hash
41
+ #
42
+ # Note that you will never need to use this class directly--you can control
43
+ # whether the OpenSSH configuration files are read by passing the :config
44
+ # option to Net::SSH.start. (They are, by default.)
45
+ class Config
46
+ class << self
47
+ @@default_files = %w[~/.ssh/config /etc/ssh_config /etc/ssh/ssh_config]
48
+ # The following defaults follow the openssh client ssh_config defaults.
49
+ # http://lwn.net/Articles/544640/
50
+ # "hostbased" is off and "none" is not supported but we allow it since
51
+ # it's used by some clients to query the server for allowed auth methods
52
+ @@default_auth_methods = %w[none publickey password keyboard-interactive]
53
+
54
+ # Returns an array of locations of OpenSSH configuration files
55
+ # to parse by default.
56
+ def default_files
57
+ @@default_files.clone
58
+ end
59
+
60
+ def default_auth_methods
61
+ @@default_auth_methods.clone
62
+ end
63
+
64
+ # Loads the configuration data for the given +host+ from all of the
65
+ # given +files+ (defaulting to the list of files returned by
66
+ # #default_files), translates the resulting hash into the options
67
+ # recognized by Net::SSH, and returns them.
68
+ def for(host, files = expandable_default_files)
69
+ translate(files.inject({}) { |settings, file|
70
+ load(file, host, settings)
71
+ })
72
+ end
73
+
74
+ # Load the OpenSSH configuration settings in the given +file+ for the
75
+ # given +host+. If +settings+ is given, the options are merged into
76
+ # that hash, with existing values taking precedence over newly parsed
77
+ # ones. Returns a hash containing the OpenSSH options. (See
78
+ # #translate for how to convert the OpenSSH options into Net::SSH
79
+ # options.)
80
+ def load(path, host, settings = {}, base_dir = nil)
81
+ file = File.expand_path(path)
82
+ base_dir ||= File.dirname(file)
83
+ return settings unless File.readable?(file)
84
+
85
+ globals = {}
86
+ block_matched = false
87
+ block_seen = false
88
+ IO.foreach(file) do |line|
89
+ next if line =~ /^\s*(?:#.*)?$/
90
+
91
+ if line =~ /^\s*(\S+)\s*=(.*)$/
92
+ key, value = $1, $2
93
+ else
94
+ key, value = line.strip.split(/\s+/, 2)
95
+ end
96
+
97
+ # silently ignore malformed entries
98
+ next if value.nil?
99
+
100
+ key.downcase!
101
+ value = unquote(value)
102
+
103
+ value = case value.strip
104
+ when /^\d+$/ then value.to_i
105
+ when /^no$/i then false
106
+ when /^yes$/i then true
107
+ else value
108
+ end
109
+
110
+ if key == 'host'
111
+ # Support "Host host1 host2 hostN".
112
+ # See http://github.com/net-ssh/net-ssh/issues#issue/6
113
+ negative_hosts, positive_hosts = value.to_s.split(/\s+/).partition { |h| h.start_with?('!') }
114
+
115
+ # Check for negative patterns first. If the host matches, that overrules any other positive match.
116
+ # The host substring code is used to strip out the starting "!" so the regexp will be correct.
117
+ negative_matched = negative_hosts.any? { |h| host =~ pattern2regex(h[1..-1]) }
118
+
119
+ if negative_matched
120
+ block_matched = false
121
+ else
122
+ block_matched = positive_hosts.any? { |h| host =~ pattern2regex(h) }
123
+ end
124
+
125
+ block_seen = true
126
+ settings[key] = host
127
+ elsif key == 'match'
128
+ block_matched = eval_match_conditions(value, host, settings)
129
+ block_seen = true
130
+ elsif !block_seen
131
+ case key
132
+ when 'identityfile', 'certificatefile'
133
+ (globals[key] ||= []) << value
134
+ when 'include'
135
+ included_file_paths(base_dir, value).each do |file_path|
136
+ globals = load(file_path, host, globals, base_dir)
137
+ end
138
+ else
139
+ globals[key] = value unless settings.key?(key)
140
+ end
141
+ elsif block_matched
142
+ case key
143
+ when 'identityfile', 'certificatefile'
144
+ (settings[key] ||= []) << value
145
+ when 'include'
146
+ included_file_paths(base_dir, value).each do |file_path|
147
+ settings = load(file_path, host, settings, base_dir)
148
+ end
149
+ else
150
+ settings[key] = value unless settings.key?(key)
151
+ end
152
+ end
153
+
154
+ # ProxyCommand and ProxyJump override each other so they need to be tracked togeather
155
+ %w[proxyjump proxycommand].each do |proxy_key|
156
+ if (proxy_value = settings.delete(proxy_key))
157
+ settings['proxy'] ||= [proxy_key, proxy_value]
158
+ end
159
+ end
160
+ end
161
+
162
+ globals.merge(settings) do |key, oldval, newval|
163
+ case key
164
+ when 'identityfile', 'certificatefile'
165
+ oldval + newval
166
+ else
167
+ newval
168
+ end
169
+ end
170
+ end
171
+
172
+ # Given a hash of OpenSSH configuration options, converts them into
173
+ # a hash of Net::SSH options. Unrecognized options are ignored. The
174
+ # +settings+ hash must have Strings for keys, all downcased, and
175
+ # the returned hash will have Symbols for keys.
176
+ def translate(settings)
177
+ auth_methods = default_auth_methods.clone
178
+ (auth_methods << 'challenge-response').uniq!
179
+ ret = settings.each_with_object({ auth_methods: auth_methods }) do |(key, value), hash|
180
+ translate_config_key(hash, key.to_sym, value, settings)
181
+ end
182
+ merge_challenge_response_with_keyboard_interactive(ret)
183
+ end
184
+
185
+ # Filters default_files down to the files that are expandable.
186
+ def expandable_default_files
187
+ default_files.keep_if do |path|
188
+ File.expand_path(path)
189
+ true
190
+ rescue ArgumentError
191
+ false
192
+ end
193
+ end
194
+
195
+ private
196
+
197
+ def translate_verify_host_key(value)
198
+ case value
199
+ when false
200
+ :never
201
+ when true
202
+ :always
203
+ when 'accept-new'
204
+ :accept_new
205
+ end
206
+ end
207
+
208
+ def translate_keepalive(hash, value)
209
+ if value && value.to_i > 0
210
+ hash[:keepalive] = true
211
+ hash[:keepalive_interval] = value.to_i
212
+ else
213
+ hash[:keepalive] = false
214
+ end
215
+ end
216
+
217
+ TRANSLATE_CONFIG_KEY_RENAME_MAP = {
218
+ bindaddress: :bind_address,
219
+ compression: :compression,
220
+ compressionlevel: :compression_level,
221
+ certificatefile: :keycerts,
222
+ connecttimeout: :timeout,
223
+ forwardagent: :forward_agent,
224
+ identitiesonly: :keys_only,
225
+ identityagent: :identity_agent,
226
+ globalknownhostsfile: :global_known_hosts_file,
227
+ hostkeyalias: :host_key_alias,
228
+ identityfile: :keys,
229
+ fingerprinthash: :fingerprint_hash,
230
+ port: :port,
231
+ user: :user,
232
+ userknownhostsfile: :user_known_hosts_file,
233
+ checkhostip: :check_host_ip
234
+ }.freeze
235
+ def translate_config_key(hash, key, value, settings)
236
+ case key
237
+ when :stricthostkeychecking
238
+ hash[:verify_host_key] = translate_verify_host_key(value)
239
+ when :ciphers
240
+ hash[:encryption] = value.split(/,/)
241
+ when :hostbasedauthentication
242
+ if value
243
+ (hash[:auth_methods] << "hostbased").uniq!
244
+ else
245
+ hash[:auth_methods].delete("hostbased")
246
+ end
247
+ when :hostkeyalgorithms
248
+ hash[:host_key] = value.split(/,/)
249
+ when :hostname
250
+ hash[:host_name] = value.gsub(/%h/, settings['host'])
251
+ when :macs
252
+ hash[:hmac] = value.split(/,/)
253
+ when :serveralivecountmax
254
+ hash[:keepalive_maxcount] = value.to_i if value
255
+ when :serveraliveinterval
256
+ translate_keepalive(hash, value)
257
+ when :passwordauthentication
258
+ if value
259
+ (hash[:auth_methods] << 'password').uniq!
260
+ else
261
+ hash[:auth_methods].delete('password')
262
+ end
263
+ when :challengeresponseauthentication
264
+ if value
265
+ (hash[:auth_methods] << 'challenge-response').uniq!
266
+ else
267
+ hash[:auth_methods].delete('challenge-response')
268
+ end
269
+ when :kbdinteractiveauthentication
270
+ if value
271
+ (hash[:auth_methods] << 'keyboard-interactive').uniq!
272
+ else
273
+ hash[:auth_methods].delete('keyboard-interactive')
274
+ end
275
+ when :preferredauthentications
276
+ hash[:auth_methods] = value.split(/,/) # TODO we should place to preferred_auth_methods rather than auth_methods
277
+ when :proxy
278
+ if (proxy = setup_proxy(*value))
279
+ hash[:proxy] = proxy
280
+ end
281
+ when :pubkeyauthentication
282
+ if value
283
+ (hash[:auth_methods] << 'publickey').uniq!
284
+ else
285
+ hash[:auth_methods].delete('publickey')
286
+ end
287
+ when :rekeylimit
288
+ hash[:rekey_limit] = interpret_size(value)
289
+ when :sendenv
290
+ multi_send_env = value.to_s.split(/\s+/)
291
+ hash[:send_env] = multi_send_env.map { |e| Regexp.new pattern2regex(e).source, false }
292
+ when :setenv
293
+ hash[:set_env] = Shellwords.split(value.to_s).map { |e| e.split '=', 2 }.to_h
294
+ when :numberofpasswordprompts
295
+ hash[:number_of_password_prompts] = value.to_i
296
+ when *TRANSLATE_CONFIG_KEY_RENAME_MAP.keys
297
+ hash[TRANSLATE_CONFIG_KEY_RENAME_MAP[key]] = value
298
+ end
299
+ end
300
+
301
+ def setup_proxy(type, value)
302
+ case type
303
+ when 'proxycommand'
304
+ if value !~ /^none$/
305
+ require 'net/ssh/proxy/command'
306
+ Net::SSH::Proxy::Command.new(value)
307
+ end
308
+ when 'proxyjump'
309
+ require 'net/ssh/proxy/jump'
310
+ Net::SSH::Proxy::Jump.new(value)
311
+ end
312
+ end
313
+
314
+ # Converts an ssh_config pattern into a regex for matching against
315
+ # host names.
316
+ def pattern2regex(pattern)
317
+ tail = pattern
318
+ prefix = String.new
319
+ while !tail.empty? do
320
+ head, sep, tail = tail.partition(/[\*\?]/)
321
+ prefix = prefix + Regexp.quote(head)
322
+ case sep
323
+ when '*'
324
+ prefix += '.*'
325
+ when '?'
326
+ prefix += '.'
327
+ when ''
328
+ else
329
+ fail "Unpexpcted sep:#{sep}"
330
+ end
331
+ end
332
+ Regexp.new("^" + prefix + "$", true)
333
+ end
334
+
335
+ # Converts the given size into an integer number of bytes.
336
+ def interpret_size(size)
337
+ case size
338
+ when /k$/i then size.to_i * 1024
339
+ when /m$/i then size.to_i * 1024 * 1024
340
+ when /g$/i then size.to_i * 1024 * 1024 * 1024
341
+ else size.to_i
342
+ end
343
+ end
344
+
345
+ def merge_challenge_response_with_keyboard_interactive(hash)
346
+ if hash[:auth_methods].include?('challenge-response')
347
+ hash[:auth_methods].delete('challenge-response')
348
+ (hash[:auth_methods] << 'keyboard-interactive').uniq!
349
+ end
350
+ hash
351
+ end
352
+
353
+ def included_file_paths(base_dir, config_paths)
354
+ tokenize_config_value(config_paths).flat_map do |path|
355
+ Dir.glob(File.expand_path(path, base_dir)).select { |f| File.file?(f) }
356
+ end
357
+ end
358
+
359
+ # Tokenize string into tokens.
360
+ # A token is a word or a quoted sequence of words, separated by whitespaces.
361
+ def tokenize_config_value(str)
362
+ str.scan(/([^"\s]+)?(?:"([^"]+)")?\s*/).map(&:join)
363
+ end
364
+
365
+ def eval_match_conditions(condition, host, settings)
366
+ # Not using `\s` for whitespace matching as canonical
367
+ # ssh_config parser implementation (OpenSSH) has specific character set.
368
+ # Ref: https://github.com/openssh/openssh-portable/blob/2581333d564d8697837729b3d07d45738eaf5a54/misc.c#L237-L239
369
+ conditions = condition.split(/[ \t\r\n]+|(?<!=)=(?!=)/).reject(&:empty?)
370
+ return true if conditions == ["all"]
371
+
372
+ conditions = conditions.each_slice(2)
373
+ condition_matches = []
374
+ conditions.each do |(kind, exprs)|
375
+ exprs = unquote(exprs)
376
+
377
+ case kind.downcase
378
+ when "all"
379
+ raise "all cannot be mixed with other conditions"
380
+ when "host"
381
+ if exprs.start_with?('!')
382
+ negated = true
383
+ exprs = exprs[1..-1]
384
+ else
385
+ negated = false
386
+ end
387
+ condition_met = false
388
+ exprs.split(",").each do |expr|
389
+ condition_met = condition_met || host =~ pattern2regex(expr)
390
+ end
391
+ condition_matches << (true && negated ^ condition_met)
392
+ # else
393
+ # warn "net-ssh: Unsupported expr in Match block: #{kind}"
394
+ end
395
+ end
396
+
397
+ !condition_matches.empty? && condition_matches.all?
398
+ end
399
+
400
+ def unquote(string)
401
+ string =~ /^"(.*)"$/ ? Regexp.last_match(1) : string
402
+ end
403
+ end
404
+ end
405
+ end
406
+ end