U
    dB                     @   s  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Zd dlZd dl	Z	d dl
m
Z d dlmZ d dlmZ z4d dlZd dlmZmZ d dlZd dlmZ dZW n& ek
r   d	Zd dlZejZY nX d
ZdZdZdZdZ dZ!dZ"G dd dZ#G dd de$Z%dd Z&d8ddZ'dd Z(dd Z)dd Z*dd Z+d9d d!Z,d:d"d#Z-d$d% Z.d&d' Z/G d(d) d)e0Z1G d*d+ d+ee1Z2d,d- Z3d.d/ Z4d;d0d1Z5G d2d3 d3e0Z6d4d5 Z7e8d6krd dl9Z9e.e9j:d7 Z;e<e4e; dS )<    )print_functionN)gettext)Thread)ShortcutException)	HTTPErrorURLError)HTTPExceptionFTzNhttps://keyserver.ubuntu.com/pks/lookup?op=get&options=mr&exact=on&search=0x%sz.https://launchpad.net/api/devel/%s/+archive/%sz https://launchpad.net/api/1.0/%sz%https://launchpad.net/api/1.0/%s/ppasz#https://launchpad.net/api/1.0/%s/%sz"/etc/ssl/certs/ca-certificates.crtc                   @   s   e Zd Zdd Zdd ZdS )CurlCallbackc                 C   s
   d| _ d S )N contentsself r   8/usr/lib/python3/dist-packages/softwareproperties/ppa.py__init__?   s    zCurlCallback.__init__c                 C   s   | j | | _ d S Nr   )r   Zbufr   r   r   body_callbackB   s    zCurlCallback.body_callbackN)__name__
__module____qualname__r   r   r   r   r   r   r	   >   s   r	   c                   @   s   e Zd ZdddZdd ZdS )PPAExceptionNc                 C   s   || _ || _d S r   )valueoriginal_error)r   r   r   r   r   r   r   H   s    zPPAException.__init__c                 C   s
   t | jS r   )reprr   r   r   r   r   __str__L   s    zPPAException.__str__)N)r   r   r   r   r   r   r   r   r   r   F   s   
r   c                 C   s   t dd| S )Nz[^a-zA-Z0-9_-]_)resub)sr   r   r   encodeP   s    r    c                 C   s0   t rtnt}|| ||d}|r(t|S |S dS )a-  Return the content from url.
    accept_json indicates that:
        a.) Send header Accept: 'application/json'
        b.) Instead of raw content, return json.loads(content)
    retry_delays is None or an iterator (including list or tuple)
        If it is None, no retries will be done.
        If it is an iterator, each value is number of seconds to delay before
        retrying.  For example, retry_delays=(3,5) means to try up to 3
        times, with a 3s delay after first failure and 5s delay after second.
        Retries will not be done on 404.)lp_urlaccept_jsonretry_delaysN)NEED_PYCURL_get_https_content_pycurl_get_https_content_py3jsonloads)Zurlr"   r#   funcdatar   r   r   get_info_from_httpsT   s
    
r+   c                 C   s
   t | dS NT)r+   )r!   r   r   r   get_info_from_lpg   s    r-   c                 C   s(   | d dkrd|  } t | |f }t|S )Nr   ~)LAUNCHPAD_PPA_APIr-   )Z
owner_nameppar!   r   r   r   get_ppa_info_from_lpj   s    r1   c                 C   s6   t | |f }zt| W dS  tk
r0   Y dS X d S )NTF)!LAUNCHPAD_DISTRIBUTION_SERIES_APIr-   r   )distributionZseriesr!   r   r   r   series_valid_for_distrop   s    r4   c                 C   s   t |  }tjt|d S )NZcurrent_series_link)LAUNCHPAD_DISTRIBUTION_APIospathbasenamer-   )r3   r!   r   r   r   get_current_series_from_lpx   s    r9   c           
   
   C   s   |d krg }d}d }t |}|r(ddini }|d7 }z6tjjt| |d}tjj|td}| ddW S  t	t
fk
r }	 z6td	| ||	jf |	}t|	tr|	jd
krW Y qW 5 d }	~	X Y nX ztt| W q, tk
r   Y qY q,X q,|d S )Nr   ZAcceptzapplication/json   )headers)Zcafileutf-8strictError reading %s (%d tries): %si  )iterurllibrequestZRequeststrZurlopenLAUNCHPAD_PPA_CERTreaddecoder   r   r   reason
isinstancer   codetimesleepnextStopIteration)
r!   r"   r#   trynumerrsleep_waitsr;   rA   Zlp_pageer   r   r   r&   }   s2    r&   c              
   C   sh  |d krg }d}t |}d }d }|d7 }zt }t }|tjd |tjd |tjd |tj|j	 t
r|tjt
 |tjt|  |r|tjdg |  ||j}	|  |	dkrd|	 }W n2 tjk
r
 }
 zt|
}|
}W 5 d }
~
X Y nX |d kr|jS ztt| W q tk
rJ   Y qNY qX qtd| ||f |dd S )	Nr   r:      zAccept: application/json   zresponse code %ir>   )r   )r?   r	   pycurlZCurlZsetoptZSSL_VERIFYPEERZSSL_VERIFYHOSTZFOLLOWLOCATIONZWRITEFUNCTIONr   rC   ZCAINFOZURLrB   Z
HTTPHEADERZperformZgetinfoZRESPONSE_CODEcloseerrorr   rI   rJ   rK   rL   r   )r!   r"   r#   rM   rO   err_msgrN   callbackZcurlZresponserP   r   r   r   r%      sJ    
r%   c                 C   s   d| kr|  dd }n| }|dr0|d}| dd }|d dkrV|dd  }| ddd  }g }t|dk rddg}n(t|dkr|dd || n|}d|d|f }|S )	N:r:   /r   r.   Zubuntur0   z~%s/%s)split
startswithlstripleninsertextendjoin)shortcutZppa_shortcutuserZppa_path_objsppa_pathr0   r   r   r   mangle_ppa_shortcut   s$    


rd   c                 C   s   t | dkS )z>Verify that the keyid is a v4 fingerprint with at least 160bitg      4@)r]   )signing_key_fingerprintr   r   r   verify_keyid_is_v4   s    rf   c                   @   sT   e Zd Zd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dZdS )AddPPASigningKeyz; thread class for adding the signing key in the background Nc                 C   s   || _ t | _d S r   )rc   tempfileZmkdtemp_homedirr   rc   	keyserverr   r   r   r      s    zAddPPASigningKey.__init__c                 C   s   t | j d S r   )shutilZrmtreeri   r   r   r   r   __del__   s    zAddPPASigningKey.__del__c                 C   s&   d| j |f }tj| tjtjdS )NzRgpg -q --homedir %s --no-default-keyring --no-options --import --import-options %s)stdinstdout)ri   
subprocessPopenrZ   PIPE)r   argscmdr   r   r   gpg_cmd   s    zAddPPASigningKey.gpg_cmdc                 C   sN   |d }zt |s$td|  W dS W n tk
rD   td Y dS X t|S )Nre   z-Error: signing key fingerprint '%s' too shortFz-Error: signing key fingerprint does not exist)rf   print	TypeErrorget_ppa_signing_key_data)r   ppa_infore   r   r   r   	_recv_key   s    
zAddPPASigningKey._recv_keyc                 C   s.   |  d}|| \}}|jdkr*dS |S )Nzimport-minimal,import-exportr   F)ru   communicater    
returncode)r   keypminimal_keyr   r   r   r   _minimize_key  s
    

zAddPPASigningKey._minimize_keyc                 C   s\   g }|  d}||\}}|jdkrX|d D ]"}|dr4||dd  q4|S )Nz-show-only --fingerprint --batch --with-colonsr   r<   zfpr:rX   	   )ru   r{   r|   rE   
splitlinesr[   appendrZ   )r   r}   Zfingerprintsr~   outputr   liner   r   r   _get_fingerprints
  s    


z"AddPPASigningKey._get_fingerprintsc                 C   sR   |  |}t|dkr*tdt|  dS |d }||krNtd||f  dS dS )Nr:   z(Got '%s' fingerprints, expected only oneFr   z6Fingerprints do not match, not importing: '%s' != '%s'T)r   r]   rv   )r   r}   Zexpected_fingerprintZgot_fingerprintsZgot_fingerprintr   r   r   _verify_fingerprint  s    
 z$AddPPASigningKey._verify_fingerprintc           
   
   C   s  |dkr| j }ztt|}W n2 tk
rP } zt|j W Y dS d}~X Y nX z|d }W n" tk
r   td|  Y dS X | |}|sdS tj	
d}tj|t|d dd }| |}|sdS | ||sdS td| d	}	|	| W 5 Q R X d
S )zQuery and add the corresponding PPA signing key.

        The signing key fingerprint is obtained from the Launchpad PPA page,
        via a secure channel, so it can be trusted.
        NFre   z/Error: can't find signing_key_fingerprint at %szDir::Etc::trustedparts	referencer:   z%s.gpgwbT)rc   get_ppa_inford   r   rv   r   
IndexErrorrz   apt_pkgconfigfind_dirr6   r7   r`   r    r   r   openwrite)
r   rc   ry   rP   re   Zarmored_keyZtrustedgpgdZapt_keyringr   fr   r   r   add_ppa_signing_key!  s2    


z$AddPPASigningKey.add_ppa_signing_key)N)N)r   r   r   __doc__r   rm   ru   rz   r   r   r   r   r   r   r   r   rg      s   

rg   c                   @   s   e Zd ZdddZdd ZdS )AddPPASigningKeyThreadNc                 C   s   t |  tj| ||d d S )N)rc   rk   )r   r   rg   rj   r   r   r   r   P  s    
zAddPPASigningKeyThread.__init__c                 C   s   |  | j d S r   )r   rc   r   r   r   r   runT  s    zAddPPASigningKeyThread.run)N)r   r   r   r   r   r   r   r   r   r   J  s   
r   c                 C   s2  zg }zzt t|  }W n( tk
rB   tdj| d Y W W S X t t|  }|d r`tdntd}|d dkr|td|| |d	  |td
 |d D ]$}|td|d |d d  qn|td|| d  d|W W S  tk
r
   Y W dS X W n t	k
r,   td Y S X d S )Nz,ERROR: '{user}' user or team does not exist.)rb   Zis_teamZteamrb   Z
total_sizer   z:The %(entity)s named '%(user)s' has no PPA named '%(ppa)s')entityrb   r0   z0Please choose from the following available PPAs:entriesz * '%(name)s':  %(displayname)snamedisplayname)r   r   z5The %(entity)s named '%(user)s' does not have any PPA)r   rb   
r
   z4Please check that the PPA name or format is correct.)
r-   LAUNCHPAD_USER_APIr   r   formatLAUNCHPAD_USER_PPAS_APIr   r`   KeyErrorImportError)rb   Zppa_namemsgZlp_userZlp_ppasZentity_namer0   r   r   r   _get_suggested_ppa_messageX  s<    



 
r   c              	   C   s   |  dd }d|  ddd  }z<t||}|d  dd |d< |d  dd |d< |W S  ttfk
r   g }|td	||f  td
|d
 t|| Y n0 t	t
fk
r   ttdt||f  Y nX d S )NrY   r   r:   Zdistribution_linkr3   Z
owner_linkownerzCannot add PPA: 'ppa:%s/%s'.r   zUCannot access PPA (%s) to get PPA information, please check your internet connection.)rZ   r`   r1   r   	Exceptionr   r   r   r   
ValueErrorr   r/   )ra   rb   r0   Zretr   r   r   r   r   x  s,    

 

r   c                 C   s6   t | tr| d }ntt| d }t|d dddS )a   Return signing key data in armored ascii format for the provided ppa.
    
    If 'info' is a dictionary, it is assumed to be the result
    of 'get_ppa_info(ppa)'.  If it is a string, it is assumed to
    be a ppa_path.

    Return value is a text string.Z	self_linkz?ws.op=getSigningKeyDataT)r:   rQ      )r"   r#   )rG   dictr   rd   r+   )infolinkr   r   r   rx     s    

 rx   c                       s@   e Zd Z fddZdd ZdddZdd	 Zdd
dZ  ZS )PPAShortcutHandlerc                    sn   t t|   zt|| _W n    ttdj|dY nX t| j}d|krd|d rdttd|| _	d S )Nz-ERROR: '{shortcut}' is not a valid ppa formatra   Zprivatez.Adding private PPAs is not supported currently)
superr   r   rd   ra   r   r   r   r   _info)r   ra   r   	__class__r   r   r     s    

zPPAShortcutHandler.__init__c                 C   s   | j S r   )r   r   r   r   r   r     s    zPPAShortcutHandler.infoNc              	   C   s   |d k	r4|| j d kr4t| j d |s4t| j d }d| j d dd  | j d | j d |f }tjd}tj|dt	| j d dd  t	| j d t	| j d |f }||fS )Nr3   z-deb http://ppa.launchpad.net/%s/%s/%s %s mainr   r:   r   zDir::Etc::sourcepartsz%s-%s-%s-%s.list)
r   r4   r9   r   r   r   r6   r7   r`   r    )r   ZcodenameZdistroZdeblineZsourceslistdfilenamer   r   r   expand  s(    
  
  zPPAShortcutHandler.expandc                 C   s   dS r,   r   r   r   r   r   should_confirm  s    z!PPAShortcutHandler.should_confirmc                 C   s   t | jd |d}| S )Nr   )rk   )rg   r   r   )r   rk   Zapskr   r   r   add_key  s    zPPAShortcutHandler.add_key)N)N)	r   r   r   r   r   r   r   r   __classcell__r   r   r   r   r     s
   
r   c                 C   s   |  dsd S t| S )Nzppa:)r[   r   r   r   r   r   shortcut_handler  s    
r   __main__r:   )N)N)N)N)=Z
__future__r   r   r'   r6   r   rl   rp   rh   rI   r   r   Z	threadingr   Zsoftwareproperties.shortcutsr   Zurllib.requestr@   Zurllib.errorr   r   Zurllib.parseZhttp.clientr   r$   r   rS   rU   ZSKS_KEYSERVERr/   r   r   r5   r2   rC   r	   r   r   r    r+   r-   r1   r4   r9   r&   r%   rd   rf   objectrg   r   r   r   rx   r   r   r   sysargvr0   rv   r   r   r   r   <module>   sf   



/d 
0
