o
    _d>                     @   s  d Z ddlmZ ddlmZ ddl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 edZdZdZd	Zd
ZdZdZdZdZdZdZG dd dejZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZ e!eZ"e!eZ#e!eZ$e!eZ%ej&Z'e!e Z(ej)Z*ej+Z,ej-Z.ej/Z0ej/Z1ej/Z2ej/Z3ej4Z5e2Z6e2Z7e!eZ8e!eZ9e:dej;e0ej<e1ej=e!ej>e,Z?dZ@d ZAdZBd!ZCdZDd"ZEdZFd#ZGdZHd$ZIejJKejLMd%ZNejJKejLMd&ZOejPQd're#ReOd(ZSdeOjT_Ue"e!ej<geOjT_Ve#eOjW_Uej<ej4ej=geOjW_VejXeOjY_Ue#ej4e,ej=geOjY_Ve,eOjZ_Ue#geOjZ_Ve*eOj[_Ue$geOj[_Ve*eOj\_UejXeOj]_UdeOj^_Ue$geOj^_Ve%eOj__Ug eOj__`e'eOja_Ue#e.ejbgeOja_Ve2geNjc_Ve8eNjd_Ue"eNje_Ue8geNje_VdeNjf_Ue8e$geNjf_Ve$eNjg_Ue9e#geNjg_VdeNjh_Ue9e!ej>e,e?ej;geNjh_Ve7eNji_Ue3e5geNji_Ve9eNjj_Ue(e6geNjj_VdeNjk_Ue9e%e#geNjk_VdeNjl_Ue9e%e#geNjl_Ve0eNjm_Ue9e1e,e!ej>e,geNjm_Vnend) d*d+ Zod,d- Zpd.d/ Zqd0d1 Zrd2d3 Zse?esZtd4d5 ZuG d6d7 d7ejvZwdS )8zDImplements HID device interface on MacOS using IOKit and HIDManager.    )queue)rangeN)errors)basezpyu2f.macosi   ZVendorIdZ	ProductIDZProductZPrimaryUsageZPrimaryUsagePageZMaxInputReportSizeZMaxOutputReportSizeZReportIDc                   @      e Zd ZdS )_CFTypeN__name__
__module____qualname__ r   r   /lib/python3.10/site-packages/pyu2f/hid/macos.pyr   ,       r   c                   @   r   )	_CFStringNr   r   r   r   r   r   0   r   r   c                   @   r   )_CFSetNr   r   r   r   r   r   4   r   r   c                   @   r   )_IOHIDManagerNr   r   r   r   r   r   8   r   r   c                   @   r   )_IOHIDDeviceNr   r   r   r   r   r   <   r   r   c                   @   r   )
_CFRunLoopNr   r   r   r   r   r   @   r   r   c                   @   r   )_CFAllocatorNr   r   r   r   r   r   D   r   r      i  s	   IOService         ZIOKitZCoreFoundationdarwinZkCFRunLoopDefaultModezNot running on MacOSc                 C   s   t d|  dS )zBuilds a CFString from a python string.

  Args:
    s: source string

  Returns:
    CFStringRef representation of the source string

  Resulting CFString must be CFReleased when no longer needed.
  Nr   )cfCFStringCreateWithCStringencode)sr   r   r   CFStr   s   r   c                 C   sx   t |}t| |}t| |sdS t|t kr'td	t|t
 }t|tt
|}|s9dS |jS )z'Reads int property from the HID device.NzExpected number type, got {})r   iokitIOHIDDeviceGetPropertyr   	CFReleaseCFGetTypeIDCFNumberGetTypeIDr   
OsHidErrorformatctypesc_int32CFNumberGetValueK_CF_NUMBER_SINT32_TYPEZbyrefvalueZdev_refkeyZcf_keyZtype_refoutretr   r   r   GetDeviceIntProperty   s    
r/   c                 C   s   t |}t| |}t| |sdS t|t kr'td	t|t
|t}t
t}t||tt}|s>dS |jdS )z*Reads string property from the HID device.NzExpected string type, got {}utf8)r   r   r    r   r!   r"   ZCFStringGetTypeIDr   r$   r%   r&   castCF_STRING_REFcreate_string_buffer"DEVICE_STRING_PROPERTY_BUFFER_SIZECFStringGetCStringK_CF_STRING_ENCODING_UTF8r*   decoder+   r   r   r   GetDeviceStringProperty   s"   


r8   c                 C   s(   t | }tt}t |t| |jS )zObtains the unique path for the device.

  Args:
    device_handle: reference to the device

  Returns:
    A unique path for the device, obtained from the IO Registry

  )r   ZIOHIDDeviceGetServicer&   r3   DEVICE_PATH_BUFFER_SIZEZIORegistryEntryGetPathK_IO_SERVICE_PLANEr*   )device_handleZio_service_objZ
str_bufferr   r   r   GetDevicePath   s   

r<   c                    s,   ~~~~ fddt |D }| | dS )z+Handles incoming IN report from HID device.c                    s   g | ]} | qS r   r   ).0ireportr   r   
<listcomp>  s    z#HidReadCallback.<locals>.<listcomp>N)r   Zput)
read_queueresultZsenderZreport_type	report_idr@   Zreport_lengthZincoming_bytesr   r?   r   HidReadCallback   s   rE   c                 C   s   t  | _| jstd dS t| j| jt t	}|t	ks"|t
kr1t tdd}|t	ks"|t
ks"|tkr;td| t| j| jt dS )zBinds a device to the thread's run loop, then starts the run loop.

  Args:
    hid_device: The MacOsHidDevice object

  The HID manager requires a run loop to handle Report reads. This thread
  function serves that purpose.
  zFailed to get current run loopNi  Fz!Unexpected run loop exit code: %d)r   CFRunLoopGetCurrentrun_loop_refloggererrorr   IOHIDDeviceScheduleWithRunLoopr;   K_CF_RUNLOOP_DEFAULT_MODEK_CF_RUN_LOOP_RUN_TIMED_OUT K_CF_RUN_LOOP_RUN_HANDLED_SOURCECFRunLoopRunInModeK_CF_RUN_LOOP_RUN_STOPPED IOHIDDeviceUnscheduleFromRunLoop)Z
hid_deviceZrun_loop_run_resultr   r   r   DeviceReadThread  s0   

rQ   c                   @   sL   e Zd ZdZedd Zdd Zdd Zdd	 Zd
d Z	dd Z
dd ZdS )MacOsHidDevicezaImplementation of HID device for MacOS.

  Uses IOKit HID Manager to interact with the device.
  c                  C   s   t dd} | stdt | d t | }|stdt |}t|  }t || g }|D ]6}t	
 }t|t|_t|t|_t|t|_t|t|_t|t|_t|t|_t||_||  q3t| t|  |S )See base class.Nz&Unable to obtain HID manager referencez)Failed to obtain devices from HID manager)r   IOHIDManagerCreater   r$   IOHIDManagerSetDeviceMatchingIOHIDManagerCopyDevicesZCFSetGetCountIO_HID_DEVICE_REFCFSetGetValuesr   ZDeviceDescriptorr/   HID_DEVICE_PROPERTY_VENDOR_IDZ	vendor_idHID_DEVICE_PROPERTY_PRODUCT_IDZ
product_idr8   HID_DEVICE_PROPERTY_PRODUCTZproduct_string!HID_DEVICE_PROPERTY_PRIMARY_USAGEusage&HID_DEVICE_PROPERTY_PRIMARY_USAGE_PAGEZ
usage_pageHID_DEVICE_PROPERTY_REPORT_IDrD   r<   pathappendZToPublicDictr   r!   )Zhid_mgrZdevice_set_refZnumZdevicesZdescriptorsdevdr   r   r   	Enumerate9  s8   







zMacOsHidDevice.Enumeratec              	   C   s  t t|}|stdt t|| _| jstdt | || _	t 
| jd}|tkr7td|t | _d | _tjt| fd| _d| j_| j  t| jt| _| js`tdt| jt| _| jsotdtj| j  | _t | j| j| jt t!| j d S )	Nz7Device path does not match any HID device on the systemz2Failed to obtain device handle from registry entryr   z+Failed to open device for communication: {})targetargsTz#Unable to obtain max in report sizez$Unable to obtain max out report size)"r   IORegistryEntryFromPathK_IO_MASTER_PORT_DEFAULTr   r$   IOHIDDeviceCreateK_CF_ALLOCATOR_DEFAULTr;   IOObjectReleaseZdevice_pathZIOHIDDeviceOpenK_IO_RETURN_SUCCESSr%   r   ZQueuerB   rG   	threadingZThreadrQ   read_threadZdaemonstartr/   )HID_DEVICE_PROPERTY_MAX_INPUT_REPORT_SIZEinternal_max_in_report_len*HID_DEVICE_PROPERTY_MAX_OUTPUT_REPORT_SIZEinternal_max_out_report_lenr&   c_uint8in_report_buffer&IOHIDDeviceRegisterInputReportCallbackREGISTERED_READ_CALLBACK	py_object)selfr`   Zdevice_entryrC   r   r   r   __init__`  sT   







zMacOsHidDevice.__init__c                 C      | j S rS   )rq   ry   r   r   r   GetInReportDataLength     z$MacOsHidDevice.GetInReportDataLengthc                 C   r{   r|   )rs   r}   r   r   r   GetOutReportDataLength  r   z%MacOsHidDevice.GetOutReportDataLengthc                 C   sR   d}t j| j  }|dd |dd< t| jt||| j}|tkr't	ddS )rS   r   Nz Failed to write report to device)
r&   rt   rs   r   IOHIDDeviceSetReportr;   K_IO_HID_REPORT_TYPE_OUTPUTrl   r   r$   )ry   ZpacketrD   Zout_report_bufferrC   r   r   r   Write  s   
zMacOsHidDevice.Writec                 C   s@   d}|du rz	| j jdd}W n
 tjy   Y qw |du s|S )rS   N<   )Ztimeout)rB   getr   ZEmpty)ry   rC   r   r   r   Read  s   zMacOsHidDevice.Readc                 C   sT   t | drt| j| j| jd d  t | drt| j t | dr(| j	
  d S d S )Nru   rG   rn   )hasattrr   rv   r;   ru   rq   r   ZCFRunLoopStoprG   rn   joinr}   r   r   r   __del__  s   


zMacOsHidDevice.__del__N)r	   r
   r   __doc__staticmethodrd   rz   r~   r   r   r   r   r   r   r   r   rR   3  s    
&6rR   )xr   Z	six.movesr   r   r&   Zctypes.utilZloggingsysrm   Zpyu2fr   Z	pyu2f.hidr   Z	getLoggerrH   r9   r4   rY   rZ   r[   r\   r^   rp   rr   r_   Z	Structurer   r   r   r   r   r   r   ZPOINTERZ
CF_SET_REFr2   ZCF_TYPE_REFZCF_RUN_LOOP_REFr'   ZCF_RUN_LOOP_RUN_RESULTZCF_ALLOCATOR_REFZc_ulongZ
CF_TYPE_IDZc_longZCF_INDEXZc_doubleZCF_TIME_INTERVALZc_uintZ	IO_RETURNZIO_HID_REPORT_TYPEZIO_OBJECT_TZMACH_PORT_TZc_char_pZIO_STRING_TZIO_SERVICE_TZIO_REGISTRY_ENTRY_TZIO_HID_MANAGER_REFrW   Z	CFUNCTYPErx   Zc_void_pZc_uint32rt   ZIO_HID_REPORT_CALLBACKr)   r6   rj   r:   rh   r   rl   rO   rL   rM   ZcdllZLoadLibraryutilZfind_libraryr   r   platform
startswithZin_dllrK   rX   Zrestypeargtypesr   Zc_intr5   ZCFStringGetLengthr"   r#   r(   r!   rF   ZargTypesrN   Zc_boolrk   rT   rV   rU   r    rv   rg   ri   rJ   rP   r   warnr   r/   r8   r<   rE   rw   rQ   Z	HidDevicerR   r   r   r   r   <module>   s
  



















'