# -*- coding: utf8 -*-
"""
.. module:: burpui.misc.backend.interface
    :platform: Unix
    :synopsis: Burp-UI backend interface.

.. moduleauthor:: Ziirish <hi+burpui@ziirish.me>

"""
import os
import re
import logging

from abc import ABCMeta, abstractmethod

from six import with_metaclass

G_BURPPORT = 4972
G_BURPHOST = u'::1'
G_BURPBIN = u'/usr/sbin/burp'
G_STRIPBIN = u'/usr/sbin/vss_strip'
G_STRIPBIN2 = u'/usr/bin/vss_strip'
G_BURPCONFCLI = u'/etc/burp/burp.conf'
G_BURPCONFSRV = u'/etc/burp/burp-server.conf'
G_TMPDIR = u'/tmp/bui'
G_TIMEOUT = 15
G_ZIP64 = False
G_INCLUDES = [u'/etc/burp']
G_ENFORCE = False
G_REVOKE = True


class BUIbackend(with_metaclass(ABCMeta, object)):
    """The :class:`burpui.misc.backend.interface.BUIbackend` class provides
    a consistent interface backend for any ``burp`` server.

    :param server: ``Flask`` server instance in order to access logger
                   and/or some global settings
    :type server: :class:`burpui.server.BUIServer`

    :param conf: Configuration file to use
    :type conf: str
    """

    # cache the running clients
    running = []
    # do we need to refresh the cache?
    refresh = None
    # Defaults config parameters
    defaults = {}

    logger = logging.getLogger('burp-ui')

    def __init__(self, server=None, conf=None):  # pragma: no cover
        """
        :param server: Application context
        :type server: :class:`burpui.server.BUIServer`
        """
        self.app = server
        self.zip64 = G_ZIP64
        self.timeout = G_TIMEOUT
        self.host = G_BURPHOST
        self.port = G_BURPPORT
        self.burpbin = G_BURPBIN
        self.stripbin = G_STRIPBIN
        self.burpconfcli = G_BURPCONFCLI
        self.burpconfsrv = G_BURPCONFSRV
        self.includes = G_INCLUDES
        self.revoke = G_REVOKE
        self.enforce = G_ENFORCE
        self.running = []
        burp_opts = {
            'bport': G_BURPPORT,
            'bhost': G_BURPHOST,
            'burpbin': G_BURPBIN,
            'stripbin': G_STRIPBIN,
            'bconfcli': G_BURPCONFCLI,
            'bconfsrv': G_BURPCONFSRV,
            'timeout': G_TIMEOUT,
            'tmpdir': G_TMPDIR,
        }
        self.defaults = {
            'Burp': burp_opts,
            # TODO: remove this when we drop the compatibility
            'Burp1': burp_opts,
            'Burp2': burp_opts,
            'Experimental': {
                'zip64': G_ZIP64,
            },
            'Security': {
                'includes': G_INCLUDES,
                'revoke': G_REVOKE,
                'enforce': G_ENFORCE,
            },
        }
        self.defaults['Burp2']['stripbin'] = G_STRIPBIN2
        tmpdir = G_TMPDIR
        if conf is not None:
            conf.update_defaults(self.defaults)
            section = 'Burp'
            if section not in conf.options:
                section = 'Burp{}'.format(self._vers)
                if section in conf.options:
                    # TODO: remove the compatibility
                    self.logger.critical(
                        'The "[{}]" section is DEPRECATED and will be removed '
                        'in v0.7.0. Please use the "[Burp]" section '
                        'instead.'.format(section)
                    )
            conf.default_section(section)
            self.port = conf.safe_get('bport', 'integer')
            self.host = conf.safe_get('bhost')
            self.burpbin = self._get_binary_path(
                conf,
                'burpbin',
                G_BURPBIN,
                sect=section
            )
            STRIPBIN_DEFAULT = G_STRIPBIN
            if self._vers == 2:
                STRIPBIN_DEFAULT = G_STRIPBIN2
            self.stripbin = self._get_binary_path(
                conf,
                'stripbin',
                STRIPBIN_DEFAULT,
                sect=section
            )
            confcli = conf.safe_get('bconfcli')
            confsrv = conf.safe_get('bconfsrv')
            tmpdir = conf.safe_get('tmpdir')
            self.timeout = conf.safe_get(
                'timeout',
                'integer'
            )

            # Experimental options
            self.zip64 = conf.safe_get(
                'zip64',
                'boolean',
                section='Experimental'
            )

            # Security options
            self.includes = conf.safe_get(
                'includes',
                'force_list',
                section='Security'
            )
            self.enforce = conf.safe_get(
                'enforce',
                'boolean',
                section='Security'
            )
            self.revoke = conf.safe_get(
                'revoke',
                'boolean',
                section='Security'
            )

            if confcli and not os.path.isfile(confcli):
                self.logger.warning("The file '%s' does not exist", confcli)

            if confsrv and not os.path.isfile(confsrv):
                self.logger.warning("The file '%s' does not exist", confsrv)

            if not self.burpbin and self._vers == 2 and \
                    getattr(self.app, 'strict', True):
                # The burp binary is mandatory for this backend
                raise Exception(
                    'This backend *CAN NOT* work without a burp binary'
                )

            if self.host not in ['127.0.0.1', '::1'] and self._vers == 1:
                self.logger.warning("Invalid value for 'bhost'. Must be '127.0.0.1' or '::1'. Falling back to '%s'", G_BURPHOST)
                self.host = G_BURPHOST

            self.burpconfcli = confcli
            self.burpconfsrv = confsrv

        if (tmpdir and os.path.exists(tmpdir) and
                not os.path.isdir(tmpdir)):
            self.logger.warning(
                "'%s' is not a directory",
                tmpdir
            )
            if tmpdir == G_TMPDIR and \
                    getattr(self.app, 'strict', True):
                raise IOError(
                    "Cannot use '{}' as tmpdir".format(tmpdir)
                )
            tmpdir = G_TMPDIR
            if os.path.exists(tmpdir) and not os.path.isdir(tmpdir) and \
                    getattr(self.app, 'strict', True):
                raise IOError(
                    "Cannot use '{}' as tmpdir".format(tmpdir)
                )
        if tmpdir and not os.path.exists(tmpdir):
            os.makedirs(tmpdir)

        self.tmpdir = tmpdir

    # Utilities functions
    def _get_binary_path(self, config, field, default=None, sect='Burp'):
        """Helper function to retrieve a binary path from the configuration

        :param field: Field name to look for
        :type field: str

        :param default: Default value in case the retrieved value is not correct
        :type default: str
        """
        temp = config.safe_get(field, section=sect) or default

        if temp and not temp.startswith('/'):
            self.logger.warning("Please provide an absolute path for the '{}' option. Fallback to '{}'".format(field, default))
            temp = default
        elif temp and not re.match(r'^\S+$', temp):
            self.logger.warning("Incorrect value for the '{}' option. Fallback to '{}'".format(field, default))
            temp = default
        elif temp and (not os.path.isfile(temp) or not os.access(temp, os.X_OK)):
            self.logger.warning("'{}' does not exist or is not executable. Fallback to '{}'".format(temp, default))
            temp = default

        if temp and (not os.path.isfile(temp) or not os.access(temp, os.X_OK)):  # pragma: no cover
            self.logger.error("Ooops, '{}' not found or is not executable".format(temp))
            temp = None

        return temp

    """
    Utilities functions
    """

    @abstractmethod
    def status(self, query='\n', timeout=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.status` method is
        used to send queries to the Burp server

        :param query: Query to send to the server
        :type query: str

        :param timeout: Query timeout in seconds
        :type timeout: int

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: The output returned by the server parsed as an array

        Example::

            [
                "client1\t2\ti\t576 0 1443766803",
                "client2\t2\ti\t1 0 1422189120"
            ]
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def get_backup_logs(self, number, client, forward=False, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.get_backup_logs`
        function is used to retrieve the burp logs depending the burp-server
        version.

        :param number: Backup number to work on
        :type number: int

        :param client: Client name to work on
        :type client: str

        :param forward: Is the client name needed in later process
        :type forward: bool

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: Dict containing the backup log

        Example::

            {
                "dir": {
                    "changed": 0,
                    "deleted": 0,
                    "new": 17,
                    "scanned": 30246,
                    "total": 30246,
                    "unchanged": 30229
                },
                "duration": 436,
                "efs": {
                    "changed": 0,
                    "deleted": 0,
                    "new": 0,
                    "scanned": 0,
                    "total": 0,
                    "unchanged": 0
                },
                "encrypted": false,
                "end": 1443767237,
                "files": {
                    "changed": 47,
                    "deleted": 2,
                    "new": 2,
                    "scanned": 227377,
                    "total": 227377,
                    "unchanged": 227328
                },
                "files_enc": {
                    "changed": 0,
                    "deleted": 0,
                    "new": 0,
                    "scanned": 0,
                    "total": 0,
                    "unchanged": 0
                },
                "hardlink": {
                    "changed": 0,
                    "deleted": 0,
                    "new": 0,
                    "scanned": 28,
                    "total": 28,
                    "unchanged": 28
                },
                "meta": {
                    "changed": 0,
                    "deleted": 0,
                    "new": 0,
                    "scanned": 58,
                    "total": 58,
                    "unchanged": 58
                },
                "meta_enc": {
                    "changed": 0,
                    "deleted": 0,
                    "new": 0,
                    "scanned": 0,
                    "total": 0,
                    "unchanged": 0
                },
                "number": 576,
                "received": 11691704,
                "softlink": {
                    "changed": 0,
                    "deleted": 0,
                    "new": 0,
                    "scanned": 9909,
                    "total": 9909,
                    "unchanged": 9909
                },
                "special": {
                    "changed": 0,
                    "deleted": 0,
                    "new": 0,
                    "scanned": 1,
                    "total": 1,
                    "unchanged": 1
                },
                "start": 1443766801,
                "total": {
                    "changed": 47,
                    "deleted": 2,
                    "new": 19,
                    "scanned": 267619,
                    "total": 267619,
                    "unchanged": 267553
                },
                "totsize": 52047768383,
                "vssfooter": {
                    "changed": 0,
                    "deleted": 0,
                    "new": 0,
                    "scanned": 0,
                    "total": 0,
                    "unchanged": 0
                },
                "vssfooter_enc": {
                    "changed": 0,
                    "deleted": 0,
                    "new": 0,
                    "scanned": 0,
                    "total": 0,
                    "unchanged": 0
                },
                "vssheader": {
                    "changed": 0,
                    "deleted": 0,
                    "new": 0,
                    "scanned": 0,
                    "total": 0,
                    "unchanged": 0
                },
                "vssheader_enc": {
                    "changed": 0,
                    "deleted": 0,
                    "new": 0,
                    "scanned": 0,
                    "total": 0,
                    "unchanged": 0
                },
                "windows": "false"
            }
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def get_clients_report(self, clients, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.get_clients_report`
        function returns the computed/compacted data to display clients report.

        :param clients: List of clients as returned by
                        :func:`burpui.misc.backend.interface.BUIbackend.get_all_clients`
        :type clients: list

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: A dict with the computed data
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def get_counters(self, name=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.get_counters`
        function returns a dict of counters for a given client while it performs
        a backup.

        :param name: Name of the client for which you'd like stats
        :type name: str

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: A dict of counters
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def is_backup_running(self, name=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.is_backup_running`
        functions tells you if a given client is currently performing a backup.

        :param name: Name of the client
        :type name: str

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: True or False
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def is_one_backup_running(self, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.is_one_backup_running`
        function tells you if at least one backup is running.

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: A list of running clients
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def get_all_clients(self, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.get_all_clients`
        function returns a list containing all the clients with their states.

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: A list of clients

        Example::

            [
                {
                    "last": "2015-10-02 08:20:03",
                    "name": "client1",
                    "state": "idle",
                },
                {
                    "last": "2015-01-25 13:32:00",
                    "name": "client2",
                    "state": "idle"
                }
            ]
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def get_client_status(self, name=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.get_client_status`
        function returns the status of a given client with its last stats.

        :param name: What client status do we want
        :type name: str
        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: The last status of a given client

        Example::

            {
                "state": "idle",
                "percent": null,
                "phase": null,
                "last": "never"
            }

        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def get_client(self, name=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.get_client`
        function returns a list of dict representing the backups of a given
        client.

        :param name: Client name
        :type name: str

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: A list of backups

        Example::

            [
                {
                    "date": "2015-01-25 13:32:00",
                    "deletable": true,
                    "encrypted": true,
                    "number": "1",
                    "received": 889818873,
                    "size": 35612321050
                }
            ]
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def get_client_filtered(self, name=None, limit=-1, page=None, start=None, end=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.get_client_filtered`
        function returns a list of dict representing the backups of a given
        client filtered by the given criteria.

        :param name: Client name
        :type name: str

        :param limit: Number of element to return, -1 for not limit
        :type limit: int

        :param page: What page to retrieve
        :type page: int

        :param start: Return elements after this date
        :type start: int

        :param end: Return elements until this date
        :type end: int

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: A list of backups

        Example::

            [
                {
                    "date": "2015-01-25 13:32:00",
                    "deletable": true,
                    "encrypted": true,
                    "number": "1",
                    "received": 889818873,
                    "size": 35612321050
                }
            ]
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def get_tree(self, name=None, backup=None, root=None, level=-1, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.get_tree`
        function returns a list of dict representing files/dir (with their
        attr) within a given path

        :param name: Client name
        :type name: str

        :param backup: Backup number
        :type backup: int

        :param root: Root path to look into
        :type root: str

        :param level: Level of the tree relative to its root
        :type level: int

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: A list of files/dir within the given path with their attr

        Example::

            [
                {
                    "date": "2015-01-23 20:00:07",
                    "gid": "0",
                    "inodes": "168",
                    "mode": "drwxr-xr-x",
                    "name": "/",
                    "parent": "",
                    "fullname": "/",
                    "level": -1,
                    "size": "12.0KiB",
                    "type": "d",
                    "uid": "0",
                    "folder": True,
                    "children": []
                }
            ]
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def delete_backup(self, name=None, backup=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.delete_backup`
        function performs a backup deletion and returns an error message if
        the command failed.

        :param name: Client name
        :type name: str

        :param backup: Backup number
        :type backup: int

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: An error message if the command failed
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def restore_files(self, name=None, backup=None, files=None, strip=None, archive='zip', password=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.restore_files`
        function performs a restoration and returns a tuple containing the path
        of the generated archive and/or a message if an error happened.

        :param name: Client name
        :type name: str

        :param backup: Backup number
        :type backup: int

        :param files: A string representing a list of files to restore
        :type files: str

        Example::

            ['/etc/passwd', '/etc/shadow']

        :param strip: Number of parent directories to strip while restoring
                      files
        :type strip: int

        :param archive: Format of the generated archive (may be zip, tar.gz or
                        tar.bz2)
        :type archive: str

        :param password: Password for encrypted backups
        :type password: str

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: A tuple with the generated archive path and/or an error message
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def read_conf_srv(self, conf=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.read_conf_srv`
        function returns a dict of options present in the server config file.

        :param conf: Complementary configuration file (for instance, file
                     inclusions)
        :type conf: str

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: Dict of options

        Example::

            {
                "boolean": [
                    {
                        "name": "hardlinked_archive",
                        "value": false
                    },
                    {
                        "name": "syslog",
                        "value": true
                    },
                ],
                "clients": [
                    {
                        "name": "client1",
                        "value": "/etc/burp/clientconfdir/client1"
                    },
                    {
                        "name": "client2",
                        "value": "/etc/burp/clientconfdir/client2"
                    },
                ],
                "common": [
                    {
                        "name": "mode",
                        "value": "server"
                    },
                    {
                        "name": "directory",
                        "value": "/srv/burp"
                    },
                ],
                "includes": [],
                "includes_ext": [],
                "integer": [
                    {
                        "name": "port",
                        "value": 4971
                    },
                    {
                        "name": "status_port",
                        "value": 4972
                    },
                    {
                        "name": "max_children",
                        "value": 5
                    },
                    {
                        "name": "max_status_children",
                        "value": 5
                    }
                ],
                "multi": [
                    {
                        "name": "keep",
                        "value": [
                            "7",
                            "4",
                            "4"
                        ]
                    },
                    {
                        "name": "timer_arg",
                        "value": [
                            "12h",
                            "Mon,Tue,Thu,Fri,17,18,19,20,21,22,23",
                            "Wed,Sat,Sun,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23"
                        ]
                    }
                ]
            }
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def read_conf_cli(self, client=None, conf=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.read_conf_cli`
        function works the same way as the
        :func:`burpui.misc.backend.interface.BUIbackend.read_conf_srv` function
        but for the client config file.
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def store_conf_srv(self, data, conf=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.store_conf_srv`
        functions is used to save the new settings in the configuration file.

        :param data: Data as sent by the web-form
        :type data: dict

        :param conf: Force the file path (for file inclusions for instance)
        :type conf: str

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: A list of notifications to return to the UI (success or
                  failure)

        Example::

            [[0, "Success"]]
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def store_conf_cli(self, data, client=None, conf=None, template=False, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.store_conf_cli`
        function works the same way as the
        :func:`burpui.misc.backend.interface.BUIbackend.store_conf_srv` function
        but for the client config file.
        It takes an extra parameter:

        :param client: Name of the client for which to apply this config
        :type client: str
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def get_parser_attr(self, attr=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.get_parser_attr`
        function is used to retrieve some attributes from the Parser.
        This function is useful in multi-agent mode because the front-end needs
        to access the backend attributes through the agents.

        :param attr: Name of the attribute to retrieve
        :type attr: str

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: The requested attribute or an empty list
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def expand_path(self, path=None, source=None, client=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.expand_path`
        function is used to expand path of file inclusions glob the user can
        set in the setting panel.
        This function is also a *proxy* for multi-agent setup.

        :param path: The glob/path to expand
        :type path: str

        :param source: In which file are we working
        :type source: str

        :param client: The client name when working on client files
        :type client: str

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: A list of files or an empty list
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def clients_list(self, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.clients_list`
        function is used to retrieve a list of clients with their configuration
        file.

        :returns: A list of clients with their configuration file
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def delete_client(self, client=None, keepconf=False, delcert=False, revoke=False, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.delete_client`
        function is used to delete a client from burp's configuration.

        :param client: The name of the client to remove
        :type client: str

        :param keepconf: Whether to keep the conf (in order to just revoke/delete the certs for instance)
        :type keepconf: bool

        :param delcert: Whether to delete the associated certificate
        :type delcert: bool

        :param revoke: Whether to revoke the associated certificate
        :type revoke: bool

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: A list of notifications to return to the UI (success or
                  failure)
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def is_server_restore(self, client=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.is_server_restore`
        function is used to know if there is a server-initiated restoration file
        in place and retrieve its content in order to edit it.

        :param client: The name of the client to look for
        :type client: str

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: A dict representing the content of the server-initiated
                  restoration file
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def cancel_server_restore(self, client=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.cancel_server_restore`
        function is used to delete the server-initiated restoration file of a
        given client.

        :param client: The name of the client to look for
        :type client: str

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: A list of notifications to return to the UI (success or
                  failure)

        Example::

            [[0, "Success"]]
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def server_restore(self, client=None, backup=None, files=None, strip=None, force=None, prefix=None, restoreto=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.server_restore`
        function is used to schedule a server-side initiated restoration.

        :param client: Client name
        :type client: str

        :param backup: Backup number
        :type backup: int

        :param files: List of files to restore
        :type files: str

        :param strip: Number of leading path to strip
        :type strip: int

        :param force: Whether to force overriding files or not
        :type force: bool

        :param prefix: Where to restore files
        :type prefix: str

        :param retoreto: Restore on an other client
        :type restoreto: str

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: A list of notifications to return to the UI (success or
                  failure)
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def is_server_backup(self, client=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.is_server_backup`
        function is used to know if there is a server-initiated backup file
        in place.

        :param client: The name of the client to look for
        :type client: str

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: True or False
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def cancel_server_backup(self, client=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.cancel_server_backup`
        function is used to delete the server-initiated backup file of a given
        client.

        :param client: The name of the client to look for
        :type client: str

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: A list of notifications to return to the UI (success or
                  failure)

        Example::

            [[0, "Success"]]
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def server_backup(self, client=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.server_backup`
        function is used to schedule a server-side initiated backup.

        :param client: Client name
        :type client: str

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: A list of notifications to return to the UI (success or
                  failure)
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def revocation_enabled(self, agent=None):
        """The
        :func:`burpui.misc.backend.interface.BUIbackend.revocation_enabled`
        function is used to know if the revocation feature is enabled or not.

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: True or False
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def get_client_version(self, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.get_client_version`
        function returns the client version used to connect to the server.

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: Burp client version
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def get_server_version(self, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.get_server_version`
        function returns the server version (if any).

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: Burp server version
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def get_client_labels(self, client=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.get_client_labels`
        function returns a list of labels (if any) for a given client.

        .. note:: Labels are only available since Burp 2.0.34

        :param client: The client for which you want the labels
        :type client: str

        :param agent: What server to ask (only in multi-agent mode)
        :type agent: str

        :returns: A list of labels or an empty list
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def get_attr(self, name, default=None, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.get_attr`
        function returns the given attribute or default.
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def get_parser(self, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.get_parser`
        function returns the parser of the current backend.
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def get_file(self, path, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.get_file`
        function is used to retrieve a file on a remote agent.
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def del_file(self, path, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.del_file`
        function is used to delete a file on a remote agent.
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover

    @abstractmethod
    def version(self, agent=None):
        """The :func:`burpui.misc.backend.interface.BUIbackend.version` function
        returns the version of the given agent.
        """
        raise NotImplementedError("Sorry, the current Backend does not implement this method!")  # pragma: no cover
