asyncssh 2.21.0__tar.gz → 2.22.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.0 → asyncssh-2.22.0}/.github/workflows/run_tests.yml +27 -20
- {asyncssh-2.21.0/asyncssh.egg-info → asyncssh-2.22.0}/PKG-INFO +16 -25
- {asyncssh-2.21.0 → asyncssh-2.22.0}/README.rst +12 -20
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/channel.py +6 -4
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/client.py +1 -1
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/config.py +1 -1
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/connection.py +55 -24
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/crypto/__init__.py +7 -7
- asyncssh-2.22.0/asyncssh/crypto/chacha.py +103 -0
- asyncssh-2.22.0/asyncssh/crypto/ed.py +186 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/forward.py +10 -4
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/misc.py +3 -3
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/process.py +1 -1
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/public_key.py +147 -97
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/scp.py +8 -3
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/sftp.py +18 -8
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/sk.py +23 -12
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/version.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0/asyncssh.egg-info}/PKG-INFO +16 -25
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh.egg-info/requires.txt +1 -1
- {asyncssh-2.21.0 → asyncssh-2.22.0}/docs/changes.rst +56 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/callback_client.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/callback_client2.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/callback_client3.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/callback_math_server.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/chat_server.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/check_exit_status.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/chroot_sftp_server.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/direct_client.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/direct_server.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/editor.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/gather_results.py +8 -6
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/listening_client.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/local_forwarding_client.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/local_forwarding_client2.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/local_forwarding_server.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/math_client.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/math_server.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/redirect_input.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/redirect_local_pipe.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/redirect_remote_pipe.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/redirect_server.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/remote_forwarding_client.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/remote_forwarding_client2.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/remote_forwarding_server.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/reverse_client.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/reverse_server.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/scp_client.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/set_environment.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/set_terminal.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/sftp_client.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/show_environment.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/show_terminal.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/simple_cert_server.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/simple_client.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/simple_keyed_server.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/simple_scp_server.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/simple_server.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/simple_sftp_server.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/stream_direct_client.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/stream_direct_server.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/examples/stream_listening_client.py +2 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/pyproject.toml +3 -4
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/sk_stub.py +22 -6
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_agent.py +3 -4
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_channel.py +27 -1
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_config.py +12 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_connection.py +23 -8
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_connection_auth.py +5 -5
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_forward.py +1 -1
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_kex.py +0 -5
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_pkcs11.py +1 -1
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_public_key.py +5 -16
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_sftp.py +25 -2
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_sk.py +1 -1
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_stream.py +1 -1
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_tuntap.py +1 -1
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/util.py +1 -1
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tox.ini +7 -5
- asyncssh-2.21.0/asyncssh/crypto/chacha.py +0 -162
- asyncssh-2.21.0/asyncssh/crypto/ed.py +0 -325
- {asyncssh-2.21.0 → asyncssh-2.22.0}/.coveragerc +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/.gitignore +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/.readthedocs.yaml +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/CONTRIBUTING.rst +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/COPYRIGHT +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/LICENSE +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/MANIFEST.in +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/__init__.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/agent.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/agent_unix.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/agent_win32.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/asn1.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/auth.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/auth_keys.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/compression.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/constants.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/crypto/cipher.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/crypto/dh.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/crypto/dsa.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/crypto/ec.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/crypto/ec_params.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/crypto/kdf.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/crypto/misc.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/crypto/pq.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/crypto/rsa.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/crypto/umac.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/crypto/x509.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/dsa.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/ecdsa.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/eddsa.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/editor.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/encryption.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/gss.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/gss_unix.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/gss_win32.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/kex.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/kex_dh.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/kex_rsa.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/keysign.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/known_hosts.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/listener.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/logging.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/mac.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/packet.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/pattern.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/pbe.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/pkcs11.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/py.typed +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/rsa.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/saslprep.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/server.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/session.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/sk_ecdsa.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/sk_eddsa.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/socks.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/stream.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/subprocess.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/tuntap.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh/x11.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh.egg-info/SOURCES.txt +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh.egg-info/dependency_links.txt +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/asyncssh.egg-info/top_level.txt +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/docs/_templates/sidebarbottom.html +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/docs/_templates/sidebartop.html +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/docs/api.rst +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/docs/conf.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/docs/contributing.rst +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/docs/index.rst +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/docs/requirements.txt +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/docs/rftheme/layout.html +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/docs/rftheme/static/rftheme.css_t +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/docs/rftheme/theme.conf +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/docs/rtd-req.txt +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/mypy.ini +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/pylintrc +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/setup.cfg +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/__init__.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/gss_stub.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/gssapi_stub.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/keysign_stub.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/pkcs11_stub.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/server.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/sspi_stub.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_asn1.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_auth.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_auth_keys.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_compression.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_editor.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_encryption.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_known_hosts.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_logging.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_mac.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_packet.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_process.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_saslprep.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_subprocess.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_x11.py +0 -0
- {asyncssh-2.21.0 → asyncssh-2.22.0}/tests/test_x509.py +0 -0
|
@@ -1,27 +1,20 @@
|
|
|
1
1
|
name: Run tests
|
|
2
2
|
on: [push, pull_request]
|
|
3
3
|
|
|
4
|
+
permissions:
|
|
5
|
+
contents: read
|
|
6
|
+
|
|
4
7
|
jobs:
|
|
5
8
|
run-tests:
|
|
6
9
|
name: Run tests
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
actions: write
|
|
7
13
|
strategy:
|
|
8
14
|
fail-fast: false
|
|
9
15
|
matrix:
|
|
10
16
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
11
|
-
python-version: ["3.
|
|
12
|
-
include:
|
|
13
|
-
- os: macos-latest
|
|
14
|
-
python-version: "3.10"
|
|
15
|
-
openssl-version: "3"
|
|
16
|
-
- os: macos-latest
|
|
17
|
-
python-version: "3.11"
|
|
18
|
-
openssl-version: "3"
|
|
19
|
-
- os: macos-latest
|
|
20
|
-
python-version: "3.12"
|
|
21
|
-
openssl-version: "3"
|
|
22
|
-
- os: macos-latest
|
|
23
|
-
python-version: "3.13"
|
|
24
|
-
openssl-version: "3"
|
|
17
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
25
18
|
|
|
26
19
|
runs-on: ${{ matrix.os }}
|
|
27
20
|
env:
|
|
@@ -50,6 +43,19 @@ jobs:
|
|
|
50
43
|
asyncssh/setup.py
|
|
51
44
|
asyncssh/tox.ini
|
|
52
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
|
+
|
|
53
59
|
- name: Set up ccache for liboqs (Linux)
|
|
54
60
|
uses: hendrikmuhs/ccache-action@v1.2
|
|
55
61
|
if: ${{ runner.os == 'Linux' }}
|
|
@@ -60,15 +66,11 @@ jobs:
|
|
|
60
66
|
if: ${{ runner.os == 'Linux' }}
|
|
61
67
|
run: |
|
|
62
68
|
sudo apt update
|
|
63
|
-
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
|
|
64
70
|
|
|
65
71
|
- name: Install macOS dependencies
|
|
66
72
|
if: ${{ runner.os == 'macOS' }}
|
|
67
|
-
run: brew install nettle liboqs
|
|
68
|
-
|
|
69
|
-
- name: Provide OpenSSL 3
|
|
70
|
-
if: ${{ runner.os == 'macOS' && matrix.openssl-version == '3' }}
|
|
71
|
-
run: echo "/usr/local/opt/openssl@3/bin" >> $GITHUB_PATH
|
|
73
|
+
run: brew install nettle liboqs
|
|
72
74
|
|
|
73
75
|
- name: Install nettle (Windows)
|
|
74
76
|
if: ${{ runner.os == 'Windows' }}
|
|
@@ -124,6 +126,8 @@ jobs:
|
|
|
124
126
|
runs-on: ubuntu-latest
|
|
125
127
|
needs: run-tests
|
|
126
128
|
if: ${{ always() }}
|
|
129
|
+
permissions:
|
|
130
|
+
actions: write
|
|
127
131
|
steps:
|
|
128
132
|
- name: Merge coverage
|
|
129
133
|
uses: actions/upload-artifact/merge@v4
|
|
@@ -137,6 +141,9 @@ jobs:
|
|
|
137
141
|
runs-on: ubuntu-latest
|
|
138
142
|
needs: merge-coverage
|
|
139
143
|
if: ${{ always() }}
|
|
144
|
+
permissions:
|
|
145
|
+
contents: read
|
|
146
|
+
actions: read
|
|
140
147
|
steps:
|
|
141
148
|
- uses: actions/checkout@v4
|
|
142
149
|
- uses: actions/setup-python@v5
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: asyncssh
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.22.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,7 +31,7 @@ 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"
|
|
36
35
|
Provides-Extra: gssapi
|
|
37
36
|
Requires-Dist: gssapi>=1.2.0; extra == "gssapi"
|
|
38
37
|
Provides-Extra: libnacl
|
|
@@ -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
|
------------
|
|
@@ -207,12 +206,6 @@ functionality:
|
|
|
207
206
|
if you want support for the OpenSSH post-quantum key exchange
|
|
208
207
|
algorithms based on ML-KEM and SNTRUP.
|
|
209
208
|
|
|
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
209
|
* Install libnettle from http://www.lysator.liu.se/~nisse/nettle/
|
|
217
210
|
if you want support for UMAC cryptographic hashes.
|
|
218
211
|
|
|
@@ -229,28 +222,26 @@ easy to install any or all of these dependencies:
|
|
|
229
222
|
| bcrypt
|
|
230
223
|
| fido2
|
|
231
224
|
| gssapi
|
|
232
|
-
| libnacl
|
|
233
225
|
| pkcs11
|
|
234
226
|
| pyOpenSSL
|
|
235
227
|
| pywin32
|
|
236
228
|
|
|
237
|
-
For example, to install bcrypt, fido2, gssapi,
|
|
238
|
-
|
|
229
|
+
For example, to install bcrypt, fido2, gssapi, pkcs11, and pyOpenSSL
|
|
230
|
+
on UNIX, you can run:
|
|
239
231
|
|
|
240
232
|
::
|
|
241
233
|
|
|
242
|
-
pip install 'asyncssh[bcrypt,fido2,gssapi,
|
|
234
|
+
pip install 'asyncssh[bcrypt,fido2,gssapi,pkcs11,pyOpenSSL]'
|
|
243
235
|
|
|
244
|
-
To install bcrypt, fido2,
|
|
245
|
-
|
|
236
|
+
To install bcrypt, fido2, pkcs11, pyOpenSSL, and pywin32 on Windows,
|
|
237
|
+
you can run:
|
|
246
238
|
|
|
247
239
|
::
|
|
248
240
|
|
|
249
|
-
pip install 'asyncssh[bcrypt,fido2,
|
|
241
|
+
pip install 'asyncssh[bcrypt,fido2,pkcs11,pyOpenSSL,pywin32]'
|
|
250
242
|
|
|
251
|
-
Note that you will still need to manually install the
|
|
252
|
-
|
|
253
|
-
support. Unfortunately, since liboqs, libsodium, and libnettle are not
|
|
243
|
+
Note that you will still need to manually install the libnettle library
|
|
244
|
+
for UMAC support. Unfortunately, since liboqs and libnettle are not
|
|
254
245
|
Python packages, they cannot be directly installed using pip.
|
|
255
246
|
|
|
256
247
|
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
|
------------
|
|
@@ -160,12 +160,6 @@ functionality:
|
|
|
160
160
|
if you want support for the OpenSSH post-quantum key exchange
|
|
161
161
|
algorithms based on ML-KEM and SNTRUP.
|
|
162
162
|
|
|
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
163
|
* Install libnettle from http://www.lysator.liu.se/~nisse/nettle/
|
|
170
164
|
if you want support for UMAC cryptographic hashes.
|
|
171
165
|
|
|
@@ -182,28 +176,26 @@ easy to install any or all of these dependencies:
|
|
|
182
176
|
| bcrypt
|
|
183
177
|
| fido2
|
|
184
178
|
| gssapi
|
|
185
|
-
| libnacl
|
|
186
179
|
| pkcs11
|
|
187
180
|
| pyOpenSSL
|
|
188
181
|
| pywin32
|
|
189
182
|
|
|
190
|
-
For example, to install bcrypt, fido2, gssapi,
|
|
191
|
-
|
|
183
|
+
For example, to install bcrypt, fido2, gssapi, pkcs11, and pyOpenSSL
|
|
184
|
+
on UNIX, you can run:
|
|
192
185
|
|
|
193
186
|
::
|
|
194
187
|
|
|
195
|
-
pip install 'asyncssh[bcrypt,fido2,gssapi,
|
|
188
|
+
pip install 'asyncssh[bcrypt,fido2,gssapi,pkcs11,pyOpenSSL]'
|
|
196
189
|
|
|
197
|
-
To install bcrypt, fido2,
|
|
198
|
-
|
|
190
|
+
To install bcrypt, fido2, pkcs11, pyOpenSSL, and pywin32 on Windows,
|
|
191
|
+
you can run:
|
|
199
192
|
|
|
200
193
|
::
|
|
201
194
|
|
|
202
|
-
pip install 'asyncssh[bcrypt,fido2,
|
|
195
|
+
pip install 'asyncssh[bcrypt,fido2,pkcs11,pyOpenSSL,pywin32]'
|
|
203
196
|
|
|
204
|
-
Note that you will still need to manually install the
|
|
205
|
-
|
|
206
|
-
support. Unfortunately, since liboqs, libsodium, and libnettle are not
|
|
197
|
+
Note that you will still need to manually install the libnettle library
|
|
198
|
+
for UMAC support. Unfortunately, since liboqs and libnettle are not
|
|
207
199
|
Python packages, they cannot be directly installed using pip.
|
|
208
200
|
|
|
209
201
|
Installing the development branch
|
|
@@ -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
|
|
@@ -877,6 +877,7 @@ class SSHConnection(SSHPacketHandler, asyncio.Protocol):
|
|
|
877
877
|
self._peer_addr = ''
|
|
878
878
|
self._peer_port = 0
|
|
879
879
|
self._tcp_keepalive = options.tcp_keepalive
|
|
880
|
+
self._utf8_decode_errors = options.utf8_decode_errors
|
|
880
881
|
self._owner: Optional[Union[SSHClient, SSHServer]] = None
|
|
881
882
|
self._extra: Dict[str, object] = {}
|
|
882
883
|
|
|
@@ -1042,6 +1043,11 @@ class SSHConnection(SSHPacketHandler, asyncio.Protocol):
|
|
|
1042
1043
|
|
|
1043
1044
|
return self._logger
|
|
1044
1045
|
|
|
1046
|
+
def _decode_utf8(self, msg_bytes) -> str:
|
|
1047
|
+
"""Decode UTF-8 bytes, honoring utf8_decode_errors setting"""
|
|
1048
|
+
|
|
1049
|
+
return msg_bytes.decode('utf-8', self._utf8_decode_errors)
|
|
1050
|
+
|
|
1045
1051
|
def _cleanup(self, exc: Optional[Exception]) -> None:
|
|
1046
1052
|
"""Clean up this connection"""
|
|
1047
1053
|
|
|
@@ -1550,8 +1556,7 @@ class SSHConnection(SSHPacketHandler, asyncio.Protocol):
|
|
|
1550
1556
|
|
|
1551
1557
|
self._inpbuf = self._inpbuf[idx+1:]
|
|
1552
1558
|
|
|
1553
|
-
if
|
|
1554
|
-
(self.is_client() and version.startswith(b'SSH-1.99-'))):
|
|
1559
|
+
if version.startswith(b'SSH-2.0-') or version.startswith(b'SSH-1.99-'):
|
|
1555
1560
|
if len(version) > _MAX_VERSION_LINE_LEN:
|
|
1556
1561
|
self._force_close(ProtocolError('Version too long'))
|
|
1557
1562
|
|
|
@@ -2194,7 +2199,7 @@ class SSHConnection(SSHPacketHandler, asyncio.Protocol):
|
|
|
2194
2199
|
packet.check_end()
|
|
2195
2200
|
|
|
2196
2201
|
try:
|
|
2197
|
-
reason =
|
|
2202
|
+
reason = self._decode_utf8(reason_bytes)
|
|
2198
2203
|
lang = lang_bytes.decode('ascii')
|
|
2199
2204
|
except UnicodeDecodeError:
|
|
2200
2205
|
raise ProtocolError('Invalid disconnect message') from None
|
|
@@ -2237,7 +2242,7 @@ class SSHConnection(SSHPacketHandler, asyncio.Protocol):
|
|
|
2237
2242
|
packet.check_end()
|
|
2238
2243
|
|
|
2239
2244
|
try:
|
|
2240
|
-
msg =
|
|
2245
|
+
msg = self._decode_utf8(msg_bytes)
|
|
2241
2246
|
lang = lang_bytes.decode('ascii')
|
|
2242
2247
|
except UnicodeDecodeError:
|
|
2243
2248
|
raise ProtocolError('Invalid debug message') from None
|
|
@@ -2639,7 +2644,7 @@ class SSHConnection(SSHPacketHandler, asyncio.Protocol):
|
|
|
2639
2644
|
packet.check_end()
|
|
2640
2645
|
|
|
2641
2646
|
try:
|
|
2642
|
-
msg =
|
|
2647
|
+
msg = self._decode_utf8(msg_bytes)
|
|
2643
2648
|
lang = lang_bytes.decode('ascii')
|
|
2644
2649
|
except UnicodeDecodeError:
|
|
2645
2650
|
raise ProtocolError('Invalid userauth banner') from None
|
|
@@ -2756,7 +2761,7 @@ class SSHConnection(SSHPacketHandler, asyncio.Protocol):
|
|
|
2756
2761
|
packet.check_end()
|
|
2757
2762
|
|
|
2758
2763
|
try:
|
|
2759
|
-
reason =
|
|
2764
|
+
reason = self._decode_utf8(reason_bytes)
|
|
2760
2765
|
lang = lang_bytes.decode('ascii')
|
|
2761
2766
|
except UnicodeDecodeError:
|
|
2762
2767
|
raise ProtocolError('Invalid channel open failure') from None
|
|
@@ -4169,7 +4174,7 @@ class SSHClientConnection(SSHConnection):
|
|
|
4169
4174
|
async def create_session(self, session_factory: SSHClientSessionFactory,
|
|
4170
4175
|
command: DefTuple[Optional[str]] = (), *,
|
|
4171
4176
|
subsystem: DefTuple[Optional[str]]= (),
|
|
4172
|
-
env: DefTuple[Env] = (),
|
|
4177
|
+
env: DefTuple[Optional[Env]] = (),
|
|
4173
4178
|
send_env: DefTuple[Optional[EnvSeq]] = (),
|
|
4174
4179
|
request_pty: DefTuple[Union[bool, str]] = (),
|
|
4175
4180
|
term_type: DefTuple[Optional[str]] = (),
|
|
@@ -4374,8 +4379,8 @@ class SSHClientConnection(SSHConnection):
|
|
|
4374
4379
|
window: int
|
|
4375
4380
|
max_pktsize: int
|
|
4376
4381
|
|
|
4377
|
-
chan = SSHClientChannel(self, self._loop,
|
|
4378
|
-
window, max_pktsize)
|
|
4382
|
+
chan = SSHClientChannel(self, self._loop, self._utf8_decode_errors,
|
|
4383
|
+
encoding, errors, window, max_pktsize)
|
|
4379
4384
|
|
|
4380
4385
|
session = await chan.create(session_factory, command, subsystem,
|
|
4381
4386
|
new_env, request_pty, term_type, term_size,
|
|
@@ -5687,7 +5692,7 @@ class SSHClientConnection(SSHConnection):
|
|
|
5687
5692
|
return cast(SSHForwarder, peer)
|
|
5688
5693
|
|
|
5689
5694
|
@async_context_manager
|
|
5690
|
-
async def start_sftp_client(self, env: DefTuple[Env] = (),
|
|
5695
|
+
async def start_sftp_client(self, env: DefTuple[Optional[Env]] = (),
|
|
5691
5696
|
send_env: DefTuple[Optional[EnvSeq]] = (),
|
|
5692
5697
|
path_encoding: Optional[str] = 'utf-8',
|
|
5693
5698
|
path_errors = 'strict',
|
|
@@ -5746,9 +5751,9 @@ class SSHClientConnection(SSHConnection):
|
|
|
5746
5751
|
env=env, send_env=send_env,
|
|
5747
5752
|
encoding=None)
|
|
5748
5753
|
|
|
5749
|
-
return await start_sftp_client(self, self._loop,
|
|
5750
|
-
|
|
5751
|
-
sftp_version)
|
|
5754
|
+
return await start_sftp_client(self, self._loop,
|
|
5755
|
+
self._utf8_decode_errors, reader, writer,
|
|
5756
|
+
path_encoding, path_errors, sftp_version)
|
|
5752
5757
|
|
|
5753
5758
|
|
|
5754
5759
|
class SSHServerConnection(SSHConnection):
|
|
@@ -7279,6 +7284,7 @@ class SSHConnectionOptions(Options, Generic[_Options]):
|
|
|
7279
7284
|
family: int
|
|
7280
7285
|
local_addr: HostPort
|
|
7281
7286
|
tcp_keepalive: bool
|
|
7287
|
+
utf8_decode_errors: str
|
|
7282
7288
|
canonicalize_hostname: Union[bool, str]
|
|
7283
7289
|
canonical_domains: Sequence[str]
|
|
7284
7290
|
canonicalize_fallback_local: bool
|
|
@@ -7324,6 +7330,7 @@ class SSHConnectionOptions(Options, Generic[_Options]):
|
|
|
7324
7330
|
passphrase: Optional[BytesOrStr],
|
|
7325
7331
|
proxy_command: DefTuple[_ProxyCommand], family: DefTuple[int],
|
|
7326
7332
|
local_addr: DefTuple[HostPort], tcp_keepalive: DefTuple[bool],
|
|
7333
|
+
utf8_decode_errors: str,
|
|
7327
7334
|
canonicalize_hostname: DefTuple[Union[bool, str]],
|
|
7328
7335
|
canonical_domains: DefTuple[Sequence[str]],
|
|
7329
7336
|
canonicalize_fallback_local: DefTuple[bool],
|
|
@@ -7388,6 +7395,8 @@ class SSHConnectionOptions(Options, Generic[_Options]):
|
|
|
7388
7395
|
self.tcp_keepalive = cast(bool, tcp_keepalive if tcp_keepalive != ()
|
|
7389
7396
|
else config.get('TCPKeepAlive', True))
|
|
7390
7397
|
|
|
7398
|
+
self.utf8_decode_errors = utf8_decode_errors
|
|
7399
|
+
|
|
7391
7400
|
self.canonicalize_hostname = \
|
|
7392
7401
|
cast(Union[bool, str], canonicalize_hostname
|
|
7393
7402
|
if canonicalize_hostname != ()
|
|
@@ -7813,6 +7822,13 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
|
|
|
7813
7822
|
:param tcp_keepalive: (optional)
|
|
7814
7823
|
Whether or not to enable keepalive probes at the TCP level to
|
|
7815
7824
|
detect broken connections, defaulting to `True`.
|
|
7825
|
+
:param utf8_decode_errors: (optional)
|
|
7826
|
+
Error handling strategy to apply when UTF-8 decode errors
|
|
7827
|
+
occur in SSH protocol messages, defaulting to 'strict'
|
|
7828
|
+
which shuts down the connection with a ProtocolError.
|
|
7829
|
+
Choosing other strategies can allow the message parsing
|
|
7830
|
+
to proceed with invalid bytes in the message being removed
|
|
7831
|
+
or replaced.
|
|
7816
7832
|
:param canonicalize_hostname: (optional)
|
|
7817
7833
|
Whether or not to enable hostname canonicalization, defaulting
|
|
7818
7834
|
to `False`, in which case hostnames are passed as-is to the
|
|
@@ -7985,6 +8001,7 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
|
|
|
7985
8001
|
:type keepalive_interval: *see* :ref:`SpecifyingTimeIntervals`
|
|
7986
8002
|
:type keepalive_count_max: `int`
|
|
7987
8003
|
:type tcp_keepalive: `bool`
|
|
8004
|
+
:type utf8_decode_errors: `str`
|
|
7988
8005
|
:type canonicalize_hostname: `bool` or `'always'`
|
|
7989
8006
|
:type canonical_domains: `list` of `str`
|
|
7990
8007
|
:type canonicalize_fallback_local: `bool`
|
|
@@ -8042,7 +8059,7 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
|
|
|
8042
8059
|
pkcs11_pin: Optional[str]
|
|
8043
8060
|
command: Optional[str]
|
|
8044
8061
|
subsystem: Optional[str]
|
|
8045
|
-
env: Env
|
|
8062
|
+
env: Optional[Env]
|
|
8046
8063
|
send_env: Optional[EnvSeq]
|
|
8047
8064
|
request_pty: _RequestPTY
|
|
8048
8065
|
term_type: Optional[str]
|
|
@@ -8070,6 +8087,7 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
|
|
|
8070
8087
|
family: DefTuple[int] = (),
|
|
8071
8088
|
local_addr: DefTuple[HostPort] = (),
|
|
8072
8089
|
tcp_keepalive: DefTuple[bool] = (),
|
|
8090
|
+
utf8_decode_errors: str = 'strict',
|
|
8073
8091
|
canonicalize_hostname: DefTuple[Union[bool, str]] = (),
|
|
8074
8092
|
canonical_domains: DefTuple[Sequence[str]] = (),
|
|
8075
8093
|
canonicalize_fallback_local: DefTuple[bool] = (),
|
|
@@ -8115,7 +8133,8 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
|
|
|
8115
8133
|
pkcs11_provider: DefTuple[Optional[str]] = (),
|
|
8116
8134
|
pkcs11_pin: Optional[str] = None,
|
|
8117
8135
|
command: DefTuple[Optional[str]] = (),
|
|
8118
|
-
subsystem: Optional[str] = None,
|
|
8136
|
+
subsystem: Optional[str] = None,
|
|
8137
|
+
env: DefTuple[Optional[Env]] = (),
|
|
8119
8138
|
send_env: DefTuple[Optional[EnvSeq]] = (),
|
|
8120
8139
|
request_pty: DefTuple[_RequestPTY] = (),
|
|
8121
8140
|
term_type: Optional[str] = None,
|
|
@@ -8180,10 +8199,11 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
|
|
|
8180
8199
|
|
|
8181
8200
|
super().prepare(config, client_factory or SSHClient, client_version,
|
|
8182
8201
|
host, port, tunnel, passphrase, proxy_command, family,
|
|
8183
|
-
local_addr, tcp_keepalive,
|
|
8184
|
-
|
|
8185
|
-
|
|
8186
|
-
|
|
8202
|
+
local_addr, tcp_keepalive, utf8_decode_errors,
|
|
8203
|
+
canonicalize_hostname, canonical_domains,
|
|
8204
|
+
canonicalize_fallback_local, canonicalize_max_dots,
|
|
8205
|
+
canonicalize_permitted_cnames, kex_algs,
|
|
8206
|
+
encryption_algs, mac_algs, compression_algs,
|
|
8187
8207
|
signature_algs, host_based_auth, public_key_auth,
|
|
8188
8208
|
kbdint_auth, password_auth, x509_trusted_certs,
|
|
8189
8209
|
x509_trusted_cert_paths, x509_purposes, rekey_bytes,
|
|
@@ -8354,7 +8374,8 @@ class SSHClientConnectionOptions(SSHConnectionOptions):
|
|
|
8354
8374
|
|
|
8355
8375
|
self.subsystem = subsystem
|
|
8356
8376
|
|
|
8357
|
-
self.env = cast(Env, env if env != () else
|
|
8377
|
+
self.env = cast(Optional[Env], env if env != () else
|
|
8378
|
+
config.get('SetEnv'))
|
|
8358
8379
|
|
|
8359
8380
|
self.send_env = cast(Optional[EnvSeq], send_env if send_env != () else
|
|
8360
8381
|
config.get('SendEnv'))
|
|
@@ -8635,6 +8656,13 @@ class SSHServerConnectionOptions(SSHConnectionOptions):
|
|
|
8635
8656
|
:param tcp_keepalive: (optional)
|
|
8636
8657
|
Whether or not to enable keepalive probes at the TCP level to
|
|
8637
8658
|
detect broken connections, defaulting to `True`.
|
|
8659
|
+
:param utf8_decode_errors: (optional)
|
|
8660
|
+
Error handling strategy to apply when UTF-8 decode errors
|
|
8661
|
+
occur in SSH protocol messages, defaulting to 'strict'
|
|
8662
|
+
which shuts down the connection with a ProtocolError.
|
|
8663
|
+
Choosing other strategies can allow the message parsing
|
|
8664
|
+
to proceed with invalid bytes in the message being removed
|
|
8665
|
+
or replaced.
|
|
8638
8666
|
:param canonicalize_hostname: (optional)
|
|
8639
8667
|
Whether or not to enable hostname canonicalization, defaulting
|
|
8640
8668
|
to `False`, in which case hostnames are passed as-is to the
|
|
@@ -8731,6 +8759,7 @@ class SSHServerConnectionOptions(SSHConnectionOptions):
|
|
|
8731
8759
|
:type keepalive_interval: *see* :ref:`SpecifyingTimeIntervals`
|
|
8732
8760
|
:type keepalive_count_max: `int`
|
|
8733
8761
|
:type tcp_keepalive: `bool`
|
|
8762
|
+
:type utf8_decode_errors: `str`
|
|
8734
8763
|
:type canonicalize_hostname: `bool` or `'always'`
|
|
8735
8764
|
:type canonical_domains: `list` of `str`
|
|
8736
8765
|
:type canonicalize_fallback_local: `bool`
|
|
@@ -8789,6 +8818,7 @@ class SSHServerConnectionOptions(SSHConnectionOptions):
|
|
|
8789
8818
|
family: DefTuple[int] = (),
|
|
8790
8819
|
local_addr: DefTuple[HostPort] = (),
|
|
8791
8820
|
tcp_keepalive: DefTuple[bool] = (),
|
|
8821
|
+
utf8_decode_errors: str = 'strict',
|
|
8792
8822
|
canonicalize_hostname: DefTuple[Union[bool, str]] = (),
|
|
8793
8823
|
canonical_domains: DefTuple[Sequence[str]] = (),
|
|
8794
8824
|
canonicalize_fallback_local: DefTuple[bool] = (),
|
|
@@ -8864,10 +8894,11 @@ class SSHServerConnectionOptions(SSHConnectionOptions):
|
|
|
8864
8894
|
|
|
8865
8895
|
super().prepare(config, server_factory or SSHServer, server_version,
|
|
8866
8896
|
host, port, tunnel, passphrase, proxy_command, family,
|
|
8867
|
-
local_addr, tcp_keepalive,
|
|
8868
|
-
|
|
8869
|
-
|
|
8870
|
-
|
|
8897
|
+
local_addr, tcp_keepalive, utf8_decode_errors,
|
|
8898
|
+
canonicalize_hostname, canonical_domains,
|
|
8899
|
+
canonicalize_fallback_local, canonicalize_max_dots,
|
|
8900
|
+
canonicalize_permitted_cnames, kex_algs,
|
|
8901
|
+
encryption_algs, mac_algs, compression_algs,
|
|
8871
8902
|
signature_algs, host_based_auth, public_key_auth,
|
|
8872
8903
|
kbdint_auth, password_auth, x509_trusted_certs,
|
|
8873
8904
|
x509_trusted_cert_paths, x509_purposes,
|
|
@@ -62,11 +62,11 @@ __all__ = [
|
|
|
62
62
|
'BasicCipher', 'ChachaCipher', 'CryptoKey', 'Curve25519DH', 'Curve448DH',
|
|
63
63
|
'DH', 'DSAPrivateKey', 'DSAPublicKey', 'ECDH', 'ECDSAPrivateKey',
|
|
64
64
|
'ECDSAPublicKey', 'EdDSAPrivateKey', 'EdDSAPublicKey', 'GCMCipher', 'PQDH',
|
|
65
|
-
'PyCAKey', 'RSAPrivateKey', 'RSAPublicKey', '
|
|
66
|
-
'
|
|
67
|
-
'
|
|
68
|
-
'generate_x509_certificate', 'get_cipher_params',
|
|
69
|
-
'
|
|
70
|
-
'register_cipher', 'sntrup_available', 'umac32', 'umac64',
|
|
71
|
-
'umac128'
|
|
65
|
+
'PyCAKey', 'RSAPrivateKey', 'RSAPublicKey', 'X509Certificate',
|
|
66
|
+
'X509Name', 'X509NamePattern', 'chacha_available', 'curve25519_available',
|
|
67
|
+
'curve448_available', 'ed25519_available', 'ed448_available',
|
|
68
|
+
'generate_x509_certificate', 'get_cipher_params',
|
|
69
|
+
'import_x509_certificate', 'lookup_ec_curve_by_params', 'mlkem_available',
|
|
70
|
+
'pbkdf2_hmac', 'register_cipher', 'sntrup_available', 'umac32', 'umac64',
|
|
71
|
+
'umac96', 'umac128'
|
|
72
72
|
]
|