o
    ,                     @   sd   d Z ddlZddlZddlZddlZddlmZ ddlmZ dd ZefddZ	G d	d
 d
e
ZdS )zHID Transport for U2F.

This module imports the U2F HID Transport protocol as well as methods
for discovering devices implementing this protocol.
    N)errors)hidc                 C   s    | d dkr| d dkrdS dS )N
usage_pagei  usage   TF )devicer   r   ;/tmp/google-cloud-sdk/lib/third_party/pyu2f/hidtransport.pyHidUsageSelector   s   r
   c              	   c   sL    t  D ]}| |r#zt |d }t|V  W q ty"   Y qw qd S )Npath)r   	EnumerateOpenUsbHidTransportOSError)selectorddevr   r   r	   DiscoverLocalHIDU2FDevices#   s   r   c                   @   s   e Zd ZdZdZdZdZdZdZdZ	dZ
d	Zeg d
ZedgZG dd deZG dd deZd(ddZdd Zdd Zdd Zdd Zdd Zdd Zdd  Zd!d" Zd#d$ Zd%d& Zd'S ))r   am  Implements the U2FHID transport protocol.

  This class implements the U2FHID transport protocol from the
  FIDO U2F specs.  This protocol manages fragmenting longer messages
  over a short hid frame (usually 64 bytes).  It exposes an APDU
  channel through the MSG command as well as a series of other commands
  for configuring and interacting with the device.
                          )   r   r   r      c                   @   ,   e Zd ZdZdd Zdd Zedd ZdS )	zUsbHidTransport.InitPacketa  Represent an initial U2FHID packet.

    Represent an initial U2FHID packet.  This packet contains
    metadata necessary to interpret the entire packet stream associated
    with a particular exchange (read or write).

    Attributes:
      packet_size: The size of the hid report (packet) used.  Usually 64.
      cid: The channel id for the connection to the device.
      size: The size of the entire message to be sent (including
          all continuation packets)
      payload: The portion of the message to put into the init packet.
          This must be smaller than packet_size - 7 (the overhead for
          an init packet).
    c                 C   s`   || _ t|dks|dks|dkrt t|| j d kr"t || _|| _|| _|| _d S )N   r   i      )packet_sizelenr   InvalidPacketErrorcidcmdsizepayload)selfr!   r$   r%   r&   r'   r   r   r	   __init__V   s   
z#UsbHidTransport.InitPacket.__init__c                 C   sX   t d}| j|dd< | j|d< td|d| j | j|ddt| j < tt	t
|S )Serializes the packet.@   r   r   >H   r    )	bytearrayr$   r%   struct	pack_intor&   r'   r"   listmapintr(   retr   r   r	   ToWireFormatb   s   
z'UsbHidTransport.InitPacket.ToWireFormatc                 C   sn   t |}t|| krt |dd }|d }tdt|dd d }|dd|  }t| ||||S )am  Derializes the packet.

      Deserializes the packet from wire format.

      Args:
        packet_size: The size of all packets (usually 64)
        data: List of ints or bytearray containing the data from the wire.

      Returns:
        InitPacket object for specified data

      Raises:
        InvalidPacketError: if the data isn't a valid InitPacket
      r   r   r,   r-   r    )	r.   r"   r   r#   r/   unpackbytesr   
InitPacket)r!   databar$   r%   r&   r'   r   r   r	   FromWireFormatk   s   z)UsbHidTransport.InitPacket.FromWireFormatN__name__
__module____qualname____doc__r)   r6   staticmethodr<   r   r   r   r	   r9   E   s    	r9   c                   @   r   )	zUsbHidTransport.ContPacketa  Represents a continutation U2FHID packet.

    Represents a continutation U2FHID packet.  These packets follow
    the intial packet and contains the remaining data in a particular
    message.

    Attributes:
      packet_size: The size of the hid report (packet) used.  Usually 64.
      cid: The channel id for the connection to the device.
      seq: The sequence number for this continuation packet.  The first
          continuation packet is 0 and it increases from there.
      payload:  The payload to put into this continuation packet.  This
          must be less than packet_size - 5 (the overhead of the
          continuation packet is 5).
    c                 C   sF   || _ || _|| _|| _t|| j d krt |dkr!t d S )Nr-      )r!   r$   seqr'   r"   r   r#   )r(   r!   r$   rD   r'   r   r   r	   r)      s   z#UsbHidTransport.ContPacket.__init__c                 C   sH   t | j}| j|dd< | j|d< | j|ddt| j < ttt|S )r*   r   r   r-   )	r.   r!   r$   rD   r'   r"   r1   r2   r3   r4   r   r   r	   r6      s
   

z'UsbHidTransport.ContPacket.ToWireFormatc                 C   sL   t |}t|| krt |dd }|d }|dd }t| |||S )am  Derializes the packet.

      Deserializes the packet from wire format.

      Args:
        packet_size: The size of all packets (usually 64)
        data: List of ints or bytearray containing the data from the wire.

      Returns:
        InitPacket object for specified data

      Raises:
        InvalidPacketError: if the data isn't a valid ContPacket
      r   r   r-   N)r.   r"   r   r#   r   
ContPacket)r!   r:   r;   r$   rD   r'   r   r   r	   r<      s   z)UsbHidTransport.ContPacket.FromWireFormatNr=   r   r   r   r	   rE      s    
rE         @c                 C   s^   || _ | }| }||krtd|dkrtd|| _|| _td| _	| 
  d S )Nz6unsupported device with different in/out packet sizes.r   zunable to determine packet sizezpyu2f.hidtransport)
hid_deviceGetInReportDataLengthGetOutReportDataLengthr   HardwareErrorr!   read_timeout_secslogging	getLoggerloggerInternalInit)r(   rG   rK   in_sizeout_sizer   r   r	   r)      s   
zUsbHidTransport.__init__c                 C   s   |  tj|}|S N)InternalExchanger   
U2FHID_MSG)r(   msgrr   r   r	   SendMsgBytes   s   zUsbHidTransport.SendMsgBytesc                 C   s   |  tjt|gS rR   )rS   r   U2FHID_PROMPTr.   )r(   lengthr   r   r	   	SendBlink   s   zUsbHidTransport.SendBlinkc                 C   s   |  tjtg S rR   )rS   r   U2FHID_WINKr.   )r(   r   r   r	   SendWink   s   zUsbHidTransport.SendWinkc                 C   s   |  tj|S rR   )rS   r   U2FHID_PING)r(   r:   r   r   r	   SendPing   s   zUsbHidTransport.SendPingc                 C   st   t j| _ttd}| t j|}t|dk rt	
d|dd |kr*t	
dt|dd | _|d | _dS )z.Initializes the device and obtains channel id.      zunexpected init reply lenr   znonce mismatch   N)r   U2FHID_BROADCAST_CIDr$   r.   osurandomrS   U2FHID_INITr"   r   HidErroru2fhid_version)r(   noncerV   r   r   r	   rO      s   

zUsbHidTransport.InternalInitc                 C   s   | j dtt|  t }||dd< tdD ]5}| || |  \}}|tj	krB|tj
kr7td qtdt|d  ||krKtd|  S td)	z-Sends and receives a message from the device.z	payload: N   g      ?zDevice error: %dr   zCommand mismatch!zDevice Busy.  Please retry)rN   debugstrr1   r.   rangeInternalSendInternalRecvr   U2FHID_ERRORERR_CHANNEL_BUSYtimesleepr   rf   r3   )r(   r%   
payload_inr'   _ret_cmdret_payloadr   r   r	   rS      s   




z UsbHidTransport.InternalExchangec           
      C   s   t |}| jd }|d| }t| j| j|t ||}|d|= |t |8 }| | d}|dkra| jd }|d| }|d|= |t |8 }t| j| j||}	| |	 |d7 }|dks2dS dS )z8Sends a message to the device, including fragmenting it.r    r   r-   r   N)r"   r!   r   r9   r$   InternalSendPacketrE   )
r(   r%   r'   length_to_sendmax_payloadfirst_framefirst_packetrD   
next_framenext_packetr   r   r	   rm     s*   





zUsbHidTransport.InternalSendc                 C   s,   |  }| jdt|  | j| d S )Nzsending packet: )r6   rN   rj   rk   rG   Write)r(   packetwirer   r   r	   rw     s   z"UsbHidTransport.InternalSendPacketc                 C   s"   | j  }| jdt|  |S )Nzrecv: )rG   ReadrN   rj   rk   )r(   framer   r   r	   InternalReadFrame   s   
z!UsbHidTransport.InternalReadFramec                 C   s   |   }tj| j|}|j}|jt|j }d}|dkrO|   }tj| j|}| j	|j	kr0q||j
kr:td|t|j8 }||j |d7 }|dks|d|j }|j|fS )z?Receives a message from the device, including defragmenting it.r   zPackets received out of orderr   )r   r   r9   r<   r!   r'   r&   r"   rE   r$   rD   r   rJ   extendr%   )r(   
first_readr{   r:   to_readrD   	next_readr}   r   r   r	   rn   )  s,   




zUsbHidTransport.InternalRecvN)rF   )r>   r?   r@   rA   r]   rT   r[   rX   re   U2FHID_LOCKro   U2FHID_SYNCr.   rb   rp   objectr9   rE   r)   rW   rZ   r\   r^   rO   rS   rm   rw   r   rn   r   r   r   r	   r   .   s2    	
?
?	r   )rA   rL   rc   r/   rq   pyu2fr   r   r
   r   r   r   r   r   r   r	   <module>   s   