asyncssh 2.14.2__tar.gz → 2.16.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.14.2 → asyncssh-2.16.0}/.github/workflows/run_tests.yml +26 -10
  2. {asyncssh-2.14.2 → asyncssh-2.16.0}/CONTRIBUTING.rst +9 -10
  3. {asyncssh-2.14.2 → asyncssh-2.16.0}/PKG-INFO +13 -5
  4. {asyncssh-2.14.2 → asyncssh-2.16.0}/README.rst +1 -0
  5. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/__init__.py +18 -17
  6. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/agent.py +3 -3
  7. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/agent_unix.py +1 -1
  8. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/agent_win32.py +1 -1
  9. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/channel.py +75 -18
  10. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/client.py +1 -1
  11. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/config.py +16 -7
  12. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/connection.py +716 -170
  13. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/crypto/cipher.py +48 -30
  14. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/crypto/x509.py +2 -1
  15. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/dsa.py +1 -1
  16. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/ecdsa.py +1 -1
  17. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/editor.py +1 -1
  18. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/encryption.py +1 -1
  19. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/forward.py +33 -3
  20. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/gss_unix.py +1 -1
  21. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/kex.py +1 -1
  22. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/kex_dh.py +1 -1
  23. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/kex_rsa.py +1 -1
  24. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/listener.py +3 -2
  25. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/logging.py +22 -12
  26. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/misc.py +39 -1
  27. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/process.py +115 -32
  28. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/public_key.py +34 -7
  29. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/rsa.py +1 -1
  30. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/saslprep.py +4 -2
  31. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/scp.py +23 -9
  32. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/server.py +122 -1
  33. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/session.py +41 -8
  34. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/sftp.py +205 -94
  35. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/stream.py +54 -12
  36. asyncssh-2.16.0/asyncssh/tuntap.py +431 -0
  37. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/version.py +2 -2
  38. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh.egg-info/PKG-INFO +13 -5
  39. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh.egg-info/SOURCES.txt +2 -0
  40. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh.egg-info/requires.txt +1 -1
  41. {asyncssh-2.14.2 → asyncssh-2.16.0}/docs/api.rst +122 -339
  42. {asyncssh-2.14.2 → asyncssh-2.16.0}/docs/changes.rst +102 -1
  43. {asyncssh-2.14.2 → asyncssh-2.16.0}/docs/index.rst +20 -1
  44. {asyncssh-2.14.2 → asyncssh-2.16.0}/mypy.ini +0 -1
  45. {asyncssh-2.14.2 → asyncssh-2.16.0}/setup.py +3 -1
  46. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_agent.py +2 -2
  47. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_channel.py +44 -1
  48. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_config.py +19 -2
  49. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_connection.py +141 -3
  50. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_connection_auth.py +80 -0
  51. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_forward.py +30 -12
  52. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_process.py +126 -30
  53. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_sftp.py +158 -3
  54. asyncssh-2.16.0/tests/test_tuntap.py +703 -0
  55. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/util.py +9 -0
  56. {asyncssh-2.14.2 → asyncssh-2.16.0}/.coveragerc +0 -0
  57. {asyncssh-2.14.2 → asyncssh-2.16.0}/.gitignore +0 -0
  58. {asyncssh-2.14.2 → asyncssh-2.16.0}/.readthedocs.yaml +0 -0
  59. {asyncssh-2.14.2 → asyncssh-2.16.0}/COPYRIGHT +0 -0
  60. {asyncssh-2.14.2 → asyncssh-2.16.0}/LICENSE +0 -0
  61. {asyncssh-2.14.2 → asyncssh-2.16.0}/MANIFEST.in +0 -0
  62. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/asn1.py +0 -0
  63. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/auth.py +0 -0
  64. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/auth_keys.py +0 -0
  65. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/compression.py +0 -0
  66. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/constants.py +0 -0
  67. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/crypto/__init__.py +0 -0
  68. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/crypto/chacha.py +0 -0
  69. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/crypto/dh.py +0 -0
  70. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/crypto/dsa.py +0 -0
  71. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/crypto/ec.py +0 -0
  72. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/crypto/ec_params.py +0 -0
  73. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/crypto/ed.py +0 -0
  74. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/crypto/kdf.py +0 -0
  75. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/crypto/misc.py +0 -0
  76. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/crypto/rsa.py +0 -0
  77. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/crypto/sntrup.py +0 -0
  78. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/crypto/umac.py +0 -0
  79. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/eddsa.py +0 -0
  80. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/gss.py +0 -0
  81. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/gss_win32.py +0 -0
  82. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/keysign.py +0 -0
  83. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/known_hosts.py +0 -0
  84. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/mac.py +0 -0
  85. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/packet.py +0 -0
  86. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/pattern.py +0 -0
  87. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/pbe.py +0 -0
  88. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/pkcs11.py +0 -0
  89. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/py.typed +0 -0
  90. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/sk.py +0 -0
  91. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/sk_ecdsa.py +0 -0
  92. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/sk_eddsa.py +0 -0
  93. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/socks.py +0 -0
  94. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/subprocess.py +0 -0
  95. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh/x11.py +0 -0
  96. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh.egg-info/dependency_links.txt +0 -0
  97. {asyncssh-2.14.2 → asyncssh-2.16.0}/asyncssh.egg-info/top_level.txt +0 -0
  98. {asyncssh-2.14.2 → asyncssh-2.16.0}/docs/_templates/sidebarbottom.html +0 -0
  99. {asyncssh-2.14.2 → asyncssh-2.16.0}/docs/_templates/sidebartop.html +0 -0
  100. {asyncssh-2.14.2 → asyncssh-2.16.0}/docs/conf.py +0 -0
  101. {asyncssh-2.14.2 → asyncssh-2.16.0}/docs/contributing.rst +0 -0
  102. {asyncssh-2.14.2 → asyncssh-2.16.0}/docs/requirements.txt +0 -0
  103. {asyncssh-2.14.2 → asyncssh-2.16.0}/docs/rftheme/layout.html +0 -0
  104. {asyncssh-2.14.2 → asyncssh-2.16.0}/docs/rftheme/static/rftheme.css_t +0 -0
  105. {asyncssh-2.14.2 → asyncssh-2.16.0}/docs/rftheme/theme.conf +0 -0
  106. {asyncssh-2.14.2 → asyncssh-2.16.0}/docs/rtd-req.txt +0 -0
  107. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/callback_client.py +0 -0
  108. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/callback_client2.py +0 -0
  109. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/callback_client3.py +0 -0
  110. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/callback_math_server.py +0 -0
  111. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/chat_server.py +0 -0
  112. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/check_exit_status.py +0 -0
  113. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/chroot_sftp_server.py +0 -0
  114. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/direct_client.py +0 -0
  115. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/direct_server.py +0 -0
  116. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/editor.py +0 -0
  117. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/gather_results.py +0 -0
  118. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/listening_client.py +0 -0
  119. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/local_forwarding_client.py +0 -0
  120. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/local_forwarding_client2.py +0 -0
  121. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/local_forwarding_server.py +0 -0
  122. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/math_client.py +0 -0
  123. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/math_server.py +0 -0
  124. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/redirect_input.py +0 -0
  125. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/redirect_local_pipe.py +0 -0
  126. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/redirect_remote_pipe.py +0 -0
  127. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/redirect_server.py +0 -0
  128. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/remote_forwarding_client.py +0 -0
  129. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/remote_forwarding_client2.py +0 -0
  130. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/remote_forwarding_server.py +0 -0
  131. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/reverse_client.py +0 -0
  132. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/reverse_server.py +0 -0
  133. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/scp_client.py +0 -0
  134. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/set_environment.py +0 -0
  135. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/set_terminal.py +0 -0
  136. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/sftp_client.py +0 -0
  137. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/show_environment.py +0 -0
  138. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/show_terminal.py +0 -0
  139. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/simple_cert_server.py +0 -0
  140. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/simple_client.py +0 -0
  141. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/simple_keyed_server.py +0 -0
  142. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/simple_scp_server.py +0 -0
  143. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/simple_server.py +0 -0
  144. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/simple_sftp_server.py +0 -0
  145. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/stream_direct_client.py +0 -0
  146. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/stream_direct_server.py +0 -0
  147. {asyncssh-2.14.2 → asyncssh-2.16.0}/examples/stream_listening_client.py +0 -0
  148. {asyncssh-2.14.2 → asyncssh-2.16.0}/pylintrc +0 -0
  149. {asyncssh-2.14.2 → asyncssh-2.16.0}/setup.cfg +0 -0
  150. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/__init__.py +0 -0
  151. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/gss_stub.py +0 -0
  152. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/gssapi_stub.py +0 -0
  153. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/keysign_stub.py +0 -0
  154. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/pkcs11_stub.py +0 -0
  155. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/server.py +0 -0
  156. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/sk_stub.py +0 -0
  157. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/sspi_stub.py +0 -0
  158. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_asn1.py +0 -0
  159. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_auth.py +0 -0
  160. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_auth_keys.py +0 -0
  161. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_compression.py +0 -0
  162. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_editor.py +0 -0
  163. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_encryption.py +0 -0
  164. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_kex.py +0 -0
  165. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_known_hosts.py +0 -0
  166. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_logging.py +0 -0
  167. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_mac.py +0 -0
  168. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_packet.py +0 -0
  169. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_pkcs11.py +0 -0
  170. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_public_key.py +0 -0
  171. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_saslprep.py +0 -0
  172. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_sk.py +0 -0
  173. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_stream.py +0 -0
  174. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_subprocess.py +0 -0
  175. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_x11.py +0 -0
  176. {asyncssh-2.14.2 → asyncssh-2.16.0}/tests/test_x509.py +0 -0
  177. {asyncssh-2.14.2 → asyncssh-2.16.0}/tox.ini +0 -0
@@ -20,6 +20,10 @@ jobs:
20
20
  python-version: "3.12"
21
21
  openssl-version: "3"
22
22
  exclude:
23
+ # having trouble with arch arm64 on macos-ltest on Python 3.7
24
+ - os: macos-latest
25
+ python-version: "3.7"
26
+
23
27
  # test hangs on these combination
24
28
  - os: windows-latest
25
29
  python-version: "3.8"
@@ -39,19 +43,19 @@ jobs:
39
43
 
40
44
  steps:
41
45
  - name: Checkout asyncssh
42
- uses: actions/checkout@v3
46
+ uses: actions/checkout@v4
43
47
  with:
44
48
  path: asyncssh
45
49
 
46
50
  - name: Checkout liboqs
47
51
  if: ${{ runner.os != 'macOS' }}
48
- uses: actions/checkout@v3
52
+ uses: actions/checkout@v4
49
53
  with:
50
54
  repository: open-quantum-safe/liboqs
51
55
  ref: ${{ env.liboqs_version }}
52
56
  path: liboqs
53
57
 
54
- - uses: actions/setup-python@v4
58
+ - uses: actions/setup-python@v5
55
59
  with:
56
60
  python-version: ${{ matrix.python-version }}
57
61
  cache: pip
@@ -122,23 +126,34 @@ jobs:
122
126
  check=True)
123
127
 
124
128
  - name: Upload coverage data
125
- uses: actions/upload-artifact@v3
129
+ uses: actions/upload-artifact@v4
126
130
  with:
127
- name: coverage
131
+ name: coverage-${{ matrix.os }}-${{ matrix.python-version }}
128
132
  path: asyncssh/.coverage.*
129
133
  retention-days: 1
130
134
 
135
+ merge-coverage:
136
+ runs-on: ubuntu-latest
137
+ needs: run-tests
138
+ if: ${{ always() }}
139
+ steps:
140
+ - name: Merge coverage
141
+ uses: actions/upload-artifact/merge@v4
142
+ with:
143
+ name: coverage
144
+ pattern: coverage-*
145
+
131
146
  report-coverage:
132
147
  name: Report coverage
133
148
  runs-on: ubuntu-latest
134
- needs: run-tests
149
+ needs: merge-coverage
135
150
  if: ${{ always() }}
136
151
  steps:
137
- - uses: actions/checkout@v3
138
- - uses: actions/setup-python@v4
152
+ - uses: actions/checkout@v4
153
+ - uses: actions/setup-python@v5
139
154
  with:
140
155
  python-version: "3.7"
141
- - uses: actions/download-artifact@v3
156
+ - uses: actions/download-artifact@v4
142
157
  with:
143
158
  name: coverage
144
159
  - name: Install dependencies
@@ -152,6 +167,7 @@ jobs:
152
167
  sqlite3 "$f" "update file set path = replace(path, '\\', '/');"
153
168
  done
154
169
  tox -e report
155
- - uses: codecov/codecov-action@v3
170
+ - uses: codecov/codecov-action@v4
156
171
  with:
157
172
  files: coverage.xml
173
+ token: ${{ secrets.CODECOV_TOKEN }}
@@ -68,19 +68,18 @@ contributors list.
68
68
  Branches
69
69
  --------
70
70
 
71
- There are two long-lived branches in AsyncSSH at the moment:
71
+ There are two long-lived branches in AsyncSSH:
72
72
 
73
73
  * The master branch is intended to contain the latest stable version
74
74
  of the code. All official versions of AsyncSSH are released from
75
75
  this branch, and each release has a corresponding tag added
76
- matching its release number. Bug fixes and simple improvements
77
- may be checked directly into this branch, but most new features
78
- will be added to the develop branch first.
79
-
80
- * The develop branch is intended to contain features for developers
81
- to test before they are ready to be added to an official release.
82
- APIs in the develop branch may be subject to change until they
83
- are migrated back to master, and there's no guarantee of backward
76
+ matching its release number.
77
+
78
+ * The develop branch is intended to contain new features and bug fixes
79
+ ready to be tested before being added to an official release. APIs
80
+ in the develop branch may be subject to change until they are
81
+ migrated back to master, and there's no guarantee of backward
84
82
  compatibility in this branch. However, pulling from this branch
85
83
  will provide early access to new functionality and a chance to
86
- influence this functionality before it is released.
84
+ influence this functionality before it is released. Also, all
85
+ pull requests should be submitted against this branch.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: asyncssh
3
- Version: 2.14.2
3
+ Version: 2.16.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,14 +27,23 @@ 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
30
33
  Provides-Extra: bcrypt
34
+ Requires-Dist: bcrypt>=3.1.3; extra == "bcrypt"
31
35
  Provides-Extra: fido2
36
+ Requires-Dist: fido2>=0.9.2; extra == "fido2"
32
37
  Provides-Extra: gssapi
38
+ Requires-Dist: gssapi>=1.2.0; extra == "gssapi"
33
39
  Provides-Extra: libnacl
40
+ Requires-Dist: libnacl>=1.4.2; extra == "libnacl"
34
41
  Provides-Extra: pkcs11
35
- Provides-Extra: pyOpenSSL
42
+ Requires-Dist: python-pkcs11>=0.7.0; extra == "pkcs11"
43
+ Provides-Extra: pyopenssl
44
+ Requires-Dist: pyOpenSSL>=23.0.0; extra == "pyopenssl"
36
45
  Provides-Extra: pywin32
37
- License-File: LICENSE
46
+ Requires-Dist: pywin32>=227; extra == "pywin32"
38
47
 
39
48
  .. image:: https://readthedocs.org/projects/asyncssh/badge/?version=latest
40
49
  :target: https://asyncssh.readthedocs.io/en/latest/?badge=latest
@@ -79,6 +88,7 @@ Features
79
88
  * Environment variables, terminal type, and window size
80
89
  * Direct and forwarded TCP/IP channels
81
90
  * OpenSSH-compatible direct and forwarded UNIX domain socket channels
91
+ * OpenSSH-compatible TUN/TAP channels and packet forwarding
82
92
  * Local and remote TCP/IP port forwarding
83
93
  * Local and remote UNIX domain socket forwarding
84
94
  * Dynamic TCP/IP port forwarding via SOCKS
@@ -266,5 +276,3 @@ Three mailing lists are available for AsyncSSH:
266
276
  __ http://groups.google.com/d/forum/asyncssh-announce
267
277
  __ http://groups.google.com/d/forum/asyncssh-dev
268
278
  __ http://groups.google.com/d/forum/asyncssh-users
269
-
270
-
@@ -41,6 +41,7 @@ Features
41
41
  * Environment variables, terminal type, and window size
42
42
  * Direct and forwarded TCP/IP channels
43
43
  * OpenSSH-compatible direct and forwarded UNIX domain socket channels
44
+ * OpenSSH-compatible TUN/TAP channels and packet forwarding
44
45
  * Local and remote TCP/IP port forwarding
45
46
  * Local and remote UNIX domain socket forwarding
46
47
  * Dynamic TCP/IP port forwarding via SOCKS
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2013-2022 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
@@ -34,7 +34,7 @@ from .auth_keys import SSHAuthorizedKeys
34
34
  from .auth_keys import import_authorized_keys, read_authorized_keys
35
35
 
36
36
  from .channel import SSHClientChannel, SSHServerChannel
37
- from .channel import SSHTCPChannel, SSHUNIXChannel
37
+ from .channel import SSHTCPChannel, SSHUNIXChannel, SSHTunTapChannel
38
38
 
39
39
  from .client import SSHClient
40
40
 
@@ -92,7 +92,7 @@ from .rsa import set_default_skip_rsa_key_validation
92
92
  from .scp import scp
93
93
 
94
94
  from .session import DataType, SSHClientSession, SSHServerSession
95
- from .session import SSHTCPSession, SSHUNIXSession
95
+ from .session import SSHTCPSession, SSHUNIXSession, SSHTunTapSession
96
96
 
97
97
  from .server import SSHServer
98
98
 
@@ -154,18 +154,19 @@ __all__ = [
154
154
  'SSHServerSessionFactory', 'SSHSocketSessionFactory',
155
155
  'SSHSubprocessProtocol', 'SSHSubprocessReadPipe',
156
156
  'SSHSubprocessTransport', 'SSHSubprocessWritePipe', 'SSHTCPChannel',
157
- 'SSHTCPSession', 'SSHUNIXChannel', 'SSHUNIXSession', 'SSHWriter',
158
- 'STDOUT', 'ServiceNotAvailable', 'SignalReceived',
159
- 'TerminalSizeChanged', 'TimeoutError', 'connect', 'connect_agent',
160
- 'connect_reverse', 'create_connection', 'create_server',
161
- 'generate_private_key', 'get_server_auth_methods',
162
- 'get_server_host_key', 'import_authorized_keys', 'import_certificate',
163
- 'import_known_hosts', 'import_private_key', 'import_public_key',
164
- 'listen', 'listen_reverse', 'load_certificates', 'load_keypairs',
165
- 'load_pkcs11_keys', 'load_public_keys', 'load_resident_keys', 'logger',
166
- 'match_known_hosts', 'read_authorized_keys', 'read_certificate',
167
- 'read_certificate_list', 'read_known_hosts', 'read_private_key',
168
- 'read_private_key_list', 'read_public_key', 'read_public_key_list',
169
- 'run_client', 'run_server', 'scp', 'set_debug_level', 'set_log_level',
170
- 'set_sftp_log_level', 'set_default_skip_rsa_key_validation',
157
+ 'SSHTCPSession', 'SSHTunTapChannel', 'SSHTunTapSession',
158
+ 'SSHUNIXChannel', 'SSHUNIXSession', 'SSHWriter',
159
+ 'STDOUT', 'ServiceNotAvailable', 'SignalReceived', 'TerminalSizeChanged',
160
+ 'TimeoutError', 'connect', 'connect_agent', 'connect_reverse',
161
+ 'create_connection', 'create_server', 'generate_private_key',
162
+ 'get_server_auth_methods', 'get_server_host_key',
163
+ 'import_authorized_keys', 'import_certificate', 'import_known_hosts',
164
+ 'import_private_key', 'import_public_key', 'listen', 'listen_reverse',
165
+ 'load_certificates', 'load_keypairs', 'load_pkcs11_keys',
166
+ 'load_public_keys', 'load_resident_keys', 'logger', 'match_known_hosts',
167
+ 'read_authorized_keys', 'read_certificate', 'read_certificate_list',
168
+ 'read_known_hosts', 'read_private_key', 'read_private_key_list',
169
+ 'read_public_key', 'read_public_key_list', 'run_client', 'run_server',
170
+ 'scp', 'set_debug_level', 'set_default_skip_rsa_key_validation',
171
+ 'set_log_level', 'set_sftp_log_level'
171
172
  ]
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2023 by Ron Frederick <ronf@timeheart.net> and others.
1
+ # Copyright (c) 2016-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
@@ -26,7 +26,7 @@ import os
26
26
  import sys
27
27
  from types import TracebackType
28
28
  from typing import TYPE_CHECKING, List, Optional, Sequence, Tuple, Type, Union
29
- from typing_extensions import Protocol
29
+ from typing_extensions import Protocol, Self
30
30
 
31
31
  from .listener import SSHForwardListener
32
32
  from .misc import async_context_manager, maybe_wait_closed
@@ -198,7 +198,7 @@ class SSHAgentClient:
198
198
  self._writer: Optional[AgentWriter] = None
199
199
  self._lock = asyncio.Lock()
200
200
 
201
- async def __aenter__(self) -> 'SSHAgentClient':
201
+ async def __aenter__(self) -> Self:
202
202
  """Allow SSHAgentClient to be used as an async context manager"""
203
203
 
204
204
  return self
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2021 by Ron Frederick <ronf@timeheart.net> and others.
1
+ # Copyright (c) 2016-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
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2021 by Ron Frederick <ronf@timeheart.net> and others.
1
+ # Copyright (c) 2016-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
@@ -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
@@ -46,18 +46,22 @@ from .editor import SSHLineEditorChannel, SSHLineEditorSession
46
46
  from .logging import SSHLogger
47
47
 
48
48
  from .misc import ChannelOpenError, MaybeAwait, ProtocolError
49
+ from .misc import TermModes, TermSize, TermSizeArg
49
50
  from .misc import get_symbol_names, map_handler_name
50
51
 
51
52
  from .packet import Boolean, Byte, String, UInt32, SSHPacket, SSHPacketHandler
52
53
 
53
- from .session import TermModes, TermSize, TermSizeArg
54
54
  from .session import SSHSession, SSHClientSession, SSHServerSession
55
- from .session import SSHTCPSession, SSHUNIXSession
55
+ from .session import SSHTCPSession, SSHUNIXSession, SSHTunTapSession
56
56
  from .session import SSHSessionFactory, SSHClientSessionFactory
57
57
  from .session import SSHTCPSessionFactory, SSHUNIXSessionFactory
58
+ from .session import SSHTunTapSessionFactory
58
59
 
59
60
  from .stream import DataType
60
61
 
62
+ from .tuntap import SSH_TUN_MODE_POINTTOPOINT, SSH_TUN_UNIT_ANY
63
+ from .tuntap import SSH_TUN_AF_INET, SSH_TUN_AF_INET6
64
+
61
65
 
62
66
  if TYPE_CHECKING:
63
67
  # pylint: disable=cyclic-import
@@ -225,7 +229,7 @@ class SSHChannel(Generic[AnyStr], SSHPacketHandler):
225
229
 
226
230
  self._close_event.set()
227
231
 
228
- if self._conn: # pragma: no branch
232
+ if self._conn and self._recv_state == 'closed': # pragma: no branch
229
233
  self.logger.info('Channel closed%s',
230
234
  ': ' + str(exc) if exc else '')
231
235
 
@@ -259,7 +263,8 @@ class SSHChannel(Generic[AnyStr], SSHPacketHandler):
259
263
  # If recv is close_pending, we know send is already closed
260
264
  if self._recv_state == 'close_pending':
261
265
  self._recv_state = 'closed'
262
- self._loop.call_soon(self._cleanup)
266
+
267
+ self._loop.call_soon(self._cleanup)
263
268
 
264
269
  async def _start_reading(self) -> None:
265
270
  """Start processing data on a new connection"""
@@ -394,19 +399,6 @@ class SSHChannel(Generic[AnyStr], SSHPacketHandler):
394
399
  if self._send_state in {'close_pending', 'closed'}:
395
400
  return
396
401
 
397
- datalen = len(data)
398
-
399
- if datalen > self._recv_window:
400
- raise ProtocolError('Window exceeded')
401
-
402
- if datatype:
403
- typename = ' from %s' % _data_type_names[datatype]
404
- else:
405
- typename = ''
406
-
407
- self.logger.debug2('Received %d data byte%s%s', datalen,
408
- 's' if datalen > 1 else '', typename)
409
-
410
402
  if self._recv_paused:
411
403
  self._recv_buf.append((data, datatype))
412
404
  else:
@@ -579,6 +571,14 @@ class SSHChannel(Generic[AnyStr], SSHPacketHandler):
579
571
  data = packet.get_string()
580
572
  packet.check_end()
581
573
 
574
+ datalen = len(data)
575
+
576
+ if datalen > self._recv_window:
577
+ raise ProtocolError('Window exceeded')
578
+
579
+ self.logger.debug2('Received %d data byte%s', datalen,
580
+ 's' if datalen > 1 else '')
581
+
582
582
  self._accept_data(data)
583
583
 
584
584
  def _process_extended_data(self, _pkttype: int, _pktid: int,
@@ -595,6 +595,15 @@ class SSHChannel(Generic[AnyStr], SSHPacketHandler):
595
595
  if datatype not in self._read_datatypes:
596
596
  raise ProtocolError('Invalid extended data type')
597
597
 
598
+ datalen = len(data)
599
+
600
+ if datalen > self._recv_window:
601
+ raise ProtocolError('Window exceeded')
602
+
603
+ self.logger.debug2('Received %d data byte%s from %s', datalen,
604
+ 's' if datalen > 1 else '',
605
+ _data_type_names[datatype])
606
+
598
607
  self._accept_data(data, datatype)
599
608
 
600
609
  def _process_eof(self, _pkttype: int, _pktid: int,
@@ -2080,6 +2089,54 @@ class SSHUNIXChannel(SSHForwardChannel, Generic[AnyStr]):
2080
2089
  self.set_extra_info(local_peername=dest_path, remote_peername='')
2081
2090
 
2082
2091
 
2092
+ class SSHTunTapChannel(SSHForwardChannel[bytes]):
2093
+ """SSH TunTap channel"""
2094
+
2095
+ def __init__(self, conn: 'SSHConnection',
2096
+ loop: asyncio.AbstractEventLoop, encoding: Optional[str],
2097
+ errors: str, window: int, max_pktsize: int):
2098
+ super().__init__(conn, loop, encoding, errors, window, max_pktsize)
2099
+
2100
+ self._mode: Optional[int] = None
2101
+
2102
+ def _accept_data(self, data: bytes, datatype: DataType = None) -> None:
2103
+ """Strip off address family on incoming packets in TUN mode"""
2104
+
2105
+ if self._mode == SSH_TUN_MODE_POINTTOPOINT:
2106
+ data = data[4:]
2107
+
2108
+ super()._accept_data(data, datatype)
2109
+
2110
+ def write(self, data: bytes, datatype: DataType = None) -> None:
2111
+ """Add address family in outbound packets in TUN mode"""
2112
+
2113
+ if self._mode == SSH_TUN_MODE_POINTTOPOINT:
2114
+ version = data[0] >> 4
2115
+ family = SSH_TUN_AF_INET if version == 4 else SSH_TUN_AF_INET6
2116
+ data = UInt32(family) + data
2117
+
2118
+ super().write(data, datatype)
2119
+
2120
+ async def open(self, session_factory: SSHTunTapSessionFactory,
2121
+ mode: int, unit: Optional[int]) -> SSHTunTapSession:
2122
+ """Open a TUN/TAP channel"""
2123
+
2124
+ self._mode = mode
2125
+
2126
+ if unit is None:
2127
+ unit = SSH_TUN_UNIT_ANY
2128
+
2129
+ return cast(SSHTunTapSession,
2130
+ await self._open_forward(session_factory,
2131
+ b'tun@openssh.com',
2132
+ UInt32(mode), UInt32(unit)))
2133
+
2134
+ def set_mode(self, mode: int) -> None:
2135
+ """Set mode for inbound connections"""
2136
+
2137
+ self._mode = mode
2138
+
2139
+
2083
2140
  class SSHX11Channel(SSHForwardChannel[bytes]):
2084
2141
  """SSH X11 channel"""
2085
2142
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2013-2021 by Ron Frederick <ronf@timeheart.net> and others.
1
+ # Copyright (c) 2013-2023 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
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2020-2022 by Ron Frederick <ronf@timeheart.net> and others.
1
+ # Copyright (c) 2020-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
@@ -320,11 +320,16 @@ class SSHConfig:
320
320
  self._error(str(exc))
321
321
 
322
322
  args = []
323
+ loption = ''
324
+ allow_equal = True
323
325
 
324
- for arg in split_args:
326
+ for i, arg in enumerate(split_args, 1):
325
327
  if arg.startswith('='):
326
328
  if len(arg) > 1:
327
329
  args.append(arg[1:])
330
+ elif not allow_equal:
331
+ args.extend(split_args[i-1:])
332
+ break
328
333
  elif arg.endswith('='):
329
334
  args.append(arg[:-1])
330
335
  elif '=' in arg:
@@ -334,8 +339,9 @@ class SSHConfig:
334
339
  else:
335
340
  args.append(arg)
336
341
 
337
- option = args.pop(0)
338
- loption = option.lower()
342
+ if i == 1:
343
+ loption = args.pop(0).lower()
344
+ allow_equal = loption in self._conditionals
339
345
 
340
346
  if loption in self._no_split:
341
347
  args = [line.lstrip()[len(loption):].strip()]
@@ -419,7 +425,7 @@ class SSHClientConfig(SSHConfig):
419
425
  """Settings from an OpenSSH client config file"""
420
426
 
421
427
  _conditionals = {'host', 'match'}
422
- _no_split = {'remotecommand'}
428
+ _no_split = {'proxycommand', 'remotecommand'}
423
429
  _percent_expand = {'CertificateFile', 'IdentityAgent',
424
430
  'IdentityFile', 'ProxyCommand', 'RemoteCommand'}
425
431
 
@@ -447,6 +453,8 @@ class SSHClientConfig(SSHConfig):
447
453
  return self._local_user
448
454
  elif match == 'user':
449
455
  return self._options.get('User', self._local_user)
456
+ elif match == 'tagged':
457
+ return self._options.get('Tag', '')
450
458
  else:
451
459
  return None
452
460
 
@@ -551,7 +559,7 @@ class SSHClientConfig(SSHConfig):
551
559
  ('PKCS11Provider', SSHConfig._set_string),
552
560
  ('PreferredAuthentications', SSHConfig._set_string),
553
561
  ('Port', SSHConfig._set_int),
554
- ('ProxyCommand', SSHConfig._set_string_list),
562
+ ('ProxyCommand', SSHConfig._set_string),
555
563
  ('ProxyJump', SSHConfig._set_string),
556
564
  ('PubkeyAuthentication', SSHConfig._set_bool),
557
565
  ('RekeyLimit', SSHConfig._set_rekey_limits),
@@ -560,7 +568,8 @@ class SSHClientConfig(SSHConfig):
560
568
  ('SendEnv', SSHConfig._append_string_list),
561
569
  ('ServerAliveCountMax', SSHConfig._set_int),
562
570
  ('ServerAliveInterval', SSHConfig._set_int),
563
- ('SetEnv', SSHConfig._append_string_list),
571
+ ('SetEnv', SSHConfig._set_string_list),
572
+ ('Tag', SSHConfig._set_string),
564
573
  ('TCPKeepAlive', SSHConfig._set_bool),
565
574
  ('User', SSHConfig._set_string),
566
575
  ('UserKnownHostsFile', SSHConfig._set_string_list)