asyncssh 2.21.1__tar.gz → 2.23.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.
- {asyncssh-2.21.1 → asyncssh-2.23.0}/.github/workflows/run_tests.yml +17 -21
- {asyncssh-2.21.1/asyncssh.egg-info → asyncssh-2.23.0}/PKG-INFO +22 -27
- {asyncssh-2.21.1 → asyncssh-2.23.0}/README.rst +16 -20
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/agent.py +1 -3
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/channel.py +6 -4
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/client.py +1 -1
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/config.py +41 -5
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/connection.py +101 -45
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/crypto/__init__.py +7 -7
- asyncssh-2.23.0/asyncssh/crypto/chacha.py +103 -0
- asyncssh-2.23.0/asyncssh/crypto/ed.py +186 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/crypto/pq.py +5 -3
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/encryption.py +26 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/forward.py +8 -3
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/kex.py +1 -1
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/misc.py +1 -1
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/process.py +1 -1
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/scp.py +2 -1
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/server.py +4 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/sftp.py +33 -23
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/sk.py +23 -12
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/version.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/x11.py +11 -9
- {asyncssh-2.21.1 → asyncssh-2.23.0/asyncssh.egg-info}/PKG-INFO +22 -27
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh.egg-info/requires.txt +3 -3
- {asyncssh-2.21.1 → asyncssh-2.23.0}/docs/api.rst +1 -15
- {asyncssh-2.21.1 → asyncssh-2.23.0}/docs/changes.rst +75 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/callback_client.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/callback_client2.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/callback_client3.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/callback_math_server.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/chat_server.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/check_exit_status.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/chroot_sftp_server.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/direct_client.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/direct_server.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/editor.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/gather_results.py +8 -6
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/listening_client.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/local_forwarding_client.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/local_forwarding_client2.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/local_forwarding_server.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/math_client.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/math_server.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/redirect_input.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/redirect_local_pipe.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/redirect_remote_pipe.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/redirect_server.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/remote_forwarding_client.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/remote_forwarding_client2.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/remote_forwarding_server.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/reverse_client.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/reverse_server.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/scp_client.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/set_environment.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/set_terminal.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/sftp_client.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/show_environment.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/show_terminal.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/simple_cert_server.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/simple_client.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/simple_keyed_server.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/simple_scp_server.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/simple_server.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/simple_sftp_server.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/stream_direct_client.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/stream_direct_server.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/examples/stream_listening_client.py +2 -2
- {asyncssh-2.21.1 → asyncssh-2.23.0}/pyproject.toml +4 -5
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/sk_stub.py +22 -6
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_channel.py +27 -1
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_config.py +33 -1
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_connection.py +53 -10
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_forward.py +25 -1
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_kex.py +6 -5
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_pkcs11.py +1 -1
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_process.py +17 -22
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_sftp.py +22 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_sk.py +1 -1
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_stream.py +1 -1
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_tuntap.py +1 -1
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/util.py +1 -1
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tox.ini +8 -6
- asyncssh-2.21.1/asyncssh/crypto/chacha.py +0 -162
- asyncssh-2.21.1/asyncssh/crypto/ed.py +0 -325
- {asyncssh-2.21.1 → asyncssh-2.23.0}/.coveragerc +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/.gitignore +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/.readthedocs.yaml +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/CONTRIBUTING.rst +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/COPYRIGHT +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/LICENSE +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/MANIFEST.in +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/__init__.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/agent_unix.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/agent_win32.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/asn1.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/auth.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/auth_keys.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/compression.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/constants.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/crypto/cipher.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/crypto/dh.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/crypto/dsa.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/crypto/ec.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/crypto/ec_params.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/crypto/kdf.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/crypto/misc.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/crypto/rsa.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/crypto/umac.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/crypto/x509.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/dsa.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/ecdsa.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/eddsa.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/editor.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/gss.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/gss_unix.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/gss_win32.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/kex_dh.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/kex_rsa.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/keysign.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/known_hosts.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/listener.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/logging.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/mac.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/packet.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/pattern.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/pbe.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/pkcs11.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/public_key.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/py.typed +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/rsa.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/saslprep.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/session.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/sk_ecdsa.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/sk_eddsa.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/socks.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/stream.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/subprocess.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh/tuntap.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh.egg-info/SOURCES.txt +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh.egg-info/dependency_links.txt +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/asyncssh.egg-info/top_level.txt +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/docs/_templates/sidebarbottom.html +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/docs/_templates/sidebartop.html +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/docs/conf.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/docs/contributing.rst +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/docs/index.rst +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/docs/requirements.txt +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/docs/rftheme/layout.html +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/docs/rftheme/static/rftheme.css_t +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/docs/rftheme/theme.conf +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/docs/rtd-req.txt +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/mypy.ini +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/pylintrc +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/setup.cfg +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/__init__.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/gss_stub.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/gssapi_stub.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/keysign_stub.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/pkcs11_stub.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/server.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/sspi_stub.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_agent.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_asn1.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_auth.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_auth_keys.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_compression.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_connection_auth.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_editor.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_encryption.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_known_hosts.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_logging.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_mac.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_packet.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_public_key.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_saslprep.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_subprocess.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_x11.py +0 -0
- {asyncssh-2.21.1 → asyncssh-2.23.0}/tests/test_x509.py +0 -0
|
@@ -13,21 +13,8 @@ jobs:
|
|
|
13
13
|
strategy:
|
|
14
14
|
fail-fast: false
|
|
15
15
|
matrix:
|
|
16
|
-
os: [ubuntu-latest, macos-latest, windows-
|
|
17
|
-
python-version: ["3.
|
|
18
|
-
include:
|
|
19
|
-
- os: macos-latest
|
|
20
|
-
python-version: "3.10"
|
|
21
|
-
openssl-version: "3"
|
|
22
|
-
- os: macos-latest
|
|
23
|
-
python-version: "3.11"
|
|
24
|
-
openssl-version: "3"
|
|
25
|
-
- os: macos-latest
|
|
26
|
-
python-version: "3.12"
|
|
27
|
-
openssl-version: "3"
|
|
28
|
-
- os: macos-latest
|
|
29
|
-
python-version: "3.13"
|
|
30
|
-
openssl-version: "3"
|
|
16
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
17
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
31
18
|
|
|
32
19
|
runs-on: ${{ matrix.os }}
|
|
33
20
|
env:
|
|
@@ -56,6 +43,19 @@ jobs:
|
|
|
56
43
|
asyncssh/setup.py
|
|
57
44
|
asyncssh/tox.ini
|
|
58
45
|
|
|
46
|
+
- name: Fix modules path for OpenSSL on Windows
|
|
47
|
+
if: ${{ runner.os == 'Windows' }}
|
|
48
|
+
shell: pwsh
|
|
49
|
+
run: |
|
|
50
|
+
$openssl_path = ((Get-Command openssl).Path | Split-Path -Parent)
|
|
51
|
+
echo "OPENSSL_MODULES=$openssl_path" >> $env:GITHUB_ENV
|
|
52
|
+
|
|
53
|
+
- name: Verify legacy provider can be enabled in OpenSSL on Windows
|
|
54
|
+
if: ${{ runner.os == 'Windows' }}
|
|
55
|
+
shell: pwsh
|
|
56
|
+
run: |
|
|
57
|
+
openssl list -provider default -provider legacy -providers
|
|
58
|
+
|
|
59
59
|
- name: Set up ccache for liboqs (Linux)
|
|
60
60
|
uses: hendrikmuhs/ccache-action@v1.2
|
|
61
61
|
if: ${{ runner.os == 'Linux' }}
|
|
@@ -66,15 +66,11 @@ jobs:
|
|
|
66
66
|
if: ${{ runner.os == 'Linux' }}
|
|
67
67
|
run: |
|
|
68
68
|
sudo apt update
|
|
69
|
-
sudo apt install -y --no-install-recommends libnettle8
|
|
69
|
+
sudo apt install -y --no-install-recommends libnettle8 libssl-dev libkrb5-dev ssh cmake ninja-build
|
|
70
70
|
|
|
71
71
|
- name: Install macOS dependencies
|
|
72
72
|
if: ${{ runner.os == 'macOS' }}
|
|
73
|
-
run: brew install nettle liboqs
|
|
74
|
-
|
|
75
|
-
- name: Provide OpenSSL 3
|
|
76
|
-
if: ${{ runner.os == 'macOS' && matrix.openssl-version == '3' }}
|
|
77
|
-
run: echo "/usr/local/opt/openssl@3/bin" >> $GITHUB_PATH
|
|
73
|
+
run: brew install nettle liboqs
|
|
78
74
|
|
|
79
75
|
- name: Install nettle (Windows)
|
|
80
76
|
if: ${{ runner.os == 'Windows' }}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: asyncssh
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.23.0
|
|
4
4
|
Summary: AsyncSSH: Asynchronous SSHv2 client and server library
|
|
5
5
|
Author-email: Ron Frederick <ronf@timeheart.net>
|
|
6
6
|
License: EPL-2.0 OR GPL-2.0-or-later
|
|
@@ -14,17 +14,16 @@ Classifier: Intended Audience :: Developers
|
|
|
14
14
|
Classifier: License :: OSI Approved
|
|
15
15
|
Classifier: Operating System :: MacOS :: MacOS X
|
|
16
16
|
Classifier: Operating System :: POSIX
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
19
17
|
Classifier: Programming Language :: Python :: 3.10
|
|
20
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
22
20
|
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
22
|
Classifier: Topic :: Internet
|
|
24
23
|
Classifier: Topic :: Security :: Cryptography
|
|
25
24
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
26
25
|
Classifier: Topic :: System :: Networking
|
|
27
|
-
Requires-Python: >=3.
|
|
26
|
+
Requires-Python: >=3.10
|
|
28
27
|
Description-Content-Type: text/x-rst
|
|
29
28
|
License-File: LICENSE
|
|
30
29
|
Requires-Dist: cryptography>=39.0
|
|
@@ -32,11 +31,11 @@ Requires-Dist: typing_extensions>=4.0.0
|
|
|
32
31
|
Provides-Extra: bcrypt
|
|
33
32
|
Requires-Dist: bcrypt>=3.1.3; extra == "bcrypt"
|
|
34
33
|
Provides-Extra: fido2
|
|
35
|
-
Requires-Dist: fido2
|
|
34
|
+
Requires-Dist: fido2>=2; extra == "fido2"
|
|
35
|
+
Provides-Extra: ifaddr
|
|
36
|
+
Requires-Dist: ifaddr>=0.2.0; extra == "ifaddr"
|
|
36
37
|
Provides-Extra: gssapi
|
|
37
38
|
Requires-Dist: gssapi>=1.2.0; extra == "gssapi"
|
|
38
|
-
Provides-Extra: libnacl
|
|
39
|
-
Requires-Dist: libnacl>=1.4.2; extra == "libnacl"
|
|
40
39
|
Provides-Extra: pkcs11
|
|
41
40
|
Requires-Dist: python-pkcs11>=0.7.0; extra == "pkcs11"
|
|
42
41
|
Provides-Extra: pyopenssl
|
|
@@ -58,7 +57,7 @@ AsyncSSH: Asynchronous SSH for Python
|
|
|
58
57
|
=====================================
|
|
59
58
|
|
|
60
59
|
AsyncSSH is a Python package which provides an asynchronous client and
|
|
61
|
-
server implementation of the SSHv2 protocol on top of the Python 3.
|
|
60
|
+
server implementation of the SSHv2 protocol on top of the Python 3.10+
|
|
62
61
|
asyncio framework.
|
|
63
62
|
|
|
64
63
|
.. code:: python
|
|
@@ -148,7 +147,7 @@ License
|
|
|
148
147
|
|
|
149
148
|
This package is released under the following terms:
|
|
150
149
|
|
|
151
|
-
Copyright (c) 2013-
|
|
150
|
+
Copyright (c) 2013-2025 by Ron Frederick <ronf@timeheart.net> and others.
|
|
152
151
|
|
|
153
152
|
This program and the accompanying materials are made available under
|
|
154
153
|
the terms of the Eclipse Public License v2.0 which accompanies this
|
|
@@ -173,8 +172,8 @@ Prerequisites
|
|
|
173
172
|
|
|
174
173
|
To use AsyncSSH 2.0 or later, you need the following:
|
|
175
174
|
|
|
176
|
-
* Python 3.
|
|
177
|
-
* cryptography (PyCA)
|
|
175
|
+
* Python 3.10 or later
|
|
176
|
+
* cryptography (PyCA) 39.0 or later
|
|
178
177
|
|
|
179
178
|
Installation
|
|
180
179
|
------------
|
|
@@ -197,6 +196,9 @@ functionality:
|
|
|
197
196
|
* Install fido2 from https://pypi.org/project/fido2 if you want support
|
|
198
197
|
for key exchange and authentication with U2F/FIDO2 security keys.
|
|
199
198
|
|
|
199
|
+
* Install ifaddr from https://pypi.org/project/ifaddr/ if you want
|
|
200
|
+
support for matching on local network IP addresses.
|
|
201
|
+
|
|
200
202
|
* Install python-pkcs11 from https://pypi.org/project/python-pkcs11 if
|
|
201
203
|
you want support for accessing PIV keys on PKCS#11 security tokens.
|
|
202
204
|
|
|
@@ -207,12 +209,6 @@ functionality:
|
|
|
207
209
|
if you want support for the OpenSSH post-quantum key exchange
|
|
208
210
|
algorithms based on ML-KEM and SNTRUP.
|
|
209
211
|
|
|
210
|
-
* Install libsodium from https://github.com/jedisct1/libsodium
|
|
211
|
-
and libnacl from https://pypi.python.org/pypi/libnacl if you have
|
|
212
|
-
a version of OpenSSL older than 1.1.1b installed and you want
|
|
213
|
-
support for Curve25519 key exchange, Ed25519 keys and certificates,
|
|
214
|
-
or the Chacha20-Poly1305 cipher.
|
|
215
|
-
|
|
216
212
|
* Install libnettle from http://www.lysator.liu.se/~nisse/nettle/
|
|
217
213
|
if you want support for UMAC cryptographic hashes.
|
|
218
214
|
|
|
@@ -228,29 +224,28 @@ easy to install any or all of these dependencies:
|
|
|
228
224
|
|
|
229
225
|
| bcrypt
|
|
230
226
|
| fido2
|
|
227
|
+
| ifaddr
|
|
231
228
|
| gssapi
|
|
232
|
-
| libnacl
|
|
233
229
|
| pkcs11
|
|
234
230
|
| pyOpenSSL
|
|
235
231
|
| pywin32
|
|
236
232
|
|
|
237
|
-
For example, to install bcrypt, fido2, gssapi,
|
|
238
|
-
|
|
233
|
+
For example, to install bcrypt, fido2, gssapi, ifaddr, pkcs11, and pyOpenSSL
|
|
234
|
+
on UNIX, you can run:
|
|
239
235
|
|
|
240
236
|
::
|
|
241
237
|
|
|
242
|
-
pip install 'asyncssh[bcrypt,fido2,gssapi,
|
|
238
|
+
pip install 'asyncssh[bcrypt,fido2,gssapi,ifaddr,pkcs11,pyOpenSSL]'
|
|
243
239
|
|
|
244
|
-
To install bcrypt, fido2,
|
|
245
|
-
|
|
240
|
+
To install bcrypt, fido2, ifaddr, pkcs11, pyOpenSSL, and pywin32 on Windows,
|
|
241
|
+
you can run:
|
|
246
242
|
|
|
247
243
|
::
|
|
248
244
|
|
|
249
|
-
pip install 'asyncssh[bcrypt,fido2,
|
|
245
|
+
pip install 'asyncssh[bcrypt,fido2,ifaddr,pkcs11,pyOpenSSL,pywin32]'
|
|
250
246
|
|
|
251
|
-
Note that you will still need to manually install the
|
|
252
|
-
|
|
253
|
-
support. Unfortunately, since liboqs, libsodium, and libnettle are not
|
|
247
|
+
Note that you will still need to manually install the libnettle library
|
|
248
|
+
for UMAC support. Unfortunately, since liboqs and libnettle are not
|
|
254
249
|
Python packages, they cannot be directly installed using pip.
|
|
255
250
|
|
|
256
251
|
Installing the development branch
|
|
@@ -11,7 +11,7 @@ AsyncSSH: Asynchronous SSH for Python
|
|
|
11
11
|
=====================================
|
|
12
12
|
|
|
13
13
|
AsyncSSH is a Python package which provides an asynchronous client and
|
|
14
|
-
server implementation of the SSHv2 protocol on top of the Python 3.
|
|
14
|
+
server implementation of the SSHv2 protocol on top of the Python 3.10+
|
|
15
15
|
asyncio framework.
|
|
16
16
|
|
|
17
17
|
.. code:: python
|
|
@@ -101,7 +101,7 @@ License
|
|
|
101
101
|
|
|
102
102
|
This package is released under the following terms:
|
|
103
103
|
|
|
104
|
-
Copyright (c) 2013-
|
|
104
|
+
Copyright (c) 2013-2025 by Ron Frederick <ronf@timeheart.net> and others.
|
|
105
105
|
|
|
106
106
|
This program and the accompanying materials are made available under
|
|
107
107
|
the terms of the Eclipse Public License v2.0 which accompanies this
|
|
@@ -126,8 +126,8 @@ Prerequisites
|
|
|
126
126
|
|
|
127
127
|
To use AsyncSSH 2.0 or later, you need the following:
|
|
128
128
|
|
|
129
|
-
* Python 3.
|
|
130
|
-
* cryptography (PyCA)
|
|
129
|
+
* Python 3.10 or later
|
|
130
|
+
* cryptography (PyCA) 39.0 or later
|
|
131
131
|
|
|
132
132
|
Installation
|
|
133
133
|
------------
|
|
@@ -150,6 +150,9 @@ functionality:
|
|
|
150
150
|
* Install fido2 from https://pypi.org/project/fido2 if you want support
|
|
151
151
|
for key exchange and authentication with U2F/FIDO2 security keys.
|
|
152
152
|
|
|
153
|
+
* Install ifaddr from https://pypi.org/project/ifaddr/ if you want
|
|
154
|
+
support for matching on local network IP addresses.
|
|
155
|
+
|
|
153
156
|
* Install python-pkcs11 from https://pypi.org/project/python-pkcs11 if
|
|
154
157
|
you want support for accessing PIV keys on PKCS#11 security tokens.
|
|
155
158
|
|
|
@@ -160,12 +163,6 @@ functionality:
|
|
|
160
163
|
if you want support for the OpenSSH post-quantum key exchange
|
|
161
164
|
algorithms based on ML-KEM and SNTRUP.
|
|
162
165
|
|
|
163
|
-
* Install libsodium from https://github.com/jedisct1/libsodium
|
|
164
|
-
and libnacl from https://pypi.python.org/pypi/libnacl if you have
|
|
165
|
-
a version of OpenSSL older than 1.1.1b installed and you want
|
|
166
|
-
support for Curve25519 key exchange, Ed25519 keys and certificates,
|
|
167
|
-
or the Chacha20-Poly1305 cipher.
|
|
168
|
-
|
|
169
166
|
* Install libnettle from http://www.lysator.liu.se/~nisse/nettle/
|
|
170
167
|
if you want support for UMAC cryptographic hashes.
|
|
171
168
|
|
|
@@ -181,29 +178,28 @@ easy to install any or all of these dependencies:
|
|
|
181
178
|
|
|
182
179
|
| bcrypt
|
|
183
180
|
| fido2
|
|
181
|
+
| ifaddr
|
|
184
182
|
| gssapi
|
|
185
|
-
| libnacl
|
|
186
183
|
| pkcs11
|
|
187
184
|
| pyOpenSSL
|
|
188
185
|
| pywin32
|
|
189
186
|
|
|
190
|
-
For example, to install bcrypt, fido2, gssapi,
|
|
191
|
-
|
|
187
|
+
For example, to install bcrypt, fido2, gssapi, ifaddr, pkcs11, and pyOpenSSL
|
|
188
|
+
on UNIX, you can run:
|
|
192
189
|
|
|
193
190
|
::
|
|
194
191
|
|
|
195
|
-
pip install 'asyncssh[bcrypt,fido2,gssapi,
|
|
192
|
+
pip install 'asyncssh[bcrypt,fido2,gssapi,ifaddr,pkcs11,pyOpenSSL]'
|
|
196
193
|
|
|
197
|
-
To install bcrypt, fido2,
|
|
198
|
-
|
|
194
|
+
To install bcrypt, fido2, ifaddr, pkcs11, pyOpenSSL, and pywin32 on Windows,
|
|
195
|
+
you can run:
|
|
199
196
|
|
|
200
197
|
::
|
|
201
198
|
|
|
202
|
-
pip install 'asyncssh[bcrypt,fido2,
|
|
199
|
+
pip install 'asyncssh[bcrypt,fido2,ifaddr,pkcs11,pyOpenSSL,pywin32]'
|
|
203
200
|
|
|
204
|
-
Note that you will still need to manually install the
|
|
205
|
-
|
|
206
|
-
support. Unfortunately, since liboqs, libsodium, and libnettle are not
|
|
201
|
+
Note that you will still need to manually install the libnettle library
|
|
202
|
+
for UMAC support. Unfortunately, since liboqs and libnettle are not
|
|
207
203
|
Python packages, they cannot be directly installed using pip.
|
|
208
204
|
|
|
209
205
|
Installing the development branch
|
|
@@ -121,9 +121,7 @@ class SSHAgentKeyPair(SSHKeyPair):
|
|
|
121
121
|
else:
|
|
122
122
|
sig_algorithm = algorithm
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
# ssh-agent protocol flags used to request RSA SHA2 signatures yet
|
|
126
|
-
if sig_algorithm == b'ssh-rsa' and sys.platform != 'win32':
|
|
124
|
+
if sig_algorithm == b'ssh-rsa':
|
|
127
125
|
sig_algorithms: Sequence[bytes] = \
|
|
128
126
|
(b'rsa-sha2-256', b'rsa-sha2-512', b'ssh-rsa')
|
|
129
127
|
else:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) 2013-
|
|
1
|
+
# Copyright (c) 2013-2025 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
|
|
@@ -1125,10 +1125,12 @@ class SSHClientChannel(SSHChannel, Generic[AnyStr]):
|
|
|
1125
1125
|
_read_datatypes = {EXTENDED_DATA_STDERR}
|
|
1126
1126
|
|
|
1127
1127
|
def __init__(self, conn: 'SSHClientConnection',
|
|
1128
|
-
loop: asyncio.AbstractEventLoop,
|
|
1129
|
-
|
|
1128
|
+
loop: asyncio.AbstractEventLoop, utf8_decode_errors: str,
|
|
1129
|
+
encoding: Optional[str], errors: str, window: int,
|
|
1130
|
+
max_pktsize: int):
|
|
1130
1131
|
super().__init__(conn, loop, encoding, errors, window, max_pktsize)
|
|
1131
1132
|
|
|
1133
|
+
self._utf8_decode_errors = utf8_decode_errors
|
|
1132
1134
|
self._exit_status: Optional[int] = None
|
|
1133
1135
|
self._exit_signal: Optional[_ExitSignal] = None
|
|
1134
1136
|
|
|
@@ -1299,7 +1301,7 @@ class SSHClientChannel(SSHChannel, Generic[AnyStr]):
|
|
|
1299
1301
|
|
|
1300
1302
|
try:
|
|
1301
1303
|
signal = signal_bytes.decode('ascii')
|
|
1302
|
-
msg = msg_bytes.decode('utf-8')
|
|
1304
|
+
msg = msg_bytes.decode('utf-8', self._utf8_decode_errors)
|
|
1303
1305
|
lang = lang_bytes.decode('ascii')
|
|
1304
1306
|
except UnicodeDecodeError:
|
|
1305
1307
|
raise ProtocolError('Invalid exit signal request') from None
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) 2013-
|
|
1
|
+
# Copyright (c) 2013-2025 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-
|
|
1
|
+
# Copyright (c) 2020-2026 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
|
|
@@ -29,14 +29,20 @@ import subprocess
|
|
|
29
29
|
from hashlib import sha1
|
|
30
30
|
from pathlib import Path, PurePath
|
|
31
31
|
from subprocess import DEVNULL
|
|
32
|
-
from typing import Callable, Dict, List, NoReturn, Optional
|
|
33
|
-
from typing import Set, Tuple, Union, cast
|
|
32
|
+
from typing import Callable, Dict, Iterator, List, NoReturn, Optional
|
|
33
|
+
from typing import Sequence, Set, Tuple, Union, cast
|
|
34
34
|
|
|
35
35
|
from .constants import DEFAULT_PORT
|
|
36
36
|
from .logging import logger
|
|
37
|
-
from .misc import DefTuple, FilePath, ip_address
|
|
37
|
+
from .misc import DefTuple, FilePath, IllegalUserName, ip_address
|
|
38
38
|
from .pattern import HostPatternList, WildcardPatternList
|
|
39
39
|
|
|
40
|
+
try:
|
|
41
|
+
import ifaddr
|
|
42
|
+
_ifaddr_available = True
|
|
43
|
+
except ImportError: # pragma: no cover
|
|
44
|
+
_ifaddr_available = False
|
|
45
|
+
|
|
40
46
|
|
|
41
47
|
ConfigPaths = Union[None, FilePath, Sequence[FilePath]]
|
|
42
48
|
|
|
@@ -52,6 +58,18 @@ def _exec(cmd: str) -> bool:
|
|
|
52
58
|
stdout=DEVNULL, stderr=DEVNULL).returncode == 0
|
|
53
59
|
|
|
54
60
|
|
|
61
|
+
def _get_local_ips() -> Iterator[str]:
|
|
62
|
+
"""Return local IP addresses of the system"""
|
|
63
|
+
|
|
64
|
+
for adapter in ifaddr.get_adapters():
|
|
65
|
+
for ip in adapter.ips:
|
|
66
|
+
if isinstance(ip.ip, tuple):
|
|
67
|
+
addr, _, scope_id = ip.ip
|
|
68
|
+
yield f'{addr}%{scope_id}' if scope_id else addr
|
|
69
|
+
else:
|
|
70
|
+
yield ip.ip
|
|
71
|
+
|
|
72
|
+
|
|
55
73
|
class ConfigParseError(ValueError):
|
|
56
74
|
"""Configuration parsing exception"""
|
|
57
75
|
|
|
@@ -146,7 +164,7 @@ class SSHConfig:
|
|
|
146
164
|
else:
|
|
147
165
|
path = self._default_path
|
|
148
166
|
|
|
149
|
-
paths = list(path.glob(pattern))
|
|
167
|
+
paths = list(p for p in path.glob(pattern) if p.is_file())
|
|
150
168
|
|
|
151
169
|
if not paths:
|
|
152
170
|
logger.debug1(f'Config pattern "{pattern}" matched no files')
|
|
@@ -183,6 +201,10 @@ class SSHConfig:
|
|
|
183
201
|
elif match == 'final':
|
|
184
202
|
result = cast(bool, self._final)
|
|
185
203
|
else:
|
|
204
|
+
if (match == 'localnetwork' and
|
|
205
|
+
not _ifaddr_available): # pragma: no cover
|
|
206
|
+
self._error('Local network match requires ifaddr module')
|
|
207
|
+
|
|
186
208
|
match_val = self._match_val(match)
|
|
187
209
|
|
|
188
210
|
if match != 'exec' and match_val is None:
|
|
@@ -201,6 +223,15 @@ class SSHConfig:
|
|
|
201
223
|
ip = ip_address(cast(str, match_val)) \
|
|
202
224
|
if match_val else None
|
|
203
225
|
result = host_pat.matches(None, match_val, ip)
|
|
226
|
+
elif match == 'localnetwork':
|
|
227
|
+
host_pat = HostPatternList(arg)
|
|
228
|
+
|
|
229
|
+
for addr in cast(Iterator[str], match_val):
|
|
230
|
+
if host_pat.matches(None, addr, ip_address(addr)):
|
|
231
|
+
result = True
|
|
232
|
+
break
|
|
233
|
+
else:
|
|
234
|
+
result = False
|
|
204
235
|
else:
|
|
205
236
|
wild_pat = WildcardPatternList(arg)
|
|
206
237
|
result = wild_pat.matches(match_val)
|
|
@@ -514,6 +545,8 @@ class SSHClientConfig(SSHConfig):
|
|
|
514
545
|
return self._options.get('Hostname', self._orig_host)
|
|
515
546
|
elif match == 'originalhost':
|
|
516
547
|
return self._orig_host
|
|
548
|
+
elif match == 'localnetwork':
|
|
549
|
+
return _get_local_ips()
|
|
517
550
|
elif match == 'localuser':
|
|
518
551
|
return self._local_user
|
|
519
552
|
elif match == 'user':
|
|
@@ -679,6 +712,9 @@ class SSHServerConfig(SSHConfig):
|
|
|
679
712
|
def _set_tokens(self) -> None:
|
|
680
713
|
"""Set the tokens available for percent expansion"""
|
|
681
714
|
|
|
715
|
+
if self._user == '..' or '/' in self._user or '\\' in self._user:
|
|
716
|
+
raise IllegalUserName('Unsafe username substitution')
|
|
717
|
+
|
|
682
718
|
self._tokens.update({'u': self._user})
|
|
683
719
|
|
|
684
720
|
_handlers = {option.lower(): (option, handler) for option, handler in (
|