8b97a77413294c159b92b5cbc12b0074a154b88b
Marco Ricci Update copyright notices to...

Marco Ricci authored 2 days ago

src/derivepassphrase/ssh_agent.py            1) # SPDX-FileCopyrightText: 2025 Marco Ricci <software@the13thletter.info>
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py             2) #
Marco Ricci Update copyright notices to...

Marco Ricci authored 2 days ago

src/derivepassphrase/ssh_agent.py            3) # SPDX-License-Identifier: Zlib
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py             4) 
src/ssh_agent_client/__init__.py             5) """A bare-bones SSH agent client supporting signing and key listing."""
src/ssh_agent_client/__init__.py             6) 
src/ssh_agent_client/__init__.py             7) from __future__ import annotations
src/ssh_agent_client/__init__.py             8) 
src/ssh_agent_client/__init__.py             9) import collections
Marco Ricci Support one-off SSH agent c...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py           10) import contextlib
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py            11) import os
src/ssh_agent_client/__init__.py            12) import socket
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py           13) from typing import TYPE_CHECKING, overload
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py            14) 
Marco Ricci Support one-off SSH agent c...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py           15) from typing_extensions import Self, assert_never
Marco Ricci Support Python 3.10 and PyP...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py            16) 
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

src/derivepassphrase/ssh_agent/__init__.py  17) from derivepassphrase import _types
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py            18) 
src/ssh_agent_client/__init__.py            19) if TYPE_CHECKING:
Marco Ricci Support one-off SSH agent c...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py           20)     from collections.abc import Iterable, Iterator, Sequence
Marco Ricci Decouple deterministic sign...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py           21)     from collections.abc import Set as AbstractSet
Marco Ricci Fix import from stdlib modu...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py            22)     from types import TracebackType
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py            23) 
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py           24)     from typing_extensions import Buffer
src/derivepassphrase/ssh_agent.py           25) 
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py            26) __all__ = ('SSHAgentClient',)
Marco Ricci Change the author e-mail ad...

Marco Ricci authored 4 months ago

src/derivepassphrase/ssh_agent.py           27) __author__ = 'Marco Ricci <software@the13thletter.info>'
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py            28) 
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py            29) # In SSH bytestrings, the "length" of the byte string is stored as
src/ssh_agent_client/__init__.py            30) # a 4-byte/32-bit unsigned integer at the beginning.
src/ssh_agent_client/__init__.py            31) HEAD_LEN = 4
src/ssh_agent_client/__init__.py            32) 
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py            33) _socket = socket
src/ssh_agent_client/__init__.py            34) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py            35) 
Marco Ricci Introduce TrailingDataError...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py            36) class TrailingDataError(RuntimeError):
src/ssh_agent_client/__init__.py            37)     """The result contained trailing data."""
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py            38) 
Marco Ricci Fix typing issues in mypy s...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py            39)     def __init__(self) -> None:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py            40)         super().__init__('Overlong response from SSH agent')
Marco Ricci Introduce TrailingDataError...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py            41) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py            42) 
Marco Ricci Add a specific error class...

Marco Ricci authored 4 months ago

src/derivepassphrase/ssh_agent.py           43) class SSHAgentFailedError(RuntimeError):
src/derivepassphrase/ssh_agent.py           44)     """The SSH agent failed to complete the requested operation."""
src/derivepassphrase/ssh_agent.py           45) 
src/derivepassphrase/ssh_agent.py           46)     def __str__(self) -> str:
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py           47)         # Use match/case here once Python 3.9 becomes unsupported.
src/derivepassphrase/ssh_agent.py           48)         if self.args == (  # pragma: no branch
src/derivepassphrase/ssh_agent.py           49)             _types.SSH_AGENT.FAILURE.value,
src/derivepassphrase/ssh_agent.py           50)             b'',
src/derivepassphrase/ssh_agent.py           51)         ):
src/derivepassphrase/ssh_agent.py           52)             return 'The SSH agent failed to complete the request'
src/derivepassphrase/ssh_agent.py           53)         elif self.args[1]:  # noqa: RET505  # pragma: no cover
src/derivepassphrase/ssh_agent.py           54)             code = self.args[0]
src/derivepassphrase/ssh_agent.py           55)             msg = self.args[1].decode('utf-8', 'surrogateescape')
src/derivepassphrase/ssh_agent.py           56)             return f'[Code {code:d}] {msg:s}'
src/derivepassphrase/ssh_agent.py           57)         else:  # pragma: no cover
src/derivepassphrase/ssh_agent.py           58)             return repr(self)
Marco Ricci Add a specific error class...

Marco Ricci authored 4 months ago

src/derivepassphrase/ssh_agent.py           59) 
src/derivepassphrase/ssh_agent.py           60)     def __repr__(self) -> str:  # pragma: no cover
src/derivepassphrase/ssh_agent.py           61)         return f'{self.__class__.__name__}{self.args!r}'
src/derivepassphrase/ssh_agent.py           62) 
src/derivepassphrase/ssh_agent.py           63) 
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py            64) class SSHAgentClient:
src/ssh_agent_client/__init__.py            65)     """A bare-bones SSH agent client supporting signing and key listing.
src/ssh_agent_client/__init__.py            66) 
src/ssh_agent_client/__init__.py            67)     The main use case is requesting the agent sign some data, after
src/ssh_agent_client/__init__.py            68)     checking that the necessary key is already loaded.
src/ssh_agent_client/__init__.py            69) 
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py           70)     The main fleshed out methods are [`list_keys`][] and [`sign`][],
src/derivepassphrase/ssh_agent.py           71)     which implement the [`REQUEST_IDENTITIES`]
src/derivepassphrase/ssh_agent.py           72)     [_types.SSH_AGENTC.REQUEST_IDENTITIES] and [`SIGN_REQUEST`]
src/derivepassphrase/ssh_agent.py           73)     [_types.SSH_AGENTC.SIGN_REQUEST] requests.  If you *really* wanted
src/derivepassphrase/ssh_agent.py           74)     to, there is enough infrastructure in place to issue other requests
src/derivepassphrase/ssh_agent.py           75)     as defined in the protocol---it's merely the wrapper functions and
src/derivepassphrase/ssh_agent.py           76)     the protocol numbers table that are missing.
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py            77) 
src/ssh_agent_client/__init__.py            78)     """
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py            79) 
Marco Ricci Remove public attributes of...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py            80)     _connection: socket.socket
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py            81) 
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py            82)     def __init__(
src/ssh_agent_client/__init__.py            83)         self, /, *, socket: socket.socket | None = None, timeout: int = 125
src/ssh_agent_client/__init__.py            84)     ) -> None:
src/ssh_agent_client/__init__.py            85)         """Initialize the client.
src/ssh_agent_client/__init__.py            86) 
src/ssh_agent_client/__init__.py            87)         Args:
src/ssh_agent_client/__init__.py            88)             socket:
Marco Ricci Fail gracefully if UNIX dom...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py           89)                 An optional socket, already connected to the SSH agent.
src/derivepassphrase/ssh_agent.py           90)                 If not given, we query the `SSH_AUTH_SOCK` environment
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py            91)                 variable to auto-discover the correct socket address.
Marco Ricci Fail gracefully if UNIX dom...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py           92) 
src/derivepassphrase/ssh_agent.py           93)                 [We currently only support connecting via UNIX domain
src/derivepassphrase/ssh_agent.py           94)                 sockets][issue13], and only on platforms with support
src/derivepassphrase/ssh_agent.py           95)                 for [`socket.AF_UNIX`][AF_UNIX].
src/derivepassphrase/ssh_agent.py           96) 
src/derivepassphrase/ssh_agent.py           97)                 [issue13]: https://github.com/the-13th-letter/derivepassphrase/issues/13
src/derivepassphrase/ssh_agent.py           98)                 [AF_UNIX]: https://docs.python.org/3/library/socket.html#socket.AF_UNIX
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py            99)             timeout:
src/ssh_agent_client/__init__.py           100)                 A connection timeout for the SSH agent.  Only used if
src/ssh_agent_client/__init__.py           101)                 the socket is not yet connected.  The default value
src/ssh_agent_client/__init__.py           102)                 gives ample time for agent connections forwarded via
src/ssh_agent_client/__init__.py           103)                 SSH on high-latency networks (e.g. Tor).
src/ssh_agent_client/__init__.py           104) 
Marco Ricci Distinguish errors when con...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           105)         Raises:
src/ssh_agent_client/__init__.py           106)             KeyError:
Marco Ricci Fail gracefully if UNIX dom...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          107)                 The `SSH_AUTH_SOCK` environment variable was not found.
src/derivepassphrase/ssh_agent.py          108)             NotImplementedError:
src/derivepassphrase/ssh_agent.py          109)                 This Python version does not support UNIX domain
src/derivepassphrase/ssh_agent.py          110)                 sockets, necessary to automatically connect to a running
src/derivepassphrase/ssh_agent.py          111)                 SSH agent via the `SSH_AUTH_SOCK` environment variable.
Marco Ricci Distinguish errors when con...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           112)             OSError:
src/ssh_agent_client/__init__.py           113)                 There was an error setting up a socket connection to the
src/ssh_agent_client/__init__.py           114)                 agent.
src/ssh_agent_client/__init__.py           115) 
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           116)         """
src/ssh_agent_client/__init__.py           117)         if socket is not None:
Marco Ricci Remove public attributes of...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           118)             self._connection = socket
src/ssh_agent_client/__init__.py           119)             # Test whether the socket is connected.
src/ssh_agent_client/__init__.py           120)             self._connection.getpeername()
Marco Ricci Fail gracefully if UNIX dom...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          121)         else:
src/derivepassphrase/ssh_agent.py          122)             if not hasattr(_socket, 'AF_UNIX'):
src/derivepassphrase/ssh_agent.py          123)                 msg = (
src/derivepassphrase/ssh_agent.py          124)                     'This Python version does not support UNIX domain sockets'
src/derivepassphrase/ssh_agent.py          125)                 )
src/derivepassphrase/ssh_agent.py          126)                 raise NotImplementedError(msg)
src/derivepassphrase/ssh_agent.py          127)             self._connection = _socket.socket(family=_socket.AF_UNIX)
Marco Ricci Distinguish errors when con...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           128)             if 'SSH_AUTH_SOCK' not in os.environ:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           129)                 msg = 'SSH_AUTH_SOCK environment variable'
Marco Ricci Fail gracefully if UNIX dom...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          130)                 raise KeyError(msg)
Marco Ricci Distinguish errors when con...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           131)             ssh_auth_sock = os.environ['SSH_AUTH_SOCK']
Marco Ricci Remove public attributes of...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           132)             self._connection.settimeout(timeout)
Marco Ricci Distinguish errors when con...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           133)             self._connection.connect(ssh_auth_sock)
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           134) 
src/ssh_agent_client/__init__.py           135)     def __enter__(self) -> Self:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

src/derivepassphrase/ssh_agent.py          136)         """Close socket connection upon context manager completion.
src/derivepassphrase/ssh_agent.py          137) 
src/derivepassphrase/ssh_agent.py          138)         Returns:
src/derivepassphrase/ssh_agent.py          139)             Self.
src/derivepassphrase/ssh_agent.py          140) 
src/derivepassphrase/ssh_agent.py          141)         """
Marco Ricci Remove public attributes of...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           142)         self._connection.__enter__()
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           143)         return self
src/ssh_agent_client/__init__.py           144) 
src/ssh_agent_client/__init__.py           145)     def __exit__(
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           146)         self,
src/ssh_agent_client/__init__.py           147)         exc_type: type[BaseException] | None,
src/ssh_agent_client/__init__.py           148)         exc_val: BaseException | None,
Marco Ricci Fix import from stdlib modu...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           149)         exc_tb: TracebackType | None,
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           150)     ) -> bool:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

src/derivepassphrase/ssh_agent.py          151)         """Close socket connection upon context manager completion.
src/derivepassphrase/ssh_agent.py          152) 
src/derivepassphrase/ssh_agent.py          153)         Args:
src/derivepassphrase/ssh_agent.py          154)             exc_type: An optional exception type.
src/derivepassphrase/ssh_agent.py          155)             exc_val: An optional exception value.
src/derivepassphrase/ssh_agent.py          156)             exc_tb: An optional exception traceback.
src/derivepassphrase/ssh_agent.py          157) 
src/derivepassphrase/ssh_agent.py          158)         Returns:
src/derivepassphrase/ssh_agent.py          159)             True if the exception was handled, false if it should
src/derivepassphrase/ssh_agent.py          160)             propagate.
src/derivepassphrase/ssh_agent.py          161) 
src/derivepassphrase/ssh_agent.py          162)         """
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           163)         return bool(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           164)             self._connection.__exit__(exc_type, exc_val, exc_tb)  # type: ignore[func-returns-value]
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           165)         )
src/ssh_agent_client/__init__.py           166) 
src/ssh_agent_client/__init__.py           167)     @staticmethod
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           168)     def uint32(num: int, /) -> bytes:
src/ssh_agent_client/__init__.py           169)         r"""Format the number as a `uint32`, as per the agent protocol.
src/ssh_agent_client/__init__.py           170) 
src/ssh_agent_client/__init__.py           171)         Args:
src/ssh_agent_client/__init__.py           172)             num: A number.
src/ssh_agent_client/__init__.py           173) 
src/ssh_agent_client/__init__.py           174)         Returns:
src/ssh_agent_client/__init__.py           175)             The number in SSH agent wire protocol format, i.e. as
src/ssh_agent_client/__init__.py           176)             a 32-bit big endian number.
src/ssh_agent_client/__init__.py           177) 
src/ssh_agent_client/__init__.py           178)         Raises:
src/ssh_agent_client/__init__.py           179)             OverflowError:
src/ssh_agent_client/__init__.py           180)                 As per [`int.to_bytes`][].
src/ssh_agent_client/__init__.py           181) 
src/ssh_agent_client/__init__.py           182)         Examples:
src/ssh_agent_client/__init__.py           183)             >>> SSHAgentClient.uint32(16777216)
src/ssh_agent_client/__init__.py           184)             b'\x01\x00\x00\x00'
src/ssh_agent_client/__init__.py           185) 
src/ssh_agent_client/__init__.py           186)         """
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           187)         return int.to_bytes(num, 4, 'big', signed=False)
src/ssh_agent_client/__init__.py           188) 
src/ssh_agent_client/__init__.py           189)     @classmethod
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          190)     def string(cls, payload: Buffer, /) -> bytes:
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           191)         r"""Format the payload as an SSH string, as per the agent protocol.
src/ssh_agent_client/__init__.py           192) 
src/ssh_agent_client/__init__.py           193)         Args:
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          194)             payload: A bytes-like object.
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           195) 
src/ssh_agent_client/__init__.py           196)         Returns:
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          197)             The payload, framed in the SSH agent wire protocol format,
src/derivepassphrase/ssh_agent.py          198)             as a bytes object.
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           199) 
src/ssh_agent_client/__init__.py           200)         Examples:
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          201)             >>> SSHAgentClient.string(b'ssh-rsa')
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           202)             b'\x00\x00\x00\x07ssh-rsa'
src/ssh_agent_client/__init__.py           203) 
src/ssh_agent_client/__init__.py           204)         """
Marco Ricci Fix numerous argument type...

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           205)         try:
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          206)             payload = memoryview(payload)
src/derivepassphrase/ssh_agent.py          207)         except TypeError as e:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           208)             msg = 'invalid payload type'
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

src/derivepassphrase/ssh_agent.py          209)             raise TypeError(msg) from e  # noqa: DOC501
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          210)         ret = bytearray()
src/derivepassphrase/ssh_agent.py          211)         ret.extend(cls.uint32(len(payload)))
src/derivepassphrase/ssh_agent.py          212)         ret.extend(payload)
src/derivepassphrase/ssh_agent.py          213)         return bytes(ret)
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           214) 
src/ssh_agent_client/__init__.py           215)     @classmethod
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          216)     def unstring(cls, bytestring: Buffer, /) -> bytes:
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           217)         r"""Unpack an SSH string.
src/ssh_agent_client/__init__.py           218) 
src/ssh_agent_client/__init__.py           219)         Args:
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          220)             bytestring: A framed bytes-like object.
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           221) 
src/ssh_agent_client/__init__.py           222)         Returns:
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          223)             The payload, as a bytes object.
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           224) 
src/ssh_agent_client/__init__.py           225)         Raises:
src/ssh_agent_client/__init__.py           226)             ValueError:
Marco Ricci Add function for SSH framed...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           227)                 The byte string is not an SSH string.
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           228) 
src/ssh_agent_client/__init__.py           229)         Examples:
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          230)             >>> SSHAgentClient.unstring(b'\x00\x00\x00\x07ssh-rsa')
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           231)             b'ssh-rsa'
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          232)             >>> SSHAgentClient.unstring(SSHAgentClient.string(b'ssh-ed25519'))
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           233)             b'ssh-ed25519'
src/ssh_agent_client/__init__.py           234) 
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          235)         """
src/derivepassphrase/ssh_agent.py          236)         bytestring = memoryview(bytestring)
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           237)         n = len(bytestring)
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           238)         msg = 'malformed SSH byte string'
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           239)         if n < HEAD_LEN or n != HEAD_LEN + int.from_bytes(
src/ssh_agent_client/__init__.py           240)             bytestring[:HEAD_LEN], 'big', signed=False
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           241)         ):
src/ssh_agent_client/__init__.py           242)             raise ValueError(msg)
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          243)         return bytes(bytestring[HEAD_LEN:])
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           244) 
Marco Ricci Add function for SSH framed...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           245)     @classmethod
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          246)     def unstring_prefix(cls, bytestring: Buffer, /) -> tuple[bytes, bytes]:
Marco Ricci Add function for SSH framed...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           247)         r"""Unpack an SSH string at the beginning of the byte string.
src/ssh_agent_client/__init__.py           248) 
src/ssh_agent_client/__init__.py           249)         Args:
src/ssh_agent_client/__init__.py           250)             bytestring:
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          251)                 A bytes-like object, beginning with a framed/SSH byte
src/derivepassphrase/ssh_agent.py          252)                 string.
Marco Ricci Add function for SSH framed...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           253) 
src/ssh_agent_client/__init__.py           254)         Returns:
src/ssh_agent_client/__init__.py           255)             A 2-tuple `(a, b)`, where `a` is the unframed byte
src/ssh_agent_client/__init__.py           256)             string/payload at the beginning of input byte string, and
src/ssh_agent_client/__init__.py           257)             `b` is the remainder of the input byte string.
src/ssh_agent_client/__init__.py           258) 
src/ssh_agent_client/__init__.py           259)         Raises:
src/ssh_agent_client/__init__.py           260)             ValueError:
src/ssh_agent_client/__init__.py           261)                 The byte string does not begin with an SSH string.
src/ssh_agent_client/__init__.py           262) 
src/ssh_agent_client/__init__.py           263)         Examples:
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          264)             >>> SSHAgentClient.unstring_prefix(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           265)             ...     b'\x00\x00\x00\x07ssh-rsa____trailing data'
src/ssh_agent_client/__init__.py           266)             ... )
Marco Ricci Add function for SSH framed...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           267)             (b'ssh-rsa', b'____trailing data')
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          268)             >>> SSHAgentClient.unstring_prefix(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           269)             ...     SSHAgentClient.string(b'ssh-ed25519')
src/ssh_agent_client/__init__.py           270)             ... )
Marco Ricci Add function for SSH framed...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           271)             (b'ssh-ed25519', b'')
src/ssh_agent_client/__init__.py           272) 
src/ssh_agent_client/__init__.py           273)         """
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          274)         bytestring = memoryview(bytestring).toreadonly()
Marco Ricci Add function for SSH framed...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           275)         n = len(bytestring)
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           276)         msg = 'malformed SSH byte string'
src/ssh_agent_client/__init__.py           277)         if n < HEAD_LEN:
src/ssh_agent_client/__init__.py           278)             raise ValueError(msg)
src/ssh_agent_client/__init__.py           279)         m = int.from_bytes(bytestring[:HEAD_LEN], 'big', signed=False)
src/ssh_agent_client/__init__.py           280)         if m + HEAD_LEN > n:
src/ssh_agent_client/__init__.py           281)             raise ValueError(msg)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           282)         return (
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          283)             bytes(bytestring[HEAD_LEN : m + HEAD_LEN]),
src/derivepassphrase/ssh_agent.py          284)             bytes(bytestring[m + HEAD_LEN :]),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           285)         )
Marco Ricci Add function for SSH framed...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           286) 
Marco Ricci Support one-off SSH agent c...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py          287)     @classmethod
src/derivepassphrase/ssh_agent.py          288)     @contextlib.contextmanager
src/derivepassphrase/ssh_agent.py          289)     def ensure_agent_subcontext(
src/derivepassphrase/ssh_agent.py          290)         cls,
src/derivepassphrase/ssh_agent.py          291)         conn: SSHAgentClient | socket.socket | None = None,
src/derivepassphrase/ssh_agent.py          292)     ) -> Iterator[SSHAgentClient]:
src/derivepassphrase/ssh_agent.py          293)         """Return an SSH agent client subcontext.
src/derivepassphrase/ssh_agent.py          294) 
src/derivepassphrase/ssh_agent.py          295)         If necessary, construct an SSH agent client first using the
src/derivepassphrase/ssh_agent.py          296)         connection hint.
src/derivepassphrase/ssh_agent.py          297) 
src/derivepassphrase/ssh_agent.py          298)         Args:
src/derivepassphrase/ssh_agent.py          299)             conn:
src/derivepassphrase/ssh_agent.py          300)                 If an existing SSH agent client, then enter a context
src/derivepassphrase/ssh_agent.py          301)                 within this client's scope.  After exiting the context,
src/derivepassphrase/ssh_agent.py          302)                 the client persists, including its socket.
src/derivepassphrase/ssh_agent.py          303) 
src/derivepassphrase/ssh_agent.py          304)                 If a socket, then construct a client using this socket,
src/derivepassphrase/ssh_agent.py          305)                 then enter a context within this client's scope.  After
src/derivepassphrase/ssh_agent.py          306)                 exiting the context, the client is destroyed and the
src/derivepassphrase/ssh_agent.py          307)                 socket is closed.
src/derivepassphrase/ssh_agent.py          308) 
src/derivepassphrase/ssh_agent.py          309)                 If `None`, construct a client using agent
src/derivepassphrase/ssh_agent.py          310)                 auto-discovery, then enter a context within this
src/derivepassphrase/ssh_agent.py          311)                 client's scope.  After exiting the context, both the
src/derivepassphrase/ssh_agent.py          312)                 client and its socket are destroyed.
src/derivepassphrase/ssh_agent.py          313) 
src/derivepassphrase/ssh_agent.py          314)         Yields:
src/derivepassphrase/ssh_agent.py          315)             When entering this context, return the SSH agent client.
src/derivepassphrase/ssh_agent.py          316) 
src/derivepassphrase/ssh_agent.py          317)         Raises:
src/derivepassphrase/ssh_agent.py          318)             KeyError:
src/derivepassphrase/ssh_agent.py          319)                 `conn` was `None`, and the `SSH_AUTH_SOCK` environment
src/derivepassphrase/ssh_agent.py          320)                 variable was not found.
src/derivepassphrase/ssh_agent.py          321)             NotImplementedError:
src/derivepassphrase/ssh_agent.py          322)                 `conn` was `None`, and this Python does not support
src/derivepassphrase/ssh_agent.py          323)                 [`socket.AF_UNIX`][], so the SSH agent client cannot be
src/derivepassphrase/ssh_agent.py          324)                 automatically set up.
src/derivepassphrase/ssh_agent.py          325)             OSError:
src/derivepassphrase/ssh_agent.py          326)                 `conn` was a socket or `None`, and there was an error
src/derivepassphrase/ssh_agent.py          327)                 setting up a socket connection to the agent.
src/derivepassphrase/ssh_agent.py          328) 
src/derivepassphrase/ssh_agent.py          329)         """
src/derivepassphrase/ssh_agent.py          330)         # Use match/case here once Python 3.9 becomes unsupported.
src/derivepassphrase/ssh_agent.py          331)         if isinstance(conn, SSHAgentClient):
src/derivepassphrase/ssh_agent.py          332)             with contextlib.nullcontext():
src/derivepassphrase/ssh_agent.py          333)                 yield conn
src/derivepassphrase/ssh_agent.py          334)         elif isinstance(conn, socket.socket) or conn is None:
src/derivepassphrase/ssh_agent.py          335)             with SSHAgentClient(socket=conn) as client:
src/derivepassphrase/ssh_agent.py          336)                 yield client
src/derivepassphrase/ssh_agent.py          337)         else:  # pragma: no cover
src/derivepassphrase/ssh_agent.py          338)             assert_never(conn)
src/derivepassphrase/ssh_agent.py          339)             msg = f'invalid connection hint: {conn!r}'
src/derivepassphrase/ssh_agent.py          340)             raise TypeError(msg)  # noqa: DOC501
src/derivepassphrase/ssh_agent.py          341) 
Marco Ricci Decouple deterministic sign...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py          342)     def _agent_is_pageant(self) -> bool:
src/derivepassphrase/ssh_agent.py          343)         """Return True if we are connected to Pageant.
src/derivepassphrase/ssh_agent.py          344) 
src/derivepassphrase/ssh_agent.py          345)         Warning:
src/derivepassphrase/ssh_agent.py          346)             This is a heuristic, not a verified query or computation.
src/derivepassphrase/ssh_agent.py          347) 
src/derivepassphrase/ssh_agent.py          348)         """
src/derivepassphrase/ssh_agent.py          349)         return (
src/derivepassphrase/ssh_agent.py          350)             b'list-extended@putty.projects.tartarus.org'
src/derivepassphrase/ssh_agent.py          351)             in self.query_extensions()
src/derivepassphrase/ssh_agent.py          352)         )
src/derivepassphrase/ssh_agent.py          353) 
Marco Ricci Publish polished `is_suitab...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py          354)     def has_deterministic_dsa_signatures(self) -> bool:
src/derivepassphrase/ssh_agent.py          355)         """Check whether the agent returns deterministic DSA signatures.
src/derivepassphrase/ssh_agent.py          356) 
src/derivepassphrase/ssh_agent.py          357)         This includes ECDSA signatures.
src/derivepassphrase/ssh_agent.py          358) 
src/derivepassphrase/ssh_agent.py          359)         Generally, this means that the SSH agent implements [RFC 6979][]
src/derivepassphrase/ssh_agent.py          360)         or a similar system.
src/derivepassphrase/ssh_agent.py          361) 
src/derivepassphrase/ssh_agent.py          362)         [RFC 6979]: https://www.rfc-editor.org/rfc/rfc6979
Marco Ricci Support the "all signatures...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py          363) 
src/derivepassphrase/ssh_agent.py          364)         Returns:
src/derivepassphrase/ssh_agent.py          365)             True if a known agent was detected where signatures are
Marco Ricci Publish polished `is_suitab...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py          366)             deterministic for all DSA key types, false otherwise.
Marco Ricci Support the "all signatures...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py          367) 
src/derivepassphrase/ssh_agent.py          368)         Note: Known agents with deterministic signatures
src/derivepassphrase/ssh_agent.py          369)             | agent           | detected via                                                  |
src/derivepassphrase/ssh_agent.py          370)             |:----------------|:--------------------------------------------------------------|
src/derivepassphrase/ssh_agent.py          371)             | Pageant (PuTTY) | `list-extended@putty.projects.tartarus.org` extension request |
src/derivepassphrase/ssh_agent.py          372) 
src/derivepassphrase/ssh_agent.py          373)         """  # noqa: E501
Marco Ricci Decouple deterministic sign...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py          374)         known_good_agents = {
src/derivepassphrase/ssh_agent.py          375)             'Pageant': self._agent_is_pageant,
src/derivepassphrase/ssh_agent.py          376)         }
src/derivepassphrase/ssh_agent.py          377)         return any(  # pragma: no branch
src/derivepassphrase/ssh_agent.py          378)             v() for v in known_good_agents.values()
Marco Ricci Support the "all signatures...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py          379)         )
src/derivepassphrase/ssh_agent.py          380) 
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          381)     @overload
Marco Ricci Fix formatting, some covera...

Marco Ricci authored 2 weeks ago

src/derivepassphrase/ssh_agent.py          382)     def request(
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          383)         self,
src/derivepassphrase/ssh_agent.py          384)         code: int | _types.SSH_AGENTC,
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          385)         payload: Buffer,
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          386)         /,
src/derivepassphrase/ssh_agent.py          387)         *,
src/derivepassphrase/ssh_agent.py          388)         response_code: None = None,
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          389)     ) -> tuple[int, bytes]: ...
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          390) 
src/derivepassphrase/ssh_agent.py          391)     @overload
Marco Ricci Fix formatting, some covera...

Marco Ricci authored 2 weeks ago

src/derivepassphrase/ssh_agent.py          392)     def request(
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          393)         self,
src/derivepassphrase/ssh_agent.py          394)         code: int | _types.SSH_AGENTC,
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          395)         payload: Buffer,
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          396)         /,
src/derivepassphrase/ssh_agent.py          397)         *,
src/derivepassphrase/ssh_agent.py          398)         response_code: Iterable[_types.SSH_AGENT | int] = frozenset({
src/derivepassphrase/ssh_agent.py          399)             _types.SSH_AGENT.SUCCESS
src/derivepassphrase/ssh_agent.py          400)         }),
Marco Ricci Fix spurious overloaded sig...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py          401)     ) -> bytes: ...
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          402) 
src/derivepassphrase/ssh_agent.py          403)     @overload
Marco Ricci Fix formatting, some covera...

Marco Ricci authored 2 weeks ago

src/derivepassphrase/ssh_agent.py          404)     def request(
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          405)         self,
src/derivepassphrase/ssh_agent.py          406)         code: int | _types.SSH_AGENTC,
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          407)         payload: Buffer,
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          408)         /,
src/derivepassphrase/ssh_agent.py          409)         *,
src/derivepassphrase/ssh_agent.py          410)         response_code: _types.SSH_AGENT | int = _types.SSH_AGENT.SUCCESS,
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          411)     ) -> bytes: ...
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          412) 
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           413)     def request(
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          414)         self,
src/derivepassphrase/ssh_agent.py          415)         code: int | _types.SSH_AGENTC,
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          416)         payload: Buffer,
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          417)         /,
src/derivepassphrase/ssh_agent.py          418)         *,
src/derivepassphrase/ssh_agent.py          419)         response_code: (
src/derivepassphrase/ssh_agent.py          420)             Iterable[_types.SSH_AGENT | int] | _types.SSH_AGENT | int | None
src/derivepassphrase/ssh_agent.py          421)         ) = None,
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          422)     ) -> tuple[int, bytes] | bytes:
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           423)         """Issue a generic request to the SSH agent.
src/ssh_agent_client/__init__.py           424) 
src/ssh_agent_client/__init__.py           425)         Args:
src/ssh_agent_client/__init__.py           426)             code:
src/ssh_agent_client/__init__.py           427)                 The request code.  See the SSH agent protocol for
src/ssh_agent_client/__init__.py           428)                 protocol numbers to use here (and which protocol numbers
src/ssh_agent_client/__init__.py           429)                 to expect in a response).
src/ssh_agent_client/__init__.py           430)             payload:
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          431)                 A bytes-like object containing the payload, or
src/derivepassphrase/ssh_agent.py          432)                 "contents", of the request.  Request-specific.
src/derivepassphrase/ssh_agent.py          433) 
src/derivepassphrase/ssh_agent.py          434)                 It is our responsibility to add any necessary wire
src/derivepassphrase/ssh_agent.py          435)                 framing around the request code and the payload,
src/derivepassphrase/ssh_agent.py          436)                 not the caller's.
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          437)             response_code:
src/derivepassphrase/ssh_agent.py          438)                 An optional response code, or a set of response codes,
src/derivepassphrase/ssh_agent.py          439)                 that we expect.  If given, and the actual response code
src/derivepassphrase/ssh_agent.py          440)                 does not match, raise an error.
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           441) 
src/ssh_agent_client/__init__.py           442)         Returns:
src/ssh_agent_client/__init__.py           443)             A 2-tuple consisting of the response code and the payload,
src/ssh_agent_client/__init__.py           444)             with all wire framing removed.
src/ssh_agent_client/__init__.py           445) 
Marco Ricci Fix bad documentation for S...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          446)             If a response code was passed, then only return the payload.
src/derivepassphrase/ssh_agent.py          447) 
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           448)         Raises:
src/ssh_agent_client/__init__.py           449)             EOFError:
src/ssh_agent_client/__init__.py           450)                 The response from the SSH agent is truncated or missing.
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          451)             OSError:
src/derivepassphrase/ssh_agent.py          452)                 There was a communication error with the SSH agent.
src/derivepassphrase/ssh_agent.py          453)             SSHAgentFailedError:
src/derivepassphrase/ssh_agent.py          454)                 We expected specific response codes, but did not receive
src/derivepassphrase/ssh_agent.py          455)                 any of them.
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           456) 
src/ssh_agent_client/__init__.py           457)         """
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          458)         if isinstance(  # pragma: no branch
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          459)             response_code, (int, _types.SSH_AGENT)
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          460)         ):
src/derivepassphrase/ssh_agent.py          461)             response_code = frozenset({response_code})
src/derivepassphrase/ssh_agent.py          462)         if response_code is not None:  # pragma: no branch
src/derivepassphrase/ssh_agent.py          463)             response_code = frozenset({
src/derivepassphrase/ssh_agent.py          464)                 c if isinstance(c, int) else c.value for c in response_code
src/derivepassphrase/ssh_agent.py          465)             })
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          466)         payload = memoryview(payload)
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          467)         request_message = bytearray([
src/derivepassphrase/ssh_agent.py          468)             code if isinstance(code, int) else code.value
src/derivepassphrase/ssh_agent.py          469)         ])
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           470)         request_message.extend(payload)
Marco Ricci Remove public attributes of...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           471)         self._connection.sendall(self.string(request_message))
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           472)         chunk = self._connection.recv(HEAD_LEN)
src/ssh_agent_client/__init__.py           473)         if len(chunk) < HEAD_LEN:
src/ssh_agent_client/__init__.py           474)             msg = 'cannot read response length'
src/ssh_agent_client/__init__.py           475)             raise EOFError(msg)
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           476)         response_length = int.from_bytes(chunk, 'big', signed=False)
Marco Ricci Remove public attributes of...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           477)         response = self._connection.recv(response_length)
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           478)         if len(response) < response_length:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           479)             msg = 'truncated response from SSH agent'
src/ssh_agent_client/__init__.py           480)             raise EOFError(msg)
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          481)         if not response_code:  # pragma: no cover
src/derivepassphrase/ssh_agent.py          482)             return response[0], response[1:]
src/derivepassphrase/ssh_agent.py          483)         if response[0] not in response_code:
src/derivepassphrase/ssh_agent.py          484)             raise SSHAgentFailedError(response[0], response[1:])
src/derivepassphrase/ssh_agent.py          485)         return response[1:]
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           486) 
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

src/derivepassphrase/ssh_agent/__init__.py 487)     def list_keys(self) -> Sequence[_types.KeyCommentPair]:
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           488)         """Request a list of keys known to the SSH agent.
src/ssh_agent_client/__init__.py           489) 
src/ssh_agent_client/__init__.py           490)         Returns:
src/ssh_agent_client/__init__.py           491)             A read-only sequence of key/comment pairs.
src/ssh_agent_client/__init__.py           492) 
src/ssh_agent_client/__init__.py           493)         Raises:
src/ssh_agent_client/__init__.py           494)             EOFError:
src/ssh_agent_client/__init__.py           495)                 The response from the SSH agent is truncated or missing.
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          496)             OSError:
src/derivepassphrase/ssh_agent.py          497)                 There was a communication error with the SSH agent.
Marco Ricci Introduce TrailingDataError...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           498)             TrailingDataError:
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           499)                 The response from the SSH agent is too long.
Marco Ricci Add a specific error class...

Marco Ricci authored 4 months ago

src/derivepassphrase/ssh_agent.py          500)             SSHAgentFailedError:
Marco Ricci Introduce TrailingDataError...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           501)                 The agent failed to complete the request.
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           502) 
src/ssh_agent_client/__init__.py           503)         """
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          504)         response = self.request(
src/derivepassphrase/ssh_agent.py          505)             _types.SSH_AGENTC.REQUEST_IDENTITIES.value,
src/derivepassphrase/ssh_agent.py          506)             b'',
src/derivepassphrase/ssh_agent.py          507)             response_code=_types.SSH_AGENT.IDENTITIES_ANSWER,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           508)         )
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           509)         response_stream = collections.deque(response)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           510) 
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           511)         def shift(num: int) -> bytes:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           512)             buf = collections.deque(b'')
src/ssh_agent_client/__init__.py           513)             for _ in range(num):
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           514)                 try:
src/ssh_agent_client/__init__.py           515)                     val = response_stream.popleft()
src/ssh_agent_client/__init__.py           516)                 except IndexError:
src/ssh_agent_client/__init__.py           517)                     response_stream.extendleft(reversed(buf))
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           518)                     msg = 'truncated response from SSH agent'
src/ssh_agent_client/__init__.py           519)                     raise EOFError(msg) from None
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           520)                 buf.append(val)
src/ssh_agent_client/__init__.py           521)             return bytes(buf)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           522) 
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           523)         key_count = int.from_bytes(shift(4), 'big')
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

src/derivepassphrase/ssh_agent/__init__.py 524)         keys: collections.deque[_types.KeyCommentPair]
Marco Ricci Fix Google code style viola...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           525)         keys = collections.deque()
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           526)         for _ in range(key_count):
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           527)             key_size = int.from_bytes(shift(4), 'big')
src/ssh_agent_client/__init__.py           528)             key = shift(key_size)
src/ssh_agent_client/__init__.py           529)             comment_size = int.from_bytes(shift(4), 'big')
src/ssh_agent_client/__init__.py           530)             comment = shift(comment_size)
src/ssh_agent_client/__init__.py           531)             # Both `key` and `comment` are not wrapped as SSH strings.
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

src/derivepassphrase/ssh_agent/__init__.py 532)             keys.append(_types.KeyCommentPair(key, comment))
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           533)         if response_stream:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           534)             raise TrailingDataError
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           535)         return keys
src/ssh_agent_client/__init__.py           536) 
src/ssh_agent_client/__init__.py           537)     def sign(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           538)         self,
src/ssh_agent_client/__init__.py           539)         /,
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          540)         key: Buffer,
src/derivepassphrase/ssh_agent.py          541)         payload: Buffer,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           542)         *,
src/ssh_agent_client/__init__.py           543)         flags: int = 0,
src/ssh_agent_client/__init__.py           544)         check_if_key_loaded: bool = False,
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          545)     ) -> bytes:
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           546)         """Request the SSH agent sign the payload with the key.
src/ssh_agent_client/__init__.py           547) 
src/ssh_agent_client/__init__.py           548)         Args:
src/ssh_agent_client/__init__.py           549)             key:
src/ssh_agent_client/__init__.py           550)                 The public SSH key to sign the payload with, in the same
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          551)                 format as returned by, e.g., the [`list_keys`][] method.
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           552)                 The corresponding private key must have previously been
src/ssh_agent_client/__init__.py           553)                 loaded into the agent to successfully issue a signature.
src/ssh_agent_client/__init__.py           554)             payload:
src/ssh_agent_client/__init__.py           555)                 A byte string of data to sign.
src/ssh_agent_client/__init__.py           556)             flags:
src/ssh_agent_client/__init__.py           557)                 Optional flags for the signing request.  Currently
src/ssh_agent_client/__init__.py           558)                 passed on as-is to the agent.  In real-world usage, this
src/ssh_agent_client/__init__.py           559)                 could be used, e.g., to request more modern hash
src/ssh_agent_client/__init__.py           560)                 algorithms when signing with RSA keys.  (No such
src/ssh_agent_client/__init__.py           561)                 real-world usage is currently implemented.)
src/ssh_agent_client/__init__.py           562)             check_if_key_loaded:
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          563)                 If true, check beforehand (via [`list_keys`][]) if the
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           564)                 corresponding key has been loaded into the agent.
src/ssh_agent_client/__init__.py           565) 
src/ssh_agent_client/__init__.py           566)         Returns:
src/ssh_agent_client/__init__.py           567)             The binary signature of the payload under the given key.
src/ssh_agent_client/__init__.py           568) 
src/ssh_agent_client/__init__.py           569)         Raises:
src/ssh_agent_client/__init__.py           570)             EOFError:
src/ssh_agent_client/__init__.py           571)                 The response from the SSH agent is truncated or missing.
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          572)             OSError:
src/derivepassphrase/ssh_agent.py          573)                 There was a communication error with the SSH agent.
Marco Ricci Introduce TrailingDataError...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           574)             TrailingDataError:
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           575)                 The response from the SSH agent is too long.
Marco Ricci Add a specific error class...

Marco Ricci authored 4 months ago

src/derivepassphrase/ssh_agent.py          576)             SSHAgentFailedError:
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           577)                 The agent failed to complete the request.
Marco Ricci Raise KeyError when signing...

Marco Ricci authored 6 months ago

src/ssh_agent_client/__init__.py           578)             KeyError:
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           579)                 `check_if_key_loaded` is true, and the `key` was not
src/ssh_agent_client/__init__.py           580)                 loaded into the agent.
src/ssh_agent_client/__init__.py           581) 
src/ssh_agent_client/__init__.py           582)         """
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          583)         key = memoryview(key)
src/derivepassphrase/ssh_agent.py          584)         payload = memoryview(payload)
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           585)         if check_if_key_loaded:
src/ssh_agent_client/__init__.py           586)             loaded_keys = frozenset({pair.key for pair in self.list_keys()})
src/ssh_agent_client/__init__.py           587)             if bytes(key) not in loaded_keys:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           588)                 msg = 'target SSH key not loaded into agent'
src/ssh_agent_client/__init__.py           589)                 raise KeyError(msg)
Marco Ricci Add prototype implementation

Marco Ricci authored 7 months ago

src/ssh_agent_client/__init__.py           590)         request_data = bytearray(self.string(key))
src/ssh_agent_client/__init__.py           591)         request_data.extend(self.string(payload))
src/ssh_agent_client/__init__.py           592)         request_data.extend(self.uint32(flags))
Marco Ricci Add proper support for Buff...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          593)         return bytes(
src/derivepassphrase/ssh_agent.py          594)             self.unstring(
src/derivepassphrase/ssh_agent.py          595)                 self.request(
src/derivepassphrase/ssh_agent.py          596)                     _types.SSH_AGENTC.SIGN_REQUEST.value,
src/derivepassphrase/ssh_agent.py          597)                     request_data,
src/derivepassphrase/ssh_agent.py          598)                     response_code=_types.SSH_AGENT.SIGN_RESPONSE,
src/derivepassphrase/ssh_agent.py          599)                 )
Marco Ricci Support passing expected SS...

Marco Ricci authored 3 months ago

src/derivepassphrase/ssh_agent.py          600)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

src/ssh_agent_client/__init__.py           601)         )
Marco Ricci Decouple deterministic sign...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py          602) 
src/derivepassphrase/ssh_agent.py          603)     def query_extensions(self) -> AbstractSet[bytes]:
Marco Ricci Publish polished `is_suitab...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py          604)         """Request a listing of extensions supported by the SSH agent.
Marco Ricci Decouple deterministic sign...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py          605) 
src/derivepassphrase/ssh_agent.py          606)         Returns:
Marco Ricci Publish polished `is_suitab...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py          607)             A read-only set of extension names the SSH agent says it
src/derivepassphrase/ssh_agent.py          608)             supports.
Marco Ricci Decouple deterministic sign...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py          609) 
src/derivepassphrase/ssh_agent.py          610)         Raises:
src/derivepassphrase/ssh_agent.py          611)             EOFError:
src/derivepassphrase/ssh_agent.py          612)                 The response from the SSH agent is truncated or missing.
src/derivepassphrase/ssh_agent.py          613)             OSError:
src/derivepassphrase/ssh_agent.py          614)                 There was a communication error with the SSH agent.
Marco Ricci Publish polished `is_suitab...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py          615)             RuntimeError:
src/derivepassphrase/ssh_agent.py          616)                 The response from the SSH agent is malformed.
src/derivepassphrase/ssh_agent.py          617) 
src/derivepassphrase/ssh_agent.py          618)         Note:
src/derivepassphrase/ssh_agent.py          619)             The set of supported extensions is queried via the `query`
src/derivepassphrase/ssh_agent.py          620)             extension request.  If the agent does not support the query
src/derivepassphrase/ssh_agent.py          621)             extension request, or extension requests in general, then an
src/derivepassphrase/ssh_agent.py          622)             empty set is returned.  This does not however imply that the
src/derivepassphrase/ssh_agent.py          623)             agent doesn't support *any* extension request... merely that
src/derivepassphrase/ssh_agent.py          624)             it doesn't support extension autodiscovery.
Marco Ricci Decouple deterministic sign...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py          625) 
src/derivepassphrase/ssh_agent.py          626)         """
src/derivepassphrase/ssh_agent.py          627)         try:
src/derivepassphrase/ssh_agent.py          628)             response_data = self.request(
src/derivepassphrase/ssh_agent.py          629)                 _types.SSH_AGENTC.EXTENSION,
src/derivepassphrase/ssh_agent.py          630)                 self.string(b'query'),
src/derivepassphrase/ssh_agent.py          631)                 response_code={
src/derivepassphrase/ssh_agent.py          632)                     _types.SSH_AGENT.EXTENSION_RESPONSE,
src/derivepassphrase/ssh_agent.py          633)                     _types.SSH_AGENT.SUCCESS,
src/derivepassphrase/ssh_agent.py          634)                 },
src/derivepassphrase/ssh_agent.py          635)             )
src/derivepassphrase/ssh_agent.py          636)         except SSHAgentFailedError:
src/derivepassphrase/ssh_agent.py          637)             # Cannot query extension support.  Assume no extensions.
src/derivepassphrase/ssh_agent.py          638)             # This isn't necessarily true, e.g. for OpenSSH's ssh-agent.
src/derivepassphrase/ssh_agent.py          639)             return frozenset()
src/derivepassphrase/ssh_agent.py          640)         extensions: set[bytes] = set()
Marco Ricci Publish polished `is_suitab...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py          641)         msg = 'Malformed response from SSH agent'
src/derivepassphrase/ssh_agent.py          642)         msg2 = 'Extension response message does not match request'
src/derivepassphrase/ssh_agent.py          643)         try:
src/derivepassphrase/ssh_agent.py          644)             _query, response_data = self.unstring_prefix(response_data)
src/derivepassphrase/ssh_agent.py          645)         except ValueError as e:
src/derivepassphrase/ssh_agent.py          646)             raise RuntimeError(msg) from e
src/derivepassphrase/ssh_agent.py          647)         if bytes(_query) != b'query':
src/derivepassphrase/ssh_agent.py          648)             raise RuntimeError(msg2)
Marco Ricci Decouple deterministic sign...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py          649)         while response_data:
Marco Ricci Publish polished `is_suitab...

Marco Ricci authored 1 month ago

src/derivepassphrase/ssh_agent.py          650)             try:
src/derivepassphrase/ssh_agent.py          651)                 extension, response_data = self.unstring_prefix(response_data)
src/derivepassphrase/ssh_agent.py          652)             except ValueError as e:
src/derivepassphrase/ssh_agent.py          653)                 raise RuntimeError(msg) from e
src/derivepassphrase/ssh_agent.py          654)             else:
src/derivepassphrase/ssh_agent.py          655)                 extensions.add(bytes(extension))