"""
Symfony module.

Implements the Symfony class representing the target application.
A Symfony instance is passed to EOS plugins for scanning and holds their results.
Methods and properties are provided to interact with the remote application.
"""

from re import sub
from urllib.parse import urljoin

from requests import Session

from eos.core import Base, Profiler
from eos.utils import Version, ucfirst


class Symfony(Base):
    """
    Symfony class.

    Represent the target Symfony application.
    Holds found info such as versions, secrets, etc.
    Provides methods to interact with the target while logging requests and associated tokens.
    """

    header = 'X-Debug-Token'

    def __init__(self, url, session=None, namespace='App', environment='dev', debug=True, root='src'):
        """
        Initialization.

        :param url: target URL
        :param session: requests session
        """

        self._url = url
        self.info = {}
        self.requests = []
        self.routes = {}
        self.files = {}
        self.session = session or Session()
        self._version = Version('0.0.0')
        self.profiler = Profiler(url, session=self.session)
        self.namespace = namespace
        self.environment = environment
        self.debug = debug
        self.root = root

    @property
    def version(self):
        """Get Symfony version."""
        return self._version

    @version.setter
    def version(self, value):
        self._version = Version(value)

    @property
    def token(self):
        """
        Get a valid profiler token.

        The returned token is the first one generated by the scanner.
        Usually used to get a valid token when its associated request does not matter.
        Returns None if no token.
        """

        if not self.requests:
            return None
        return self.requests[0].token

    @property
    def secret(self):
        """
        Get the application secret APP_SECRET.

        Secret used for cryptographic purposes by Symfony.
        Extract its value from previously found info.
        Returns None otherwise.
        """

        return self.info.get('env', {}).get('APP_SECRET')

    def url(self, path):
        """URL builder."""
        return urljoin(self._url + '/', path)

    def get(self, path='', **kwargs):
        """
        Wrapper on request.get.

        Prefix path with self.url and log requests/responses.

        :param path: URL path
        :param kwargs: wrapped to request.get
        :return: response
        """

        r = self.session.get(self.url(path), **kwargs)
        self.log_request(r)
        return r

    def log_request(self, r):
        """
        Log a request/response to the target Symfony.

        Extract the token from the response (from the X-Debug-Token header).
        Save it in the response and add the latter to self.requests for later reuse.
        Log it with DEBUG level if a token is found.

        :param r: request to log
        """

        token = r.headers.get(self.header, None)
        r.token = token
        self.requests.append(r)
        if r.token:
            self.log.debug('[%s] %s', token or '/', r.url)

    @property
    def kernel_container_cache(self):
        """
        Generate the XML kernel cache container path according to the Symfony version.

        | Version   | Cache filename                     |
        |-----------+------------------------------------|
        | 2.0 - 4.1 | srcDevDebugProjectContainer.xml    |
        | 4.2 - 4.4 | srcApp_KernelDevDebugContainer.xml |
        | 5.0 - 5.1 | App_KernelDevDebugContainer.xml    |

        :return: path to the kernel cache file relative to the application root
        """

        root = sub('[^a-zA-Z0-9_]+', '', self.root)
        cls = self.namespace + '_Kernel'
        env = ucfirst(self.environment)
        debug = 'Debug' if self.debug else ''

        if self.version <= '4.1':
            container = f'{root}{env}{debug}ProjectContainer'
        elif self.version <= '4.4':
            container = f'{root}{cls}{env}{debug}Container'
        else:
            container = f'{cls}{env}{debug}Container'

        return f'{self.cache}/{container}.xml'

    @property
    def cache(self):
        """Get the env dependent cache directory."""
        return f'var/cache/{self.environment}'

fd84af163a74986df2ea3fb3871549cc0813b714
<mask token>


class Symfony(Base):
    <mask token>
    <mask token>
    <mask token>

    @property
    def version(self):
        """Get Symfony version."""
        return self._version
    <mask token>
    <mask token>
    <mask token>

    def url(self, path):
        """URL builder."""
        return urljoin(self._url + '/', path)

    def get(self, path='', **kwargs):
        """
        Wrapper on request.get.

        Prefix path with self.url and log requests/responses.

        :param path: URL path
        :param kwargs: wrapped to request.get
        :return: response
        """
        r = self.session.get(self.url(path), **kwargs)
        self.log_request(r)
        return r

    def log_request(self, r):
        """
        Log a request/response to the target Symfony.

        Extract the token from the response (from the X-Debug-Token header).
        Save it in the response and add the latter to self.requests for later reuse.
        Log it with DEBUG level if a token is found.

        :param r: request to log
        """
        token = r.headers.get(self.header, None)
        r.token = token
        self.requests.append(r)
        if r.token:
            self.log.debug('[%s] %s', token or '/', r.url)

    @property
    def kernel_container_cache(self):
        """
        Generate the XML kernel cache container path according to the Symfony version.

        | Version   | Cache filename                     |
        |-----------+------------------------------------|
        | 2.0 - 4.1 | srcDevDebugProjectContainer.xml    |
        | 4.2 - 4.4 | srcApp_KernelDevDebugContainer.xml |
        | 5.0 - 5.1 | App_KernelDevDebugContainer.xml    |

        :return: path to the kernel cache file relative to the application root
        """
        root = sub('[^a-zA-Z0-9_]+', '', self.root)
        cls = self.namespace + '_Kernel'
        env = ucfirst(self.environment)
        debug = 'Debug' if self.debug else ''
        if self.version <= '4.1':
            container = f'{root}{env}{debug}ProjectContainer'
        elif self.version <= '4.4':
            container = f'{root}{cls}{env}{debug}Container'
        else:
            container = f'{cls}{env}{debug}Container'
        return f'{self.cache}/{container}.xml'

    @property
    def cache(self):
        """Get the env dependent cache directory."""
        return f'var/cache/{self.environment}'

<mask token>


class Symfony(Base):
    <mask token>
    <mask token>
    <mask token>

    @property
    def version(self):
        """Get Symfony version."""
        return self._version

    @version.setter
    def version(self, value):
        self._version = Version(value)
    <mask token>
    <mask token>

    def url(self, path):
        """URL builder."""
        return urljoin(self._url + '/', path)

    def get(self, path='', **kwargs):
        """
        Wrapper on request.get.

        Prefix path with self.url and log requests/responses.

        :param path: URL path
        :param kwargs: wrapped to request.get
        :return: response
        """
        r = self.session.get(self.url(path), **kwargs)
        self.log_request(r)
        return r

    def log_request(self, r):
        """
        Log a request/response to the target Symfony.

        Extract the token from the response (from the X-Debug-Token header).
        Save it in the response and add the latter to self.requests for later reuse.
        Log it with DEBUG level if a token is found.

        :param r: request to log
        """
        token = r.headers.get(self.header, None)
        r.token = token
        self.requests.append(r)
        if r.token:
            self.log.debug('[%s] %s', token or '/', r.url)

    @property
    def kernel_container_cache(self):
        """
        Generate the XML kernel cache container path according to the Symfony version.

        | Version   | Cache filename                     |
        |-----------+------------------------------------|
        | 2.0 - 4.1 | srcDevDebugProjectContainer.xml    |
        | 4.2 - 4.4 | srcApp_KernelDevDebugContainer.xml |
        | 5.0 - 5.1 | App_KernelDevDebugContainer.xml    |

        :return: path to the kernel cache file relative to the application root
        """
        root = sub('[^a-zA-Z0-9_]+', '', self.root)
        cls = self.namespace + '_Kernel'
        env = ucfirst(self.environment)
        debug = 'Debug' if self.debug else ''
        if self.version <= '4.1':
            container = f'{root}{env}{debug}ProjectContainer'
        elif self.version <= '4.4':
            container = f'{root}{cls}{env}{debug}Container'
        else:
            container = f'{cls}{env}{debug}Container'
        return f'{self.cache}/{container}.xml'

    @property
    def cache(self):
        """Get the env dependent cache directory."""
        return f'var/cache/{self.environment}'

<mask token>


class Symfony(Base):
    <mask token>
    <mask token>

    def __init__(self, url, session=None, namespace='App', environment=
        'dev', debug=True, root='src'):
        """
        Initialization.

        :param url: target URL
        :param session: requests session
        """
        self._url = url
        self.info = {}
        self.requests = []
        self.routes = {}
        self.files = {}
        self.session = session or Session()
        self._version = Version('0.0.0')
        self.profiler = Profiler(url, session=self.session)
        self.namespace = namespace
        self.environment = environment
        self.debug = debug
        self.root = root

    @property
    def version(self):
        """Get Symfony version."""
        return self._version

    @version.setter
    def version(self, value):
        self._version = Version(value)

    @property
    def token(self):
        """
        Get a valid profiler token.

        The returned token is the first one generated by the scanner.
        Usually used to get a valid token when its associated request does not matter.
        Returns None if no token.
        """
        if not self.requests:
            return None
        return self.requests[0].token
    <mask token>

    def url(self, path):
        """URL builder."""
        return urljoin(self._url + '/', path)

    def get(self, path='', **kwargs):
        """
        Wrapper on request.get.

        Prefix path with self.url and log requests/responses.

        :param path: URL path
        :param kwargs: wrapped to request.get
        :return: response
        """
        r = self.session.get(self.url(path), **kwargs)
        self.log_request(r)
        return r

    def log_request(self, r):
        """
        Log a request/response to the target Symfony.

        Extract the token from the response (from the X-Debug-Token header).
        Save it in the response and add the latter to self.requests for later reuse.
        Log it with DEBUG level if a token is found.

        :param r: request to log
        """
        token = r.headers.get(self.header, None)
        r.token = token
        self.requests.append(r)
        if r.token:
            self.log.debug('[%s] %s', token or '/', r.url)

    @property
    def kernel_container_cache(self):
        """
        Generate the XML kernel cache container path according to the Symfony version.

        | Version   | Cache filename                     |
        |-----------+------------------------------------|
        | 2.0 - 4.1 | srcDevDebugProjectContainer.xml    |
        | 4.2 - 4.4 | srcApp_KernelDevDebugContainer.xml |
        | 5.0 - 5.1 | App_KernelDevDebugContainer.xml    |

        :return: path to the kernel cache file relative to the application root
        """
        root = sub('[^a-zA-Z0-9_]+', '', self.root)
        cls = self.namespace + '_Kernel'
        env = ucfirst(self.environment)
        debug = 'Debug' if self.debug else ''
        if self.version <= '4.1':
            container = f'{root}{env}{debug}ProjectContainer'
        elif self.version <= '4.4':
            container = f'{root}{cls}{env}{debug}Container'
        else:
            container = f'{cls}{env}{debug}Container'
        return f'{self.cache}/{container}.xml'

    @property
    def cache(self):
        """Get the env dependent cache directory."""
        return f'var/cache/{self.environment}'

<mask token>


class Symfony(Base):
    """
    Symfony class.

    Represent the target Symfony application.
    Holds found info such as versions, secrets, etc.
    Provides methods to interact with the target while logging requests and associated tokens.
    """
    header = 'X-Debug-Token'

    def __init__(self, url, session=None, namespace='App', environment=
        'dev', debug=True, root='src'):
        """
        Initialization.

        :param url: target URL
        :param session: requests session
        """
        self._url = url
        self.info = {}
        self.requests = []
        self.routes = {}
        self.files = {}
        self.session = session or Session()
        self._version = Version('0.0.0')
        self.profiler = Profiler(url, session=self.session)
        self.namespace = namespace
        self.environment = environment
        self.debug = debug
        self.root = root

    @property
    def version(self):
        """Get Symfony version."""
        return self._version

    @version.setter
    def version(self, value):
        self._version = Version(value)

    @property
    def token(self):
        """
        Get a valid profiler token.

        The returned token is the first one generated by the scanner.
        Usually used to get a valid token when its associated request does not matter.
        Returns None if no token.
        """
        if not self.requests:
            return None
        return self.requests[0].token

    @property
    def secret(self):
        """
        Get the application secret APP_SECRET.

        Secret used for cryptographic purposes by Symfony.
        Extract its value from previously found info.
        Returns None otherwise.
        """
        return self.info.get('env', {}).get('APP_SECRET')

    def url(self, path):
        """URL builder."""
        return urljoin(self._url + '/', path)

    def get(self, path='', **kwargs):
        """
        Wrapper on request.get.

        Prefix path with self.url and log requests/responses.

        :param path: URL path
        :param kwargs: wrapped to request.get
        :return: response
        """
        r = self.session.get(self.url(path), **kwargs)
        self.log_request(r)
        return r

    def log_request(self, r):
        """
        Log a request/response to the target Symfony.

        Extract the token from the response (from the X-Debug-Token header).
        Save it in the response and add the latter to self.requests for later reuse.
        Log it with DEBUG level if a token is found.

        :param r: request to log
        """
        token = r.headers.get(self.header, None)
        r.token = token
        self.requests.append(r)
        if r.token:
            self.log.debug('[%s] %s', token or '/', r.url)

    @property
    def kernel_container_cache(self):
        """
        Generate the XML kernel cache container path according to the Symfony version.

        | Version   | Cache filename                     |
        |-----------+------------------------------------|
        | 2.0 - 4.1 | srcDevDebugProjectContainer.xml    |
        | 4.2 - 4.4 | srcApp_KernelDevDebugContainer.xml |
        | 5.0 - 5.1 | App_KernelDevDebugContainer.xml    |

        :return: path to the kernel cache file relative to the application root
        """
        root = sub('[^a-zA-Z0-9_]+', '', self.root)
        cls = self.namespace + '_Kernel'
        env = ucfirst(self.environment)
        debug = 'Debug' if self.debug else ''
        if self.version <= '4.1':
            container = f'{root}{env}{debug}ProjectContainer'
        elif self.version <= '4.4':
            container = f'{root}{cls}{env}{debug}Container'
        else:
            container = f'{cls}{env}{debug}Container'
        return f'{self.cache}/{container}.xml'

    @property
    def cache(self):
        """Get the env dependent cache directory."""
        return f'var/cache/{self.environment}'

"""
Symfony module.

Implements the Symfony class representing the target application.
A Symfony instance is passed to EOS plugins for scanning and holds their results.
Methods and properties are provided to interact with the remote application.
"""

from re import sub
from urllib.parse import urljoin

from requests import Session

from eos.core import Base, Profiler
from eos.utils import Version, ucfirst


class Symfony(Base):
    """
    Symfony class.

    Represent the target Symfony application.
    Holds found info such as versions, secrets, etc.
    Provides methods to interact with the target while logging requests and associated tokens.
    """

    header = 'X-Debug-Token'

    def __init__(self, url, session=None, namespace='App', environment='dev', debug=True, root='src'):
        """
        Initialization.

        :param url: target URL
        :param session: requests session
        """

        self._url = url
        self.info = {}
        self.requests = []
        self.routes = {}
        self.files = {}
        self.session = session or Session()
        self._version = Version('0.0.0')
        self.profiler = Profiler(url, session=self.session)
        self.namespace = namespace
        self.environment = environment
        self.debug = debug
        self.root = root

    @property
    def version(self):
        """Get Symfony version."""
        return self._version

    @version.setter
    def version(self, value):
        self._version = Version(value)

    @property
    def token(self):
        """
        Get a valid profiler token.

        The returned token is the first one generated by the scanner.
        Usually used to get a valid token when its associated request does not matter.
        Returns None if no token.
        """

        if not self.requests:
            return None
        return self.requests[0].token

    @property
    def secret(self):
        """
        Get the application secret APP_SECRET.

        Secret used for cryptographic purposes by Symfony.
        Extract its value from previously found info.
        Returns None otherwise.
        """

        return self.info.get('env', {}).get('APP_SECRET')

    def url(self, path):
        """URL builder."""
        return urljoin(self._url + '/', path)

    def get(self, path='', **kwargs):
        """
        Wrapper on request.get.

        Prefix path with self.url and log requests/responses.

        :param path: URL path
        :param kwargs: wrapped to request.get
        :return: response
        """

        r = self.session.get(self.url(path), **kwargs)
        self.log_request(r)
        return r

    def log_request(self, r):
        """
        Log a request/response to the target Symfony.

        Extract the token from the response (from the X-Debug-Token header).
        Save it in the response and add the latter to self.requests for later reuse.
        Log it with DEBUG level if a token is found.

        :param r: request to log
        """

        token = r.headers.get(self.header, None)
        r.token = token
        self.requests.append(r)
        if r.token:
            self.log.debug('[%s] %s', token or '/', r.url)

    @property
    def kernel_container_cache(self):
        """
        Generate the XML kernel cache container path according to the Symfony version.

        | Version   | Cache filename                     |
        |-----------+------------------------------------|
        | 2.0 - 4.1 | srcDevDebugProjectContainer.xml    |
        | 4.2 - 4.4 | srcApp_KernelDevDebugContainer.xml |
        | 5.0 - 5.1 | App_KernelDevDebugContainer.xml    |

        :return: path to the kernel cache file relative to the application root
        """

        root = sub('[^a-zA-Z0-9_]+', '', self.root)
        cls = self.namespace + '_Kernel'
        env = ucfirst(self.environment)
        debug = 'Debug' if self.debug else ''

        if self.version <= '4.1':
            container = f'{root}{env}{debug}ProjectContainer'
        elif self.version <= '4.4':
            container = f'{root}{cls}{env}{debug}Container'
        else:
            container = f'{cls}{env}{debug}Container'

        return f'{self.cache}/{container}.xml'

    @property
    def cache(self):
        """Get the env dependent cache directory."""
        return f'var/cache/{self.environment}'
