asyncssh 2.16.0__tar.gz → 2.17.0__tar.gz

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 (177) hide show
  1. {asyncssh-2.16.0/asyncssh.egg-info → asyncssh-2.17.0}/PKG-INFO +5 -12
  2. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/channel.py +5 -1
  3. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/client.py +9 -1
  4. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/connection.py +28 -5
  5. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/gss.py +7 -3
  6. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/gss_unix.py +9 -5
  7. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/gss_win32.py +10 -2
  8. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/listener.py +12 -2
  9. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/misc.py +1 -0
  10. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/public_key.py +2 -5
  11. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/server.py +8 -0
  12. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/version.py +1 -1
  13. {asyncssh-2.16.0 → asyncssh-2.17.0/asyncssh.egg-info}/PKG-INFO +5 -12
  14. {asyncssh-2.16.0 → asyncssh-2.17.0}/docs/changes.rst +26 -0
  15. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/callback_client.py +3 -3
  16. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/callback_client2.py +3 -3
  17. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/callback_client3.py +3 -3
  18. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/callback_math_server.py +6 -3
  19. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/chat_server.py +3 -3
  20. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/check_exit_status.py +3 -3
  21. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/chroot_sftp_server.py +3 -3
  22. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/direct_client.py +3 -3
  23. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/direct_server.py +3 -3
  24. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/editor.py +3 -3
  25. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/gather_results.py +3 -3
  26. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/listening_client.py +3 -3
  27. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/local_forwarding_client.py +3 -3
  28. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/local_forwarding_client2.py +3 -3
  29. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/local_forwarding_server.py +3 -3
  30. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/math_client.py +3 -3
  31. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/math_server.py +3 -3
  32. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/redirect_input.py +3 -3
  33. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/redirect_local_pipe.py +3 -3
  34. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/redirect_remote_pipe.py +3 -3
  35. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/redirect_server.py +3 -3
  36. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/remote_forwarding_client.py +3 -3
  37. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/remote_forwarding_client2.py +3 -3
  38. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/remote_forwarding_server.py +3 -3
  39. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/reverse_client.py +3 -3
  40. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/reverse_server.py +3 -3
  41. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/scp_client.py +3 -3
  42. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/set_environment.py +3 -3
  43. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/set_terminal.py +3 -3
  44. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/sftp_client.py +3 -3
  45. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/show_environment.py +3 -3
  46. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/show_terminal.py +3 -3
  47. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/simple_cert_server.py +3 -3
  48. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/simple_client.py +11 -5
  49. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/simple_keyed_server.py +3 -3
  50. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/simple_scp_server.py +3 -3
  51. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/simple_server.py +3 -3
  52. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/simple_sftp_server.py +3 -3
  53. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/stream_direct_client.py +3 -3
  54. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/stream_direct_server.py +3 -3
  55. {asyncssh-2.16.0 → asyncssh-2.17.0}/examples/stream_listening_client.py +3 -3
  56. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/gssapi_stub.py +3 -1
  57. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_auth.py +2 -2
  58. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_connection_auth.py +13 -1
  59. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_kex.py +2 -2
  60. {asyncssh-2.16.0 → asyncssh-2.17.0}/.coveragerc +0 -0
  61. {asyncssh-2.16.0 → asyncssh-2.17.0}/.github/workflows/run_tests.yml +0 -0
  62. {asyncssh-2.16.0 → asyncssh-2.17.0}/.gitignore +0 -0
  63. {asyncssh-2.16.0 → asyncssh-2.17.0}/.readthedocs.yaml +0 -0
  64. {asyncssh-2.16.0 → asyncssh-2.17.0}/CONTRIBUTING.rst +0 -0
  65. {asyncssh-2.16.0 → asyncssh-2.17.0}/COPYRIGHT +0 -0
  66. {asyncssh-2.16.0 → asyncssh-2.17.0}/LICENSE +0 -0
  67. {asyncssh-2.16.0 → asyncssh-2.17.0}/MANIFEST.in +0 -0
  68. {asyncssh-2.16.0 → asyncssh-2.17.0}/README.rst +0 -0
  69. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/__init__.py +0 -0
  70. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/agent.py +0 -0
  71. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/agent_unix.py +0 -0
  72. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/agent_win32.py +0 -0
  73. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/asn1.py +0 -0
  74. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/auth.py +0 -0
  75. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/auth_keys.py +0 -0
  76. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/compression.py +0 -0
  77. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/config.py +0 -0
  78. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/constants.py +0 -0
  79. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/crypto/__init__.py +0 -0
  80. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/crypto/chacha.py +0 -0
  81. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/crypto/cipher.py +0 -0
  82. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/crypto/dh.py +0 -0
  83. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/crypto/dsa.py +0 -0
  84. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/crypto/ec.py +0 -0
  85. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/crypto/ec_params.py +0 -0
  86. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/crypto/ed.py +0 -0
  87. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/crypto/kdf.py +0 -0
  88. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/crypto/misc.py +0 -0
  89. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/crypto/rsa.py +0 -0
  90. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/crypto/sntrup.py +0 -0
  91. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/crypto/umac.py +0 -0
  92. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/crypto/x509.py +0 -0
  93. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/dsa.py +0 -0
  94. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/ecdsa.py +0 -0
  95. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/eddsa.py +0 -0
  96. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/editor.py +0 -0
  97. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/encryption.py +0 -0
  98. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/forward.py +0 -0
  99. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/kex.py +0 -0
  100. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/kex_dh.py +0 -0
  101. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/kex_rsa.py +0 -0
  102. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/keysign.py +0 -0
  103. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/known_hosts.py +0 -0
  104. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/logging.py +0 -0
  105. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/mac.py +0 -0
  106. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/packet.py +0 -0
  107. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/pattern.py +0 -0
  108. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/pbe.py +0 -0
  109. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/pkcs11.py +0 -0
  110. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/process.py +0 -0
  111. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/py.typed +0 -0
  112. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/rsa.py +0 -0
  113. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/saslprep.py +0 -0
  114. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/scp.py +0 -0
  115. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/session.py +0 -0
  116. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/sftp.py +0 -0
  117. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/sk.py +0 -0
  118. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/sk_ecdsa.py +0 -0
  119. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/sk_eddsa.py +0 -0
  120. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/socks.py +0 -0
  121. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/stream.py +0 -0
  122. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/subprocess.py +0 -0
  123. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/tuntap.py +0 -0
  124. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh/x11.py +0 -0
  125. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh.egg-info/SOURCES.txt +0 -0
  126. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh.egg-info/dependency_links.txt +0 -0
  127. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh.egg-info/requires.txt +0 -0
  128. {asyncssh-2.16.0 → asyncssh-2.17.0}/asyncssh.egg-info/top_level.txt +0 -0
  129. {asyncssh-2.16.0 → asyncssh-2.17.0}/docs/_templates/sidebarbottom.html +0 -0
  130. {asyncssh-2.16.0 → asyncssh-2.17.0}/docs/_templates/sidebartop.html +0 -0
  131. {asyncssh-2.16.0 → asyncssh-2.17.0}/docs/api.rst +0 -0
  132. {asyncssh-2.16.0 → asyncssh-2.17.0}/docs/conf.py +0 -0
  133. {asyncssh-2.16.0 → asyncssh-2.17.0}/docs/contributing.rst +0 -0
  134. {asyncssh-2.16.0 → asyncssh-2.17.0}/docs/index.rst +0 -0
  135. {asyncssh-2.16.0 → asyncssh-2.17.0}/docs/requirements.txt +0 -0
  136. {asyncssh-2.16.0 → asyncssh-2.17.0}/docs/rftheme/layout.html +0 -0
  137. {asyncssh-2.16.0 → asyncssh-2.17.0}/docs/rftheme/static/rftheme.css_t +0 -0
  138. {asyncssh-2.16.0 → asyncssh-2.17.0}/docs/rftheme/theme.conf +0 -0
  139. {asyncssh-2.16.0 → asyncssh-2.17.0}/docs/rtd-req.txt +0 -0
  140. {asyncssh-2.16.0 → asyncssh-2.17.0}/mypy.ini +0 -0
  141. {asyncssh-2.16.0 → asyncssh-2.17.0}/pylintrc +0 -0
  142. {asyncssh-2.16.0 → asyncssh-2.17.0}/setup.cfg +0 -0
  143. {asyncssh-2.16.0 → asyncssh-2.17.0}/setup.py +0 -0
  144. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/__init__.py +0 -0
  145. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/gss_stub.py +0 -0
  146. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/keysign_stub.py +0 -0
  147. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/pkcs11_stub.py +0 -0
  148. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/server.py +0 -0
  149. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/sk_stub.py +0 -0
  150. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/sspi_stub.py +0 -0
  151. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_agent.py +0 -0
  152. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_asn1.py +0 -0
  153. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_auth_keys.py +0 -0
  154. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_channel.py +0 -0
  155. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_compression.py +0 -0
  156. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_config.py +0 -0
  157. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_connection.py +0 -0
  158. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_editor.py +0 -0
  159. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_encryption.py +0 -0
  160. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_forward.py +0 -0
  161. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_known_hosts.py +0 -0
  162. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_logging.py +0 -0
  163. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_mac.py +0 -0
  164. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_packet.py +0 -0
  165. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_pkcs11.py +0 -0
  166. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_process.py +0 -0
  167. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_public_key.py +0 -0
  168. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_saslprep.py +0 -0
  169. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_sftp.py +0 -0
  170. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_sk.py +0 -0
  171. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_stream.py +0 -0
  172. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_subprocess.py +0 -0
  173. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_tuntap.py +0 -0
  174. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_x11.py +0 -0
  175. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/test_x509.py +0 -0
  176. {asyncssh-2.16.0 → asyncssh-2.17.0}/tests/util.py +0 -0
  177. {asyncssh-2.16.0 → asyncssh-2.17.0}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: asyncssh
3
- Version: 2.16.0
3
+ Version: 2.17.0
4
4
  Summary: AsyncSSH: Asynchronous SSHv2 client and server library
5
5
  Home-page: http://asyncssh.timeheart.net
6
6
  Author: Ron Frederick
@@ -27,23 +27,14 @@ Classifier: Topic :: Security :: Cryptography
27
27
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
28
28
  Classifier: Topic :: System :: Networking
29
29
  Requires-Python: >= 3.6
30
- License-File: LICENSE
31
- Requires-Dist: cryptography>=39.0
32
- Requires-Dist: typing_extensions>=4.0.0
33
30
  Provides-Extra: bcrypt
34
- Requires-Dist: bcrypt>=3.1.3; extra == "bcrypt"
35
31
  Provides-Extra: fido2
36
- Requires-Dist: fido2>=0.9.2; extra == "fido2"
37
32
  Provides-Extra: gssapi
38
- Requires-Dist: gssapi>=1.2.0; extra == "gssapi"
39
33
  Provides-Extra: libnacl
40
- Requires-Dist: libnacl>=1.4.2; extra == "libnacl"
41
34
  Provides-Extra: pkcs11
42
- Requires-Dist: python-pkcs11>=0.7.0; extra == "pkcs11"
43
- Provides-Extra: pyopenssl
44
- Requires-Dist: pyOpenSSL>=23.0.0; extra == "pyopenssl"
35
+ Provides-Extra: pyOpenSSL
45
36
  Provides-Extra: pywin32
46
- Requires-Dist: pywin32>=227; extra == "pywin32"
37
+ License-File: LICENSE
47
38
 
48
39
  .. image:: https://readthedocs.org/projects/asyncssh/badge/?version=latest
49
40
  :target: https://asyncssh.readthedocs.io/en/latest/?badge=latest
@@ -276,3 +267,5 @@ Three mailing lists are available for AsyncSSH:
276
267
  __ http://groups.google.com/d/forum/asyncssh-announce
277
268
  __ http://groups.google.com/d/forum/asyncssh-dev
278
269
  __ http://groups.google.com/d/forum/asyncssh-users
270
+
271
+
@@ -413,7 +413,11 @@ class SSHChannel(Generic[AnyStr], SSHPacketHandler):
413
413
  handler = cast(_RequestHandler, getattr(self, name, None))
414
414
 
415
415
  if handler:
416
- result = cast(Optional[bool], handler(packet))
416
+ if self._session:
417
+ result = cast(Optional[bool], handler(packet))
418
+ else:
419
+ # Ignore requests received after application closes the channel
420
+ result = True
417
421
  else:
418
422
  self.logger.debug1('Received unknown channel request: %s', request)
419
423
  result = False
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2013-2023 by Ron Frederick <ronf@timeheart.net> and others.
1
+ # Copyright (c) 2013-2024 by Ron Frederick <ronf@timeheart.net> and others.
2
2
  #
3
3
  # This program and the accompanying materials are made available under
4
4
  # the terms of the Eclipse Public License v2.0 which accompanies this
@@ -39,6 +39,14 @@ class SSHClient:
39
39
  to receive callbacks when certain events occur on the SSH
40
40
  connection.
41
41
 
42
+ Whenever a new SSH client connection is opened, a corresponding
43
+ SSHClient object is created and the method :meth:`connection_made`
44
+ is called, passing in the :class:`SSHClientConnection` object.
45
+
46
+ When the connection is closed, the method :meth:`connection_lost`
47
+ is called with an exception representing the reason for the
48
+ disconnect, or `None` if the connection was closed cleanly.
49
+
42
50
  For simple password or public key based authentication, nothing
43
51
  needs to be defined here if the password or client keys are passed
44
52
  in when the connection is created. However, to prompt interactively
@@ -105,8 +105,8 @@ from .logging import SSHLogger, logger
105
105
 
106
106
  from .mac import get_mac_algs, get_default_mac_algs
107
107
 
108
- from .misc import BytesOrStr, DefTuple, FilePath, HostPort, IPNetwork
109
- from .misc import MaybeAwait, OptExcInfo, Options, SockAddr
108
+ from .misc import BytesOrStr, BytesOrStrDict, DefTuple, FilePath, HostPort
109
+ from .misc import IPNetwork, MaybeAwait, OptExcInfo, Options, SockAddr
110
110
  from .misc import ChannelListenError, ChannelOpenError, CompressionError
111
111
  from .misc import DisconnectError, ConnectionLost, HostKeyNotVerifiable
112
112
  from .misc import KeyExchangeFailed, IllegalUserName, MACError
@@ -1083,7 +1083,7 @@ class SSHConnection(SSHPacketHandler, asyncio.Protocol):
1083
1083
 
1084
1084
  self._loop.call_soon(self._cleanup, exc)
1085
1085
 
1086
- def _reap_task(self, task_logger: SSHLogger,
1086
+ def _reap_task(self, task_logger: Optional[SSHLogger],
1087
1087
  task: 'asyncio.Task[None]') -> None:
1088
1088
  """Collect result of an async task, reporting errors"""
1089
1089
 
@@ -3315,7 +3315,8 @@ class SSHClientConnection(SSHConnection):
3315
3315
 
3316
3316
  if gss_host:
3317
3317
  try:
3318
- self._gss = GSSClient(gss_host, options.gss_delegate_creds)
3318
+ self._gss = GSSClient(gss_host, options.gss_store,
3319
+ options.gss_delegate_creds)
3319
3320
  self._gss_kex = options.gss_kex
3320
3321
  self._gss_auth = options.gss_auth
3321
3322
  self._gss_mic_auth = self._gss_auth
@@ -5713,7 +5714,7 @@ class SSHServerConnection(SSHConnection):
5713
5714
 
5714
5715
  if options.gss_host:
5715
5716
  try:
5716
- self._gss = GSSServer(options.gss_host)
5717
+ self._gss = GSSServer(options.gss_host, options.gss_store)
5717
5718
  self._gss_kex = options.gss_kex
5718
5719
  self._gss_auth = options.gss_auth
5719
5720
  self._gss_mic_auth = self._gss_auth
@@ -7443,6 +7444,8 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
7443
7444
  authentication. If not specified, this value will be the same
7444
7445
  as the `host` argument. If this argument is explicitly set to
7445
7446
  `None`, GSS key exchange and authentication will not be performed.
7447
+ :param gss_store: (optional)
7448
+ The GSS credential store from which to acquire credentials.
7446
7449
  :param gss_kex: (optional)
7447
7450
  Whether or not to allow GSS key exchange. By default, GSS
7448
7451
  key exchange is enabled.
@@ -7672,6 +7675,8 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
7672
7675
  :type kbdint_auth: `bool`
7673
7676
  :type password_auth: `bool`
7674
7677
  :type gss_host: `str`
7678
+ :type gss_store:
7679
+ `str`, `bytes`, or a `dict` with `str` or `bytes` keys and values
7675
7680
  :type gss_kex: `bool`
7676
7681
  :type gss_auth: `bool`
7677
7682
  :type gss_delegate_creds: `bool`
@@ -7734,6 +7739,7 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
7734
7739
  client_certs: Sequence[FilePath]
7735
7740
  ignore_encrypted: bool
7736
7741
  gss_host: DefTuple[Optional[str]]
7742
+ gss_store: Optional[Dict[BytesOrStr, BytesOrStr]]
7737
7743
  gss_kex: bool
7738
7744
  gss_auth: bool
7739
7745
  gss_delegate_creds: bool
@@ -7802,6 +7808,7 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
7802
7808
  passphrase: Optional[BytesOrStr] = None,
7803
7809
  ignore_encrypted: DefTuple[bool] = (),
7804
7810
  gss_host: DefTuple[Optional[str]] = (),
7811
+ gss_store: Optional[Union[BytesOrStr, BytesOrStrDict]] = None,
7805
7812
  gss_kex: DefTuple[bool] = (), gss_auth: DefTuple[bool] = (),
7806
7813
  gss_delegate_creds: DefTuple[bool] = (),
7807
7814
  preferred_auth: DefTuple[Union[str, Sequence[str]]] = (),
@@ -7933,6 +7940,11 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
7933
7940
 
7934
7941
  self.gss_host = gss_host
7935
7942
 
7943
+ if isinstance(gss_store, (bytes, str)):
7944
+ self.gss_store = {'ccache': gss_store}
7945
+ else:
7946
+ self.gss_store = gss_store
7947
+
7936
7948
  self.gss_kex = cast(bool, gss_kex if gss_kex != () else
7937
7949
  config.get('GSSAPIKeyExchange', True))
7938
7950
 
@@ -8169,6 +8181,8 @@ class SSHServerConnectionOptions(SSHConnectionOptions):
8169
8181
  name. Otherwise, the value used by :func:`socket.getfqdn` will be
8170
8182
  used. If this argument is explicitly set to `None`, GSS
8171
8183
  key exchange and authentication will not be performed.
8184
+ :param gss_store: (optional)
8185
+ The GSS credential store from which to acquire credentials.
8172
8186
  :param gss_kex: (optional)
8173
8187
  Whether or not to allow GSS key exchange. By default, GSS
8174
8188
  key exchange is enabled.
@@ -8344,6 +8358,8 @@ class SSHServerConnectionOptions(SSHConnectionOptions):
8344
8358
  :type kbdint_auth: `bool`
8345
8359
  :type password_auth: `bool`
8346
8360
  :type gss_host: `str`
8361
+ :type gss_store:
8362
+ `str`, `bytes`, or a `dict` with `str` or `bytes` keys and values
8347
8363
  :type gss_kex: `bool`
8348
8364
  :type gss_auth: `bool`
8349
8365
  :type allow_pty: `bool`
@@ -8391,6 +8407,7 @@ class SSHServerConnectionOptions(SSHConnectionOptions):
8391
8407
  trust_client_host: bool
8392
8408
  authorized_client_keys: DefTuple[Optional[SSHAuthorizedKeys]]
8393
8409
  gss_host: Optional[str]
8410
+ gss_store: Optional[Dict[BytesOrStr, BytesOrStr]]
8394
8411
  gss_kex: bool
8395
8412
  gss_auth: bool
8396
8413
  allow_pty: bool
@@ -8449,6 +8466,7 @@ class SSHServerConnectionOptions(SSHConnectionOptions):
8449
8466
  trust_client_host: bool = False,
8450
8467
  authorized_client_keys: _AuthKeysArg = (),
8451
8468
  gss_host: DefTuple[Optional[str]] = (),
8469
+ gss_store: Optional[Union[BytesOrStr, BytesOrStrDict]] = None,
8452
8470
  gss_kex: DefTuple[bool] = (),
8453
8471
  gss_auth: DefTuple[bool] = (),
8454
8472
  allow_pty: DefTuple[bool] = (),
@@ -8554,6 +8572,11 @@ class SSHServerConnectionOptions(SSHConnectionOptions):
8554
8572
 
8555
8573
  self.gss_host = gss_host
8556
8574
 
8575
+ if isinstance(gss_store, (bytes, str)):
8576
+ self.gss_store = {'ccache': gss_store}
8577
+ else:
8578
+ self.gss_store = gss_store
8579
+
8557
8580
  self.gss_kex = cast(bool, gss_kex if gss_kex != () else
8558
8581
  config.get('GSSAPIKeyExchange', True))
8559
8582
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2023 by Ron Frederick <ronf@timeheart.net> and others.
1
+ # Copyright (c) 2017-2024 by Ron Frederick <ronf@timeheart.net> and others.
2
2
  #
3
3
  # This program and the accompanying materials are made available under
4
4
  # the terms of the Eclipse Public License v2.0 which accompanies this
@@ -24,6 +24,9 @@ import sys
24
24
 
25
25
  from typing import Optional
26
26
 
27
+ from .misc import BytesOrStrDict
28
+
29
+
27
30
  try:
28
31
  # pylint: disable=unused-import
29
32
 
@@ -53,11 +56,12 @@ except ImportError: # pragma: no cover
53
56
  class GSSClient(GSSBase): # type: ignore
54
57
  """Stub client class for reporting that GSS is not available"""
55
58
 
56
- def __init__(self, _host: str, _delegate_creds: bool):
59
+ def __init__(self, _host: str, _store: Optional[BytesOrStrDict],
60
+ _delegate_creds: bool):
57
61
  raise GSSError(0, 0)
58
62
 
59
63
  class GSSServer(GSSBase): # type: ignore
60
64
  """Stub client class for reporting that GSS is not available"""
61
65
 
62
- def __init__(self, _host: str):
66
+ def __init__(self, _host: str, _store: Optional[BytesOrStrDict]):
63
67
  raise GSSError(0, 0)
@@ -27,6 +27,7 @@ from gssapi import RequirementFlag, SecurityContext
27
27
  from gssapi.exceptions import GSSError
28
28
 
29
29
  from .asn1 import OBJECT_IDENTIFIER
30
+ from .misc import BytesOrStrDict
30
31
 
31
32
 
32
33
  def _mech_to_oid(mech: OID) -> bytes:
@@ -39,12 +40,14 @@ def _mech_to_oid(mech: OID) -> bytes:
39
40
  class GSSBase:
40
41
  """GSS base class"""
41
42
 
42
- def __init__(self, host: str):
43
+ def __init__(self, host: str, store: Optional[BytesOrStrDict]):
43
44
  if '@' in host:
44
45
  self._host = Name(host)
45
46
  else:
46
47
  self._host = Name('host@' + host, NameType.hostbased_service)
47
48
 
49
+ self._store = store
50
+
48
51
  self._mechs = [_mech_to_oid(mech) for mech in self._creds.mechs]
49
52
  self._ctx: Optional[SecurityContext] = None
50
53
 
@@ -141,8 +144,9 @@ class GSSBase:
141
144
  class GSSClient(GSSBase):
142
145
  """GSS client"""
143
146
 
144
- def __init__(self, host: str, delegate_creds: bool):
145
- super().__init__(host)
147
+ def __init__(self, host: str, store: Optional[BytesOrStrDict],
148
+ delegate_creds: bool):
149
+ super().__init__(host, store)
146
150
 
147
151
  flags = RequirementFlag.mutual_authentication | \
148
152
  RequirementFlag.integrity
@@ -156,7 +160,7 @@ class GSSClient(GSSBase):
156
160
  def _creds(self) -> Credentials:
157
161
  """Abstract method to construct GSS credentials"""
158
162
 
159
- return Credentials(usage='initiate')
163
+ return Credentials(usage='initiate', store=self._store)
160
164
 
161
165
  def _init_context(self) -> None:
162
166
  """Construct GSS client security context"""
@@ -172,7 +176,7 @@ class GSSServer(GSSBase):
172
176
  def _creds(self) -> Credentials:
173
177
  """Abstract method to construct GSS credentials"""
174
178
 
175
- return Credentials(name=self._host, usage='accept')
179
+ return Credentials(name=self._host, usage='accept', store=self._store)
176
180
 
177
181
  def _init_context(self) -> None:
178
182
  """Construct GSS server security context"""
@@ -35,6 +35,7 @@ from sspicon import ASC_RET_INTEGRITY, ASC_RET_MUTUAL_AUTH
35
35
  from sspicon import SECPKG_ATTR_NATIVE_NAMES
36
36
 
37
37
  from .asn1 import ObjectIdentifier, der_encode
38
+ from .misc import BytesOrStrDict
38
39
 
39
40
 
40
41
  _krb5_oid = der_encode(ObjectIdentifier('1.2.840.113554.1.2.2'))
@@ -156,7 +157,11 @@ class GSSClient(GSSBase):
156
157
  _mutual_auth_flag = ISC_RET_MUTUAL_AUTH
157
158
  _integrity_flag = ISC_RET_INTEGRITY
158
159
 
159
- def __init__(self, host: str, delegate_creds: bool):
160
+ def __init__(self, host: str, store: Optional[BytesOrStrDict],
161
+ delegate_creds: bool):
162
+ if store is not None:
163
+ raise GSSError(details='GSS store not supported on Windows')
164
+
160
165
  super().__init__(host)
161
166
 
162
167
  flags = ISC_REQ_MUTUAL_AUTH | ISC_REQ_INTEGRITY
@@ -179,7 +184,10 @@ class GSSServer(GSSBase):
179
184
  _mutual_auth_flag = ASC_RET_MUTUAL_AUTH
180
185
  _integrity_flag = ASC_RET_INTEGRITY
181
186
 
182
- def __init__(self, host: str):
187
+ def __init__(self, host: str, store: Optional[BytesOrStrDict]):
188
+ if store is not None:
189
+ raise GSSError(details='GSS store not supported on Windows')
190
+
183
191
  super().__init__(host)
184
192
 
185
193
  flags = ASC_REQ_MUTUAL_AUTH | ASC_REQ_INTEGRITY
@@ -25,7 +25,7 @@ import errno
25
25
  import socket
26
26
  from types import TracebackType
27
27
  from typing import TYPE_CHECKING, AnyStr, Callable, Generic, List, Optional
28
- from typing import Sequence, Tuple, Type, Union
28
+ from typing import Sequence, Set, Tuple, Type, Union
29
29
  from typing_extensions import Self
30
30
 
31
31
  from .forward import SSHForwarderCoro
@@ -285,9 +285,19 @@ async def create_tcp_local_listener(
285
285
  if not addrinfo: # pragma: no cover
286
286
  raise OSError('getaddrinfo() returned empty list')
287
287
 
288
+ seen_addrinfo: Set[Tuple] = set()
288
289
  servers: List[asyncio.AbstractServer] = []
289
290
 
290
- for family, socktype, proto, _, sa in addrinfo:
291
+ for addrinfo_entry in addrinfo:
292
+ # Work around an issue where getaddrinfo() on some systems may
293
+ # return duplicate results, causing bind to fail.
294
+ if addrinfo_entry in seen_addrinfo: # pragma: no cover
295
+ continue
296
+
297
+ seen_addrinfo.add(addrinfo_entry)
298
+
299
+ family, socktype, proto, _, sa = addrinfo_entry
300
+
291
301
  try:
292
302
  sock = socket.socket(family, socktype, proto)
293
303
  except OSError: # pragma: no cover
@@ -101,6 +101,7 @@ ExcInfo = Tuple[Type[BaseException], BaseException, TracebackType]
101
101
  OptExcInfo = Union[ExcInfo, Tuple[None, None, None]]
102
102
 
103
103
  BytesOrStr = Union[bytes, str]
104
+ BytesOrStrDict = Dict[BytesOrStr, BytesOrStr]
104
105
  FilePath = Union[str, PurePath]
105
106
  HostPort = Tuple[str, int]
106
107
  IPAddress = Union[ipaddress.IPv4Address, ipaddress.IPv6Address]
@@ -2541,7 +2541,7 @@ def _decode_openssh_private(
2541
2541
  'encrypted private keys')
2542
2542
 
2543
2543
  try:
2544
- key_size, iv_size, block_size, _, _, _ = \
2544
+ key_size, iv_size, _, _, _, _ = \
2545
2545
  get_encryption_params(cipher_name)
2546
2546
  except KeyError:
2547
2547
  raise KeyEncryptionError('Unknown cipher: %s' %
@@ -2579,9 +2579,6 @@ def _decode_openssh_private(
2579
2579
  raise KeyEncryptionError('Incorrect passphrase')
2580
2580
 
2581
2581
  key_data = decrypted_key
2582
- block_size = max(block_size, 8)
2583
- else:
2584
- block_size = 8
2585
2582
 
2586
2583
  packet = SSHPacket(key_data)
2587
2584
 
@@ -2602,7 +2599,7 @@ def _decode_openssh_private(
2602
2599
  comment = packet.get_string()
2603
2600
  pad = packet.get_remaining_payload()
2604
2601
 
2605
- if len(pad) >= block_size or pad != bytes(range(1, len(pad) + 1)):
2602
+ if len(pad) >= 256 or pad != bytes(range(1, len(pad) + 1)):
2606
2603
  raise KeyImportError('Invalid OpenSSH private key')
2607
2604
 
2608
2605
  if alg == b'ssh-rsa':
@@ -59,6 +59,14 @@ class SSHServer:
59
59
  Applications may subclass this when implementing an SSH server to
60
60
  provide custom authentication and request handlers.
61
61
 
62
+ Whenever a new SSH server connection is accepted, a corresponding
63
+ SSHServer object is created and the method :meth:`connection_made`
64
+ is called, passing in the :class:`SSHServerConnection` object.
65
+
66
+ When the connection is closed, the method :meth:`connection_lost`
67
+ is called with an exception representing the reason for the
68
+ disconnect, or `None` if the connection was closed cleanly.
69
+
62
70
  The method :meth:`begin_auth` can be overridden decide whether
63
71
  or not authentication is required, and additional callbacks are
64
72
  provided for each form of authentication in cases where authentication
@@ -26,4 +26,4 @@ __author_email__ = 'ronf@timeheart.net'
26
26
 
27
27
  __url__ = 'http://asyncssh.timeheart.net'
28
28
 
29
- __version__ = '2.16.0'
29
+ __version__ = '2.17.0'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: asyncssh
3
- Version: 2.16.0
3
+ Version: 2.17.0
4
4
  Summary: AsyncSSH: Asynchronous SSHv2 client and server library
5
5
  Home-page: http://asyncssh.timeheart.net
6
6
  Author: Ron Frederick
@@ -27,23 +27,14 @@ Classifier: Topic :: Security :: Cryptography
27
27
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
28
28
  Classifier: Topic :: System :: Networking
29
29
  Requires-Python: >= 3.6
30
- License-File: LICENSE
31
- Requires-Dist: cryptography>=39.0
32
- Requires-Dist: typing_extensions>=4.0.0
33
30
  Provides-Extra: bcrypt
34
- Requires-Dist: bcrypt>=3.1.3; extra == "bcrypt"
35
31
  Provides-Extra: fido2
36
- Requires-Dist: fido2>=0.9.2; extra == "fido2"
37
32
  Provides-Extra: gssapi
38
- Requires-Dist: gssapi>=1.2.0; extra == "gssapi"
39
33
  Provides-Extra: libnacl
40
- Requires-Dist: libnacl>=1.4.2; extra == "libnacl"
41
34
  Provides-Extra: pkcs11
42
- Requires-Dist: python-pkcs11>=0.7.0; extra == "pkcs11"
43
- Provides-Extra: pyopenssl
44
- Requires-Dist: pyOpenSSL>=23.0.0; extra == "pyopenssl"
35
+ Provides-Extra: pyOpenSSL
45
36
  Provides-Extra: pywin32
46
- Requires-Dist: pywin32>=227; extra == "pywin32"
37
+ License-File: LICENSE
47
38
 
48
39
  .. image:: https://readthedocs.org/projects/asyncssh/badge/?version=latest
49
40
  :target: https://asyncssh.readthedocs.io/en/latest/?badge=latest
@@ -276,3 +267,5 @@ Three mailing lists are available for AsyncSSH:
276
267
  __ http://groups.google.com/d/forum/asyncssh-announce
277
268
  __ http://groups.google.com/d/forum/asyncssh-dev
278
269
  __ http://groups.google.com/d/forum/asyncssh-users
270
+
271
+
@@ -3,6 +3,32 @@
3
3
  Change Log
4
4
  ==========
5
5
 
6
+ Release 2.17.0 (2 Sep 2024)
7
+ ---------------------------
8
+
9
+ * Add support for specifying a per-connection credential store for GSSAPI
10
+ authentication. Thanks go to GitHub user zarganum for suggesting this
11
+ feature and proposing a detailed design.
12
+
13
+ * Fixed a regression introduced in AsyncSSH 2.15.0 which could cause
14
+ connections to be closed with an uncaught exception when a session
15
+ on the connection was closed. Thanks go to Wilson Conley for being
16
+ the first to help reproduce this issue, and others who also helped
17
+ to confirm the fix.
18
+
19
+ * Added a workaround where getaddrinfo() on some systems may return duplicate
20
+ entries, causing bind() to fail when opening a listener. Thanks go to
21
+ Colin Watson for reporting this issue and suggesting a fix.
22
+
23
+ * Relaxed padding length check on OpenSSH private keys to provide better
24
+ compatibility with keys generated by PuTTYgen.
25
+
26
+ * Improved documentation on SSHClient and SSHServer classes to explain
27
+ when they are created and their relationship to the SSHClientConnection
28
+ and SSHServerConnection classes.
29
+
30
+ * Updated examples to use Python 3.7 and made some minor improvements.
31
+
6
32
  Release 2.16.0 (17 Aug 2024)
7
33
  ----------------------------
8
34
 
@@ -1,6 +1,6 @@
1
- #!/usr/bin/env python3.6
1
+ #!/usr/bin/env python3.7
2
2
  #
3
- # Copyright (c) 2013-2021 by Ron Frederick <ronf@timeheart.net> and others.
3
+ # Copyright (c) 2013-2024 by Ron Frederick <ronf@timeheart.net> and others.
4
4
  #
5
5
  # This program and the accompanying materials are made available under
6
6
  # the terms of the Eclipse Public License v2.0 which accompanies this
@@ -46,6 +46,6 @@ async def run_client() -> None:
46
46
  await chan.wait_closed()
47
47
 
48
48
  try:
49
- asyncio.get_event_loop().run_until_complete(run_client())
49
+ asyncio.run(run_client())
50
50
  except (OSError, asyncssh.Error) as exc:
51
51
  sys.exit('SSH connection failed: ' + str(exc))
@@ -1,6 +1,6 @@
1
- #!/usr/bin/env python3.6
1
+ #!/usr/bin/env python3.7
2
2
  #
3
- # Copyright (c) 2013-2021 by Ron Frederick <ronf@timeheart.net> and others.
3
+ # Copyright (c) 2013-2024 by Ron Frederick <ronf@timeheart.net> and others.
4
4
  #
5
5
  # This program and the accompanying materials are made available under
6
6
  # the terms of the Eclipse Public License v2.0 which accompanies this
@@ -37,6 +37,6 @@ async def run_client() -> None:
37
37
  await chan.wait_closed()
38
38
 
39
39
  try:
40
- asyncio.get_event_loop().run_until_complete(run_client())
40
+ asyncio.run(run_client())
41
41
  except (OSError, asyncssh.Error) as exc:
42
42
  sys.exit('SSH connection failed: ' + str(exc))
@@ -1,6 +1,6 @@
1
- #!/usr/bin/env python3.6
1
+ #!/usr/bin/env python3.7
2
2
  #
3
- # Copyright (c) 2013-2021 by Ron Frederick <ronf@timeheart.net> and others.
3
+ # Copyright (c) 2013-2024 by Ron Frederick <ronf@timeheart.net> and others.
4
4
  #
5
5
  # This program and the accompanying materials are made available under
6
6
  # the terms of the Eclipse Public License v2.0 which accompanies this
@@ -40,6 +40,6 @@ async def run_client() -> None:
40
40
  await chan.wait_closed()
41
41
 
42
42
  try:
43
- asyncio.get_event_loop().run_until_complete(run_client())
43
+ asyncio.run(run_client())
44
44
  except (OSError, asyncssh.Error) as exc:
45
45
  sys.exit('SSH connection failed: ' + str(exc))
@@ -1,6 +1,6 @@
1
- #!/usr/bin/env python3.6
1
+ #!/usr/bin/env python3.7
2
2
  #
3
- # Copyright (c) 2013-2021 by Ron Frederick <ronf@timeheart.net> and others.
3
+ # Copyright (c) 2013-2024 by Ron Frederick <ronf@timeheart.net> and others.
4
4
  #
5
5
  # This program and the accompanying materials are made available under
6
6
  # the terms of the Eclipse Public License v2.0 which accompanies this
@@ -64,6 +64,9 @@ class MySSHServerSession(asyncssh.SSHServerSession):
64
64
  def break_received(self, msec: int) -> bool:
65
65
  return self.eof_received()
66
66
 
67
+ def soft_eof_received(self) -> None:
68
+ self.eof_received()
69
+
67
70
  class MySSHServer(asyncssh.SSHServer):
68
71
  def session_requested(self) -> asyncssh.SSHServerSession:
69
72
  return MySSHServerSession()
@@ -73,7 +76,7 @@ async def start_server() -> None:
73
76
  server_host_keys=['ssh_host_key'],
74
77
  authorized_client_keys='ssh_user_ca')
75
78
 
76
- loop = asyncio.get_event_loop()
79
+ loop = asyncio.new_event_loop()
77
80
 
78
81
  try:
79
82
  loop.run_until_complete(start_server())
@@ -1,6 +1,6 @@
1
- #!/usr/bin/env python3.6
1
+ #!/usr/bin/env python3.7
2
2
  #
3
- # Copyright (c) 2016-2021 by Ron Frederick <ronf@timeheart.net> and others.
3
+ # Copyright (c) 2016-2024 by Ron Frederick <ronf@timeheart.net> and others.
4
4
  #
5
5
  # This program and the accompanying materials are made available under
6
6
  # the terms of the Eclipse Public License v2.0 which accompanies this
@@ -76,7 +76,7 @@ async def start_server() -> None:
76
76
  authorized_client_keys='ssh_user_ca',
77
77
  process_factory=ChatClient.handle_client)
78
78
 
79
- loop = asyncio.get_event_loop()
79
+ loop = asyncio.new_event_loop()
80
80
 
81
81
  try:
82
82
  loop.run_until_complete(start_server())
@@ -1,6 +1,6 @@
1
- #!/usr/bin/env python3.6
1
+ #!/usr/bin/env python3.7
2
2
  #
3
- # Copyright (c) 2013-2021 by Ron Frederick <ronf@timeheart.net> and others.
3
+ # Copyright (c) 2013-2024 by Ron Frederick <ronf@timeheart.net> and others.
4
4
  #
5
5
  # This program and the accompanying materials are made available under
6
6
  # the terms of the Eclipse Public License v2.0 which accompanies this
@@ -34,6 +34,6 @@ async def run_client() -> None:
34
34
  file=sys.stderr)
35
35
 
36
36
  try:
37
- asyncio.get_event_loop().run_until_complete(run_client())
37
+ asyncio.run(run_client())
38
38
  except (OSError, asyncssh.Error) as exc:
39
39
  sys.exit('SSH connection failed: ' + str(exc))
@@ -1,6 +1,6 @@
1
- #!/usr/bin/env python3.6
1
+ #!/usr/bin/env python3.7
2
2
  #
3
- # Copyright (c) 2016-2021 by Ron Frederick <ronf@timeheart.net> and others.
3
+ # Copyright (c) 2016-2024 by Ron Frederick <ronf@timeheart.net> and others.
4
4
  #
5
5
  # This program and the accompanying materials are made available under
6
6
  # the terms of the Eclipse Public License v2.0 which accompanies this
@@ -40,7 +40,7 @@ async def start_server() -> None:
40
40
  authorized_client_keys='ssh_user_ca',
41
41
  sftp_factory=MySFTPServer)
42
42
 
43
- loop = asyncio.get_event_loop()
43
+ loop = asyncio.new_event_loop()
44
44
 
45
45
  try:
46
46
  loop.run_until_complete(start_server())
@@ -1,6 +1,6 @@
1
- #!/usr/bin/env python3.6
1
+ #!/usr/bin/env python3.7
2
2
  #
3
- # Copyright (c) 2013-2021 by Ron Frederick <ronf@timeheart.net> and others.
3
+ # Copyright (c) 2013-2024 by Ron Frederick <ronf@timeheart.net> and others.
4
4
  #
5
5
  # This program and the accompanying materials are made available under
6
6
  # the terms of the Eclipse Public License v2.0 which accompanies this
@@ -44,6 +44,6 @@ async def run_client() -> None:
44
44
  await chan.wait_closed()
45
45
 
46
46
  try:
47
- asyncio.get_event_loop().run_until_complete(run_client())
47
+ asyncio.run(run_client())
48
48
  except (OSError, asyncssh.Error) as exc:
49
49
  sys.exit('SSH connection failed: ' + str(exc))
@@ -1,6 +1,6 @@
1
- #!/usr/bin/env python3.6
1
+ #!/usr/bin/env python3.7
2
2
  #
3
- # Copyright (c) 2013-2021 by Ron Frederick <ronf@timeheart.net> and others.
3
+ # Copyright (c) 2013-2024 by Ron Frederick <ronf@timeheart.net> and others.
4
4
  #
5
5
  # This program and the accompanying materials are made available under
6
6
  # the terms of the Eclipse Public License v2.0 which accompanies this
@@ -52,7 +52,7 @@ async def start_server() -> None:
52
52
  server_host_keys=['ssh_host_key'],
53
53
  authorized_client_keys='ssh_user_ca')
54
54
 
55
- loop = asyncio.get_event_loop()
55
+ loop = asyncio.new_event_loop()
56
56
 
57
57
  try:
58
58
  loop.run_until_complete(start_server())