B
    \              	   @   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y"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 d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   sb   yt jt j|d}W nH tjk
r\ } z(t|}|jdkrJ|jdkrJd S  W d d }~X Y nX |S )N)Type
TargetNamei  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 )Nr   r   zutf-16)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   sZ   |  ||}d}x8||fD ],}| |}|r|d |krd}| | qW |sVt|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   sb   yt jt j|d W nH tjk
r\ } z(t|}|jdkrJ|jdkrJd S  W d d }~X Y nX d S )N)r   r    i  
CredDelete)	r   r2   r"   r
   r#   r$   r%   r&   r'   )r   r(   r)   r   r   r   r0   t   s    
z WinVaultKeyring._delete_passwordc             C   sH   d }|r|  | ||}|s0|  |}|s0d S t|d |d dS )Nr   r   zutf-16)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   r-   r*   r1   r0   r3   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:   )r   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)
r4   r5   r6   r7   r;   propertyr'   r&   r8   r%   r   r   r   r   r$      s
   r$   )Z
__future__r   r=   Z
py27compatr   utilr   Zbackendr   Zcredentialsr   errorsr   r	   r   Zwin32ctypes.pywin32r
   r   r4   ImportErrortypeZ__metaclass__r   r$   r   r   r   r   <module>   s$   
r