
    .Ph6                     f   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m	Z	m
Z
mZ ddlmZmZmZ ddlmZmZ ddlmZmZ  ej        e          Z ej        d          Z G d	 d
e          Z G d de          Zdede	e         de
e         fdZdedefdZdedefdZ dede	e         defdZ!dS )a8  
Conda lock supports two kinds of credentials used for channels:

## Token based

These are used by anaconda.org, Anaconda Enterprise, and Quetz.
To pass one of these channels, specify them in your source with an environment variable.
Make sure this environment variable is not expanded.

Example:
--channel 'http://host.com/t/$MY_REPO_TOKEN/channel'
# TODO: Detect environment variables that match a channel specified incorrectly.

## Simple Auth

For other channels (such as those self-managed), you may be using standard
username/password auth:

Example:
--channel 'http://$USER:$PASSWORD@host.com/channel'

## What gets stored

Since credential parts are both volatile and secret, conda-lock will not store
the raw version of a URL. If it encounters a channel URL that contains credentials,
it will search the available environment variables for a match. When found, that portion
of the URL will be replaced with an environment variable.

Since conda also performs env var substitution, the rendered output can contain env vars
which will be handled correctly by conda/mamba.
    N)
expandvars)AnyListOptionalTuple)unquoteurlparse
urlunparse)	BaseModel
ConfigDict)mask_anaconda_tokensplit_anaconda_tokenz%(.*)(/t/\$?\{?[a-zA-Z0-9-_]*\}?)(/.*)c                       e Zd ZU dZeed<   eed<   dZee         ed<   dZee         ed<   dZ	ee         ed<   dZ
ee         ed<   dZee         ed	<   dZee         ed
<   dS )	_CondaUrlzA high-level representation of a URL that may contain credentials.

    This is an intermediate representation that is used after parsing but before
    the URL is used to create a Channel object.
    raw_urlenv_var_urlNtokentoken_env_varuseruser_env_varpasswordpassword_env_var)__name__
__module____qualname____doc__str__annotations__r   r   r   r   r   r   r        Y/var/www/html/test/jupyter/venv/lib/python3.11/site-packages/conda_lock/models/channel.pyr   r   6   s           LLLE8C=#'M8C='''D(3-"&L(3-&&&"Hhsm"""&*hsm*****r    r   c                       e Zd ZU  ed          Zeed<   eedf         ed<   ededd fd            Z	defd	Z
defd
ZdefdZdefdZdeeeef                  fdZdS )ChannelT)frozenurl.used_env_varsvaluereturnc                 d    d|v r t          |          }t          |          }|S  | |d          S )a  The primary constructor for Channel.

        >>> Channel.from_string("conda-forge")
        Channel(url='conda-forge')

        Channels can be specified with a label
        >>> Channel.from_string("conda-forge/label/micromamba_prerelease")
        Channel(url='conda-forge/label/micromamba_prerelease')

        Channels can contain tokens, and these will be replaced with env vars
        >>> os.environ["MY_A_REPO_TOKEN"] = "tk-123-456"
        >>> Channel.from_string(
        ...     "https://host.com/t/tk-123-456/channel"
        ... )  # doctest: +NORMALIZE_WHITESPACE
        Channel(url='https://host.com/t/${MY_A_REPO_TOKEN}/channel',
            used_env_vars=('MY_A_REPO_TOKEN',))

        Channels can contain username/password credentials
        >>> os.environ["MY_A_USERNAME"] = "user"
        >>> os.environ["MY_A_PASSWORD"] = "pass"
        >>> Channel.from_string(
        ...     "https://user:pass@host.com/channel"
        ... )  # doctest: +NORMALIZE_WHITESPACE
        Channel(url='https://${MY_A_USERNAME}:${MY_A_PASSWORD}@host.com/channel',
            used_env_vars=('MY_A_PASSWORD', 'MY_A_USERNAME'))

        >>> del os.environ["MY_A_USERNAME"]
        >>> del os.environ["MY_A_PASSWORD"]
        >>> del os.environ["MY_A_REPO_TOKEN"]
        z://r   r%   r&   )_conda_url_from_string_channel_from_conda_url)clsr'   	conda_urlchannels       r!   from_stringzChannel.from_stringL   sB    @ E>>.u55I-i88GNsuB////r    c                 *    t          | j                  S )a<  Expand environment variables in the URL.

        Note that we only do POSIX-style expansion here in order to maintain
        consistency across platforms.

        >>> os.environ["MY_B_VAR"] = "value"
        >>> Channel.from_string(
        ...     "https://host.com/$MY_B_VAR/channel"
        ... ).env_replaced_url()
        'https://host.com/value/channel'
        >>> Channel.from_string(
        ...     "https://host.com/${MY_B_VAR}/channel"
        ... ).env_replaced_url()
        'https://host.com/value/channel'
        >>> del os.environ["MY_B_VAR"]
        )r   r%   selfs    r!   env_replaced_urlzChannel.env_replaced_urlr   s    " $(###r    c                 H    |                                  }t          |          S )a  Emulate conda's token replacement in the output URL.

        This is used to recognize URLs contained in explicit lockfiles created by
        conda. In these lockfiles, the token is censored with <TOKEN>.

        >>> Channel.from_string(
        ...     "https://host.com/t/asdfjkl/channel"
        ... ).conda_token_replaced_url()
        'https://host.com/t/<TOKEN>/channel'
        )r4   r   )r3   expanded_urls     r!   conda_token_replaced_urlz Channel.conda_token_replaced_url   s#     ,,.."<000r    c                     |                                  }t          |          \  }}|r|                    |dd          n|S )a  Emulate mamba's v1 token replacement in the output URL.

        This is used to recognize URLs contained in explicit lockfiles created by
        mamba or micromamba. In these lockfiles, the token is censored with *****.

        >>> Channel.from_string(
        ...     "https://host.com/t/asdfjkl/channel"
        ... ).mamba_v1_token_replaced_url()
        'https://host.com/t/*****/channel'
        z*****   r4   r   replacer3   r6   _r   s       r!   mamba_v1_token_replaced_urlz#Channel.mamba_v1_token_replaced_url   sH     ,,..'555:?Q|##E7A666\Qr    c                     |                                  }t          |          \  }}|r|                    |dd          n|S )a  Emulate mamba's v2 token replacement in the output URL.

        This is used to recognize URLs contained in explicit lockfiles created by
        mamba or micromamba. In these lockfiles, the token is censored with **********.

        >>> Channel.from_string(
        ...     "https://host.com/t/asdfjkl/channel"
        ... ).mamba_v2_token_replaced_url()
        'https://host.com/t/**********/channel'
        z
**********r9   r:   r<   s       r!   mamba_v2_token_replaced_urlz#Channel.mamba_v2_token_replaced_url   sH     ,,..'555?DV|##E<;;;,Vr    c                 H    d | j                                         D             S )a  Hide falsy values from repr.

        # Note how used_env_vars is not shown:
        >>> Channel.from_string("conda-forge")
        Channel(url='conda-forge')

        # It's only shown when it's non-empty:
        >>> Channel.from_string(
        ...     "https://host.com/t/$MY_REPO_TOKEN/channel"
        ... )  # doctest: +NORMALIZE_WHITESPACE
        Channel(url='https://host.com/t/${MY_REPO_TOKEN}/channel',
            used_env_vars=('MY_REPO_TOKEN',))
        c                      g | ]\  }}|||fS r   r   ).0keyr'   s      r!   
<listcomp>z)Channel.__repr_args__.<locals>.<listcomp>   s%    NNNeNeNNNr    )__dict__itemsr2   s    r!   __repr_args__zChannel.__repr_args__   s'     ONt}/B/B/D/DNNNNr    N)r   r   r   r   model_configr   r   r   classmethodr0   r4   r7   r>   r@   r   r   rH   r   r    r!   r#   r#   G   s        :T***L	HHHc?"""#0 #0	 #0 #0 #0 [#0J$# $ $ $ $&1# 1 1 1 1RS R R R RWS W W W WOtE#s(O4 O O O O O Or    r#   r'   preferred_env_var_suffixr(   c                 n   |                      d          r(|                     d                              d          S g |dD ]ofdt          j                                        D             }|                    |           x}r|c S |                    t          |                     x}r|c S pdS )zDetect if the string exactly matches any current environment variable.

    Preference is given to variables that end in the provided suffixes.
    $z{} c                 j    i | ]/\  }}|                                                               ,||0S r   )upperendswith)rC   kvsuffixs      r!   
<dictcomp>z(_detect_used_env_var.<locals>.<dictcomp>   s;    XXXtq!QWWYY=O=OPV=W=WXaXXXr    N)
startswithlstripstriposenvironrG   getr   )r'   rK   
candidatesrD   rT   s       @r!   _detect_used_env_varr]      s      -||C  &&t,,,1,1b1  XXXXrz'7'7'9'9XXX
..'''3 	JJJ..0003 	JJJ	4r    r%   c           
      V   t          |           }dt          t                   dt          t                   dt          dt          t                   dt          f
d}d}d}d}dt          t                   dt          fd	}t	          j        |          }|j        rXt          |j        d
dg          }|r?|                     |d| d|j         ||j	                  |j
                            }|j        rXt          |j        g d          }|r?|                     ||j        d| d ||j	                  |j
                            }t                              |j                  }|r"|                                d         dd         nd}	|	rit          |	g d          }|st                              d           n:t                              d| d|j                  }
|                    |
          }t%          | t'          |          |j        ||j        ||	|          S )z-Normalize URL by using environment variables.usernamer   hostportr(   c                 D    |r| d| n|}| s|S |r|  d| n| }| d| S )N:@r   )r_   r   r`   ra   	host_info	user_infos         r!   make_netlocz+_conda_url_from_string.<locals>.make_netloc   s`     )-6t$$d$$$$	 	08Fx,,(,,,h	))i)))r    Nvalc                 (    | t          d          | S )NzExpected to be non-null)
ValueError)rh   s    r!   get_or_raisez,_conda_url_from_string.<locals>.get_or_raise   s    ;6777
r    USERNAMEUSERz${})r_   r   r`   ra   )netloc)PASSWORDPASSTOKENKEYr9      )rr   CREDrp   rq   rs   z"Token URL detected without env varz\1/t/${z}\3)path)r   r   r   r   r   r   r   r   )r	   r   r   intcopyr_   r]   _replacer   hostnamera   token_patternsearchrv   groupsloggerwarningsubr   r
   )r%   resrg   r   r   r   rk   res_replaced_token_matchr   new_paths              r!   r+   r+      s   
3--C*3-*+3C=*@C*KSTW=*	* * * * #'L&*#'M(3- C    
 9S>>L
| 
+CL:v:NOO 	'00"{3<333)2%l&;<<%*	   1  L | /L>>>
 
  	'00"{)27#3777%l&;<<%*	   1  L !''11L,8BL!!!$QRR((dE @,???
 
  	@NN?@@@@$((/M///1B H (00h0??L|,,\!)#	 	 	 	r    r.   c                     | } | j         | j        | j        h}d |D             }t          | j        t          t          |                              S )Nc                     h | ]}||S )Nr   )rC   rS   s     r!   	<setcomp>z*_channel_from_conda_url.<locals>.<setcomp>,  s    EEEaq}}}}r    r*   )r   r   r   r#   r   tuplesorted)r.   env_vars_maybe_with_noneenv_varss      r!   r,   r,   %  sh    I" 
 FE3EEEH!F8,,--   r    channelsc                 <   |D ]}|                                 }|                     |          r|                     ||j        d          } |                                }|                     |          r|                     ||j        d          } |                                }|                     |          r|                     ||j        d          } |                                }|                     |          r|                     ||j        d          } | S )aL
  Normalize URLs from lockfiles to have env var placeholders.

    The env vars are associated with channel objects, so we do the replacement for
    each channel object individually.

    Conda lockfiles with tokens are censored to look like this:
    >>> conda_url = (
    ...     "http://localhost:32817/t/<TOKEN>/get/proxy-channel"
    ...     "/linux-64/zlib-1.3.1-hb9d3cd8_2.conda#c9f075ab2f33b3bbee9e62d4ad0a6cd8"
    ... )

    Mamba v1 lockfiles are censored with ***** instead of <TOKEN>
    >>> mamba_v1_url = conda_url.replace("<TOKEN>", "*****")

    Mamba v2 lockfiles are censored with ********** instead of <TOKEN>
    >>> mamba_v2_url = conda_url.replace("<TOKEN>", "**********")

    Create a channel with a token stored in an env var
    >>> os.environ["MY_C_REPO_TOKEN"] = "some-token"
    >>> channel_url = "http://localhost:32817/t/some-token/get/proxy-channel"
    >>> channel = Channel.from_string(channel_url)
    >>> channel  # doctest: +NORMALIZE_WHITESPACE
    Channel(url='http://localhost:32817/t/${MY_C_REPO_TOKEN}/get/proxy-channel',
        used_env_vars=('MY_C_REPO_TOKEN',))

    The normalized URL should have the token replaced with the env var placeholder
    >>> expected_normalized_url = conda_url.replace("<TOKEN>", "${MY_C_REPO_TOKEN}")

    Check that the normalized URL is correct for both conda and mamba censorings
    >>> normalized_conda_url = normalize_url_with_placeholders(conda_url, [channel])
    >>> normalized_mamba_v1_url = normalize_url_with_placeholders(mamba_v1_url, [channel])
    >>> normalized_mamba_v2_url = normalize_url_with_placeholders(mamba_v2_url, [channel])
    >>> assert normalized_conda_url == expected_normalized_url, normalized_conda_url
    >>> assert normalized_mamba_v1_url == expected_normalized_url, normalized_mamba_v1_url
    >>> assert normalized_mamba_v2_url == expected_normalized_url, normalized_mamba_v2_url

    Normalization should also work similarly for basic auth
    >>> os.environ["MY_C_USERNAME"] = "user"
    >>> os.environ["MY_C_PASSWORD"] = "pass"
    >>> channel_url = "http://user:pass@localhost:32817/channel"
    >>> channel = Channel.from_string(channel_url)
    >>> channel  # doctest: +NORMALIZE_WHITESPACE
    Channel(url='http://${MY_C_USERNAME}:${MY_C_PASSWORD}@localhost:32817/channel',
        used_env_vars=('MY_C_PASSWORD', 'MY_C_USERNAME'))
    >>> normalize_url_with_placeholders(channel_url, channels=[channel])
    'http://${MY_C_USERNAME}:${MY_C_PASSWORD}@localhost:32817/channel'

    Clean up
    >>> del os.environ["MY_C_REPO_TOKEN"]
    >>> del os.environ["MY_C_USERNAME"]
    >>> del os.environ["MY_C_PASSWORD"]
    r9   )r7   rV   r;   r%   r>   r@   r4   )r%   r   r/   
candidate1
candidate2
candidate3
candidate4s          r!   normalize_url_with_placeholdersr   3  s
   j  : :5577
>>*%% 	:++j'+q99C88::
>>*%% 	:++j'+q99C88::
>>*%% 	:++j'+q99C--//
>>*%% 	:++j'+q99CJr    )"r   rx   loggingrY   re	posixpathr   typingr   r   r   r   urllib.parser   r	   r
   pydanticr   r   #conda_lock._vendor.conda.common.urlr   r   	getLoggerr   r~   compiler{   r   r#   r   r]   r+   r,   r   r   r    r!   <module>r      s   @   				 				             - - - - - - - - - - - - 6 6 6 6 6 6 6 6 6 6 * * * * * * * *        
	8	$	$
CDD+ + + + +	 + + +"xO xO xO xO xOi xO xO xOv*.s)c]   *K K	 K K K K\y W    E EW E# E E E E E Er    