
    VhO                       d Z ddlmZ ddlZddlZddlmZmZm	Z	 ddl
mZ ddlmZ ddlmZmZmZmZ ddlmZ dd	lmZmZmZ dd
lmZ ddlmZmZmZ ddlm Z  ddl!m"Z" ddl#m$Z$ ddl%m&Z& ddl'm(Z( ddl)m*Z* ddl+m,Z,  e$       Z-d"dZ.d#dZ/ G d d      Z0 ee       G d de0             Z1 ee       G d d             Z2d$dZ3 ee       G d de0e,             Z4 G d d      Z5 G d  d!      Z6y)%zE
An implementation of the OpenSSH known_hosts database.

@since: 8.2
    )annotationsN)Error
a2b_base64
b2a_base64)closing)sha1)IOCallableIterableLiteral)implementer)HostKeyChangedInvalidEntryUserRejectedKey)IKnownHostEntry)BadKeyErrorFingerprintFormatsKey)defer)Deferred)Logger)nativeString)FilePath)secureRandom)FancyEqMixinc                4    t        |       j                         S )z
    Encode a binary string as base64 with no trailing newline.

    @param s: The string to encode.

    @return: The base64-encoded string.
    )r   strip)ss    O/home/dcms/DCMS/lib/python3.12/site-packages/twisted/conch/client/knownhosts.py
_b64encoder    $   s     a=      c                &   | j                  dd      }t        |      dk7  r
t               |\  }}}|j                  dd      }t        |      dk(  r|\  }}|j                  d      }n|d   }d}t	        j
                  t        |            }||||fS )a  
    Extract common elements of base64 keys from an entry in a hosts file.

    @param string: A known hosts file entry (a single line).

    @return: a 4-tuple of hostname data (L{bytes}), ssh key type (L{bytes}), key
        (L{Key}), and comment (L{bytes} or L{None}).  The hostname data is
        simply the beginning of the line up to the first occurrence of
        whitespace.
    N            
r   )splitlenr   rstripr   
fromStringr   )	stringelements	hostnameskeyTypekeyAndCommentsplitkey	keyStringcommentkeys	            r   _extractCommonr4   /   s     ||D!$H
8}n(0%Iw""4+H
8}%	7..'QK	
..I.
/CgsG++r!   c                       e Zd ZdZddZddZy)
_BaseEntrya  
    Abstract base of both hashed and non-hashed entry objects, since they
    represent keys and key types the same way.

    @ivar keyType: The type of the key; either ssh-dss or ssh-rsa.
    @type keyType: L{bytes}

    @ivar publicKey: The server public key indicated by this line.
    @type publicKey: L{twisted.conch.ssh.keys.Key}

    @ivar comment: Trailing garbage after the key line.
    @type comment: L{bytes} or C{None}
    c                .    || _         || _        || _        y N)r.   	publicKeyr2   )selfr.   r9   r2   s       r   __init__z_BaseEntry.__init__X   s    "r!   c                $    | j                   |k(  }|S )z
        Check to see if this entry matches a given key object.

        @param keyObject: A public key object to check.

        @return: C{True} if this entry's key matches C{keyObject}, C{False}
            otherwise.
        )r9   )r:   	keyObjectresults      r   
matchesKeyz_BaseEntry.matchesKey]   s     9,r!   N)r.   bytesr9   r   r2   bytes | NonereturnNone)r=   r   rB   bool)__name__
__module____qualname____doc__r;   r?    r!   r   r6   r6   I   s    

r!   r6   c                  V     e Zd ZdZ	 	 	 	 	 	 	 	 d fdZedd       ZddZd	dZ xZ	S )

PlainEntryz
    A L{PlainEntry} is a representation of a plain-text entry in a known_hosts
    file.

    @ivar _hostnames: the list of all host-names associated with this entry.
    c                6    || _         t        | 	  |||       y r8   )
_hostnamessuperr;   )r:   r-   r.   r9   r2   	__class__s        r   r;   zPlainEntry.__init__s   s     (1)W5r!   c                Z    t        |      \  }}}} | |j                  d      |||      }|S )a  
        Parse a plain-text entry in a known_hosts file, and return a
        corresponding L{PlainEntry}.

        @param string: a space-separated string formatted like "hostname
            key-type base64-key-data comment".

        @raise DecodeError: if the key is not valid encoded as valid base64.

        @raise InvalidEntry: if the entry does not have the right number of
            elements and is therefore invalid.

        @raise BadKeyError: if the key, once decoded from base64, is not
            actually an SSH key.

        @return: an IKnownHostEntry representing the hostname and key in the
            input line.

        @rtype: L{PlainEntry}
           ,)r4   r'   )clsr+   r-   r.   r3   r2   r:   s          r   r*   zPlainEntry.fromString}   s5    , ,:&+A(	7C9??4('3@r!   c                `    t        |t              r|j                  d      }|| j                  v S )a  
        Check to see if this entry matches a given hostname.

        @param hostname: A hostname or IP address literal to check against this
            entry.

        @return: C{True} if this entry is for the given hostname or IP address,
            C{False} otherwise.
        utf-8)
isinstancestrencoderM   r:   hostnames     r   matchesHostzPlainEntry.matchesHost   s+     h$w/H4??**r!   c                   dj                  | j                        | j                  t        | j                  j                               g}| j                  |j                  | j                         dj                  |      S )z
        Implement L{IKnownHostEntry.toString} by recording the comma-separated
        hostnames, key type, and base-64 encoded key.

        @return: The string representation of this entry, with unhashed hostname
            information.
        rQ       )joinrM   r.   r    r9   blobr2   appendr:   fieldss     r   toStringzPlainEntry.toString   sb     IIdoo&LLt~~**,-

 <<#MM$,,'yy  r!   )r-   zlist[bytes]r.   r@   r9   r   r2   rA   )r+   r@   rB   rK   )rY   bytes | strrB   rD   rB   r@   )
rE   rF   rG   rH   r;   classmethodr*   rZ   rb   __classcell__rO   s   @r   rK   rK   j   sQ    66 6 	6
 6  2+!r!   rK   c                  @    e Zd ZU dZdZded<   d	dZd
dZddZddZ	y)UnparsedEntryz
    L{UnparsedEntry} is an entry in a L{KnownHostsFile} which can't actually be
    parsed; therefore it matches no keys and no hosts.
    NrC   r.   c                    || _         y)zv
        Create an unparsed entry from a line in a known_hosts file which cannot
        otherwise be parsed.
        N)_string)r:   r+   s     r   r;   zUnparsedEntry.__init__   s    
 r!   c                     yz'
        Always returns False.
        FrI   rX   s     r   rZ   zUnparsedEntry.matchesHost        r!   c                     yrm   rI   )r:   r3   s     r   r?   zUnparsedEntry.matchesKey   rn   r!   c                8    | j                   j                  d      S )a  
        Returns the input line, without its newline if one was given.

        @return: The string representation of this entry, almost exactly as was
            used to initialize this entry but without a trailing newline.
        @rtype: L{bytes}
        r&   )rk   r)   r:   s    r   rb   zUnparsedEntry.toString   s     ||""5))r!   )r+   r@   rB   rC   rY   r@   rB   rD   )r3   r   rB   rD   rd   )
rE   rF   rG   rH   r.   __annotations__r;   rZ   r?   rb   rI   r!   r   ri   ri      s'    
 GT*r!   ri   c                    t        j                  | t              }t        |t              r|j                  d      }|j                  |       |j                         S )z
    Return the SHA-1 HMAC hash of the given key and string.

    @param key: The HMAC key.

    @param string: The string to be hashed.

    @return: The keyed hash value.
    )	digestmodrT   )hmacHMACr   rU   rV   rW   updatedigest)r3   r+   hashs      r   _hmacedStringr{      sD     99SD)D&#w'KK;;=r!   c                  f     e Zd ZdZdZdZ	 	 	 	 	 	 	 	 	 	 	 	 d fdZed	d       Zd
dZ	ddZ
 xZS )HashedEntrya  
    A L{HashedEntry} is a representation of an entry in a known_hosts file
    where the hostname has been hashed and salted.

    @ivar _hostSalt: the salt to combine with a hostname for hashing.

    @ivar _hostHash: the hashed representation of the hostname.

    @cvar MAGIC: the 'hash magic' string used to identify a hashed line in a
    known_hosts file as opposed to a plaintext one.
    s   |1|)	_hostSalt	_hostHashr.   r9   r2   c                D    || _         || _        t        |   |||       y r8   )r~   r   rN   r;   )r:   hostSalthostHashr.   r9   r2   rO   s         r   r;   zHashedEntry.__init__  s$     "!)W5r!   c                    t        |      \  }}}}|t        | j                        d j                  d      }t        |      dk7  r
t	               |\  }} | t        |      t        |      |||      }	|	S )a  
        Load a hashed entry from a string representing a line in a known_hosts
        file.

        @param string: A complete single line from a I{known_hosts} file,
            formatted as defined by OpenSSH.

        @raise DecodeError: if the key, the hostname, or the is not valid
            encoded as valid base64

        @raise InvalidEntry: if the entry does not have the right number of
            elements and is therefore invalid, or the host/hash portion
            contains more items than just the host and hash.

        @raise BadKeyError: if the key, once decoded from base64, is not
            actually an SSH key.

        @return: The newly created L{HashedEntry} instance, initialized with
            the information from C{string}.
        N   |r#   )r4   r(   MAGICr'   r   r   )
rR   r+   stuffr.   r3   r2   saltAndHashr   r   r:   s
             r   r*   zHashedEntry.fromString  sw    , (6f'=$wWC		N,-33D9{q . ((:h'H)=wWUr!   c                j    t        j                  t        | j                  |      | j                        S )a  
        Implement L{IKnownHostEntry.matchesHost} to compare the hash of the
        input to the stored hash.

        @param hostname: A hostname or IP address literal to check against this
            entry.
        @type hostname: L{bytes}

        @return: C{True} if this entry is for the given hostname or IP address,
            C{False} otherwise.
        @rtype: L{bool}
        )rv   compare_digestr{   r~   r   rX   s     r   rZ   zHashedEntry.matchesHost+  s+     ""$..(3T^^
 	
r!   c                Z   | j                   dj                  t        | j                        t        | j                        g      z   | j
                  t        | j                  j                               g}| j                  |j                  | j                         dj                  |      S )z
        Implement L{IKnownHostEntry.toString} by base64-encoding the salt, host
        hash, and key.

        @return: The string representation of this entry, with the hostname part
            hashed.
        @rtype: L{bytes}
        r   r\   )
r   r]   r    r~   r   r.   r9   r^   r2   r_   r`   s     r   rb   zHashedEntry.toString<  s     JJiiDNN3Z5OPQRLLt~~**,-	
 <<#MM$,,'yy  r!   )r   r@   r   r@   r.   r@   r9   r   r2   rA   rB   rC   )r+   r@   rB   r}   rr   rd   )rE   rF   rG   rH   r   compareAttributesr;   re   r*   rZ   rb   rf   rg   s   @r   r}   r}      sr    
 EU
6
6 
6 	
6
 
6 
6 

6  :
"!r!   r}   c                  x    e Zd ZdZddZedd       ZddZddZ	 	 	 	 	 	 	 	 	 	 ddZ	ddZ
ddZedd	       Zy
)KnownHostsFileaz  
    A structured representation of an OpenSSH-format ~/.ssh/known_hosts file.

    @ivar _added: A list of L{IKnownHostEntry} providers which have been added
        to this instance in memory but not yet saved.

    @ivar _clobber: A flag indicating whether the current contents of the save
        path will be disregarded and potentially overwritten or not.  If
        C{True}, this will be done.  If C{False}, entries in the save path will
        be read and new entries will be saved by appending rather than
        overwriting.
    @type _clobber: L{bool}

    @ivar _savePath: See C{savePath} parameter of L{__init__}.
    c                .    g | _         || _        d| _        y)a$  
        Create a new, empty KnownHostsFile.

        Unless you want to erase the current contents of C{savePath}, you want
        to use L{KnownHostsFile.fromPath} instead.

        @param savePath: The L{FilePath} to which to save new entries.
        @type savePath: L{FilePath}
        TN)_added	_savePath_clobber)r:   savePaths     r   r;   zKnownHostsFile.__init__a  s     .0!r!   c                    | j                   S )z<
        @see: C{savePath} parameter of L{__init__}
        )r   rq   s    r   r   zKnownHostsFile.savePatho  s    
 ~~r!   c              #    K   | j                   D ]  }|  | j                  ry	 | j                  j                         }|5  |D ]Q  }	 |j                  t        j                        rt        j                  |      }nt        j                  |      }| S 	 ddd       y# t        $ r Y yw xY w# t        t        t        f$ r t        |      }Y @w xY w# 1 sw Y   yxY ww)aK  
        Iterate over the host entries in this file.

        @return: An iterable the elements of which provide L{IKnownHostEntry}.
            There is an element for each entry in the file as well as an element
            for each added but not yet saved entry.
        @rtype: iterable of L{IKnownHostEntry} providers
        N)r   r   r   openOSError
startswithr}   r   r*   rK   DecodeErrorr   r   ri   )r:   entryfplines       r   iterentrieszKnownHostsFile.iterentriesv  s      [[ 	EK	 ==	$$&B  		 0{'8'89 + 6 6t < * 5 5d ; 		 		  		 $\;? 0)$/E0		 		se   #C#B#  C#C	A
B2C	C##	B/,C#.B//C#2CCCCC C#c                D   t        | j                         t        | j                               D ]o  \  }}|j                  |j                         k(  s$|j                  |      s6|j                  |      r y|dk  rd}d}n|dz   }| j                  }t        |||       y)a  
        Check for an entry with matching hostname and key.

        @param hostname: A hostname or IP address literal to check for.

        @param key: The public key to check for.

        @return: C{True} if the given hostname and key are present in this
            file, C{False} if they are not.

        @raise HostKeyChanged: if the host key found for the given hostname
            does not match the given key.
        Tr   Nr%   F)
	enumerater   r(   r   r.   sshTyperZ   r?   r   r   )r:   rY   r3   lineidxr   r   paths          r   
hasHostKeyzKnownHostsFile.hasHostKey  s     ((8(8(:S=M<MN 	<NGU}}-%2C2CH2M##C( {##&{#~~(d;;	< r!   c                     t        j                   j                        }d fd}|j                  |      S )a  
        Verify the given host key for the given IP and host, asking for
        confirmation from, and notifying, the given UI about changes to this
        file.

        @param ui: The user interface to request an IP address from.

        @param hostname: The hostname that the user requested to connect to.

        @param ip: The string representation of the IP address that is actually
        being connected to.

        @param key: The public key of the server.

        @return: a L{Deferred} that fires with True when the key has been
            verified, or fires with an errback when the key either cannot be
            verified or has changed.
        @rtype: L{Deferred}
        c           
     B   | r{	j                        sgdj                          dj                          d}
j                  |j	                  d             	j                         	j                          | S d	fd}j                         }|dk(  rd}dt              d	t              d
|dj                  t        j                        d	}
j                  |j	                  t        j                                     }|j                  |      S )NzWarning: Permanently added the z host key for IP address 'z' to the list of known hosts.
rT   c                    | r6j                         j                         j                          | S t               r8   )
addHostKeysaver   )responserY   ipr3   r:   s    r   promptResponsezGKnownHostsFile.verifyHostKey.<locals>.gotHasKey.<locals>.promptResponse  s9    #6C0		'-//r!   ECECDSAzThe authenticity of host 'z (z)' can't be established.
z key fingerprint is SHA256:)formatz9.
Are you sure you want to continue connecting (yes/no)? )r   rD   rB   rD   )r   typedecodewarnrW   r   r   r   fingerprintr   SHA256_BASE64promptsysgetdefaultencodingaddCallback)r>   
addMessager   keytyper   proceedrY   r   r3   r:   uis         r   	gotHasKeyz/KnownHostsFile.verifyHostKey.<locals>.gotHasKey  s   r3/9#((* F,,.IIK= 9$$ 
 GGJ--g67OOB,IIK0 0  #xxzd?%G %X.$R(/A/O/OP	  ))FMM#2H2H2J$KL**>::r!   )r>   rD   rB   zbool | Deferred[bool])r   executer   r   )r:   r   rY   r   r3   hhkr   s   `````  r   verifyHostKeyzKnownHostsFile.verifyHostKey  s7    , mmDOOXs;)	; )	;V y))r!   c                    t        d      }|j                         }t        |t        ||      ||d      }| j                  j                  |       |S )a  
        Add a new L{HashedEntry} to the key database.

        Note that you still need to call L{KnownHostsFile.save} if you wish
        these changes to be persisted.

        @param hostname: A hostname or IP address literal to associate with the
            new entry.
        @type hostname: L{bytes}

        @param key: The public key to associate with the new entry.
        @type key: L{Key}

        @return: The L{HashedEntry} that was added.
        @rtype: L{HashedEntry}
           N)r   r   r}   r{   r   r_   )r:   rY   r3   saltr.   r   s         r   r   zKnownHostsFile.addHostKey  sI    " B++-D-h"?#tT5!r!   c           
        | j                   j                         }|j                         s|j                          | j                  rdnd}| j                   j                  |      5 }| j                  rP|j                  dj                  | j                  D cg c]  }|j                          c}      dz          g | _        ddd       d| _        yc c}w # 1 sw Y   d| _        yxY w)zM
        Save this L{KnownHostsFile} to the path it was loaded from.
        war&   NF)
r   parentisdirmakedirsr   r   r   writer]   rb   )r:   pmodehostsFileObjr   s        r   r   zKnownHostsFile.save  s     NN!!#wwyJJL)-#C^^  & 	!,{{""JJdkkJU 0JKeS !	!   K	! s   &1CC.CCC(c                $     | |      }d|_         |S )a  
        Create a new L{KnownHostsFile}, potentially reading existing known
        hosts information from the given file.

        @param path: A path object to use for both reading contents from and
            later saving to.  If no file exists at this path, it is not an
            error; a L{KnownHostsFile} with no entries is returned.

        @return: A L{KnownHostsFile} initialized with entries from C{path}.
        F)r   )rR   r   
knownHostss      r   fromPathzKnownHostsFile.fromPath   s     Y
#
r!   N)r   FilePath[str]rB   rC   )rB   r   )rB   zIterable[IKnownHostEntry])rY   r@   r3   r   rB   rD   )
r   	ConsoleUIrY   r@   r   r@   r3   r   rB   Deferred[bool])rY   r@   r3   r   rB   r}   )rB   rC   )r   r   rB   r   )rE   rF   rG   rH   r;   propertyr   r   r   r   r   r   re   r   rI   r!   r   r   r   P  s|       ><C*C*',C*27C*>AC*	C*J."  r!   r   c                  (    e Zd ZdZddZddZddZy)	r   z
    A UI object that can ask true/false questions and post notifications on the
    console, to be used during key verification.
    c                    || _         y)aA  
        @param opener: A no-argument callable which should open a console
            binary-mode file-like object to be used for reading and writing.
            This initializes the C{opener} attribute.
        @type opener: callable taking no arguments and returning a read/write
            file-like object
        N)opener)r:   r   s     r   r;   zConsoleUI.__init__7  s     r!   c                ^     t        j                  d      } fd}|j                  |      S )a  
        Write the given text as a prompt to the console output, then read a
        result from the console input.

        @param text: Something to present to a user to solicit a yes or no
            response.
        @type text: L{bytes}

        @return: a L{Deferred} which fires with L{True} when the user answers
            'yes' and L{False} when the user answers 'no'.  It may errback if
            there were any I/O errors.
        Nc                *   t        j                               5 }|j                         	 |j                         j	                         j                         }|dk(  r
	 d d d        y|dv r
	 d d d        y|j                  d       [# 1 sw Y   y xY w)NTs   yes>      nor!   Fs   Please type 'yes' or 'no': )r   r   r   readliner   lower)ignoredfanswerr:   texts      r   bodyzConsoleUI.prompt.<locals>.bodyP  s    ' 	@1ZZ\//1779F'#	@ 	@  </$	@ 	@  >? 	@ 	@s   AB	)B	7B		B)r   succeedr   )r:   r   dr   s   ``  r   r   zConsoleUI.promptA  s*     MM$
	@ }}T""r!   c                    	 t        | j                               5 }|j                  |       ddd       y# 1 sw Y   yxY w# t        $ r t        j                  d       Y yw xY w)z
        Notify the user (non-interactively) of the provided text, by writing it
        to the console.

        @param text: Some information the user is to be made aware of.
        NzFailed to write to console)r   r   r   	Exceptionlogfailure)r:   r   r   s      r   r   zConsoleUI.warn^  sR    	6' 1   	6KK45	6s(   A 6A ?A A A#"A#N)r   zCallable[[], IO[bytes]]rB   rC   )r   r@   rB   r   )r   r@   rB   rC   )rE   rF   rG   rH   r;   r   r   rI   r!   r   r   r   1  s    
#:6r!   r   )r   r@   rB   r@   )r+   r@   rB   z&tuple[bytes, bytes, Key, bytes | None])r3   r@   r+   rc   rB   r@   )7rH   
__future__r   rv   r   binasciir   r   r   r   
contextlibr   hashlibr   typingr	   r
   r   r   zope.interfacer   twisted.conch.errorr   r   r   twisted.conch.interfacesr   twisted.conch.ssh.keysr   r   r   twisted.internetr   twisted.internet.deferr   twisted.loggerr   twisted.python.compatr   twisted.python.filepathr   twisted.python.randbytesr   twisted.python.utilr   r   r    r4   r6   rK   ri   r{   r}   r   r   rI   r!   r   <module>r      s   
 #  
 A A   2 2 & M M 4 G G " + ! . , 1 ,h!,4 B _I! I! I!X _#* #* #*L" _]!*l ]! ]!@^ ^B86 86r!   