U
    ۦ\                  	   @   s   d dl mZ d dl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mZ e TZz"d d	lmZ d d
lmZ ej W n* ek
r   d dlZd dlZej Y nX W 5 Q R X eZG dd deZG dd dZdS )    )unicode_literalsN   )	text_type)
properties)KeyringBackend)SimpleCredential)PasswordDeleteErrorExceptionRaisedContext)
pywintypes)	win32credc                   @   sf   e Zd ZdZejed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d ZdS )WinVaultKeyringa  
    WinVaultKeyring stores encrypted passwords using the Windows Credential
    Manager.

    Requires pywin32

    This backend does some gymnastics to simulate multi-user support,
    which WinVault doesn't support natively. See
    https://bitbucket.org/kang/python-keyring-lib/issue/47/winvaultkeyring-only-ever-returns-last#comment-731977
    for details on the implementation, but here's the gist:

    Passwords are stored under the service name unless there is a collision
    (another password with the same service name but different user name),
    in which case the previous password is moved into a compound name:
    {username}@{service}
    c                 C   s   t rtddS )zA
        If available, the preferred backend on Windows.
        zRequires Windows and pywin32   )missing_depsRuntimeError)cls r   :/usr/lib/python3/dist-packages/keyring/backends/Windows.pypriority0   s    zWinVaultKeyring.priorityc                 C   s
   dt   S )Nz%(username)s@%(service)s)vars)usernameservicer   r   r   _compound_name:   s    zWinVaultKeyring._compound_namec                 C   sF   |  |}|r|d |kr,|  | ||}|s4d S |d }|dS NUserNameCredentialBlobzutf-16)_get_passwordr   decode)selfr   r   resZblobr   r   r   get_password>   s    
zWinVaultKeyring.get_passwordc              
   C   sh   zt jt j|d}W nN tjk
rb } z.t|}|jdkrP|jdkrPW Y 
d S  W 5 d }~X Y nX |S )NType
TargetName  CredRead)	r   r$   CRED_TYPE_GENERICr
   errorOldPywinErrorwrapwinerrorfuncname)r   targetr   er   r   r   r   I   s    


zWinVaultKeyring._get_passwordc                 C   sP   |  |}|r:|d }| ||}| |||d d | ||t| d S r   )r   r   _set_passwordr   r   )r   r   r   passwordexisting_pwZexisting_usernamer+   r   r   r   set_passwordV   s    
zWinVaultKeyring.set_passwordc                 C   s(   t tj|||dtjd}t|d d S )NzStored using python-keyring)r!   r"   r   r   CommentZPersistr   )dictr   r%   ZCRED_PERSIST_ENTERPRISEZ	CredWrite)r   r+   r   r.   Z
credentialr   r   r   r-   `   s    zWinVaultKeyring._set_passwordc                 C   sV   |  ||}d}||fD ],}| |}|r|d |krd}| | q|sRt|d S )NFr   T)r   r   _delete_passwordr   )r   r   r   ZcompoundZdeletedr+   r/   r   r   r   delete_passwordi   s    
zWinVaultKeyring.delete_passwordc              
   C   sh   zt jt j|d W nN tjk
rb } z.t|}|jdkrP|jdkrPW Y 
d S  W 5 d }~X Y nX d S )Nr    r#   
CredDelete)	r   r5   r%   r
   r&   r'   r(   r)   r*   )r   r+   r,   r   r   r   r3   t   s    


z WinVaultKeyring._delete_passwordc                 C   sH   d }|r|  | ||}|s0|  |}|s0d S t|d |d dS r   )r   r   r   r   )r   r   r   r   r   r   r   get_credential   s    
zWinVaultKeyring.get_credentialN)__name__
__module____qualname____doc__r   ZClassPropertyclassmethodr   staticmethodr   r   r   r0   r-   r4   r3   r6   r   r   r   r   r      s   

	r   c                   @   s<   e Zd ZdZdd Zedd Zedd Zedd	 Z	d
S )r'   z
    A compatibility wrapper for old PyWin32 errors, such as reported in
    https://bitbucket.org/kang/python-keyring-lib/issue/140/
    c                 C   s
   || _ d S )Norig)r   r>   r   r   r   __init__   s    zOldPywinError.__init__c                 C   s
   | j d S )N   r=   r   r   r   r   r*      s    zOldPywinError.funcnamec                 C   s
   | j d S )Nr   r=   rA   r   r   r   r)      s    zOldPywinError.winerrorc                 C   s0   t t|}tt|ddg }|r,| |S |S )Nr*   r)   )	functoolspartialhasattrallmap)r   Zorig_errZ
attr_checkZis_oldr   r   r   r(      s    zOldPywinError.wrapN)
r7   r8   r9   r:   r?   propertyr*   r)   r;   r(   r   r   r   r   r'      s   

r'   )Z
__future__r   rB   Z
py27compatr   utilr   Zbackendr   Zcredentialsr   errorsr   r	   r   Zwin32ctypes.pywin32r
   r   r7   ImportErrortypeZ__metaclass__r   r'   r   r   r   r   <module>   s$   
r