%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /opt/imunify360/venv/lib/python3.8/site-packages/defence360agent/simple_rpc/
Upload File :
Create Path :
Current File : //opt/imunify360/venv/lib/python3.8/site-packages/defence360agent/simple_rpc/endpoints.py

"""
This program is free software: you can redistribute it and/or modify it under 
the terms of the GNU General Public License as published by 
the Free Software Foundation, either version 3 of the License, 
or (at your option) any later version.


This program is distributed in the hope that it will be useful, 
but WITHOUT ANY WARRANTY; without even the implied warranty of 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
See the GNU General Public License for more details.


You should have received a copy of the GNU General Public License
 along with this program.  If not, see <https://www.gnu.org/licenses/>.

Copyright © 2019 Cloud Linux Software Inc.

This software is also available under ImunifyAV commercial license,
see <https://www.imunify360.com/legal/eula>


Here you enumerate rpc endpoints
"""
import asyncio
import json
import os
from logging import getLogger

from defence360agent import files
from defence360agent.api.jwt_issuer import JWTIssuer
from defence360agent.api.newsfeed import NewsFeed
from defence360agent.api.pam_auth import PamAuth
from defence360agent.contracts import eula
from defence360agent.contracts.config import ANTIVIRUS_MODE, ConfigFile
from defence360agent.contracts.config import Core as CoreConfig
from defence360agent.contracts.config import (
    ImmutableMerger,
    LocalConfig,
    MutableMerger,
    Packaging,
    effective_user_config,
)
from defence360agent.contracts.license import LicenseCLN
from defence360agent.internals.cln import CLN, CLNError, InvalidLicenseError
from defence360agent.rpc_tools import ValidationError
from defence360agent.rpc_tools.lookup import (
    CommonEndpoints,
    RootEndpoints,
    bind,
)
from defence360agent.subsys.panels.base import PanelException
from defence360agent.utils import (
    CheckRunError,
    antivirus_mode,
    check_db,
    check_run,
    getpwnam,
)
from defence360agent.utils.config import update_config
from defence360agent.utils.support import ZendeskAPIError, send_request

if antivirus_mode.disabled:
    from im360.subsys.panels import hosting_panel
else:
    from defence360agent.subsys.panels import hosting_panel

logger = getLogger(__name__)


async def _get_doctor_key():
    dir_ = Packaging.DATADIR
    if not os.path.isdir(dir_):
        dir_ = '..'
    out = await check_run([os.path.join(dir_, 'scripts', 'imunify-doctor.sh')])
    key = out.decode().strip()
    return key


class ConfigEndpoints(CommonEndpoints):
    @bind('config', 'show')
    async def config_show(self, user=None):
        full_conf = ConfigFile()
        if user:
            user_conf_dict = effective_user_config(full_conf, ConfigFile(user))
            return {"items": user_conf_dict}
        else:
            return {"items": full_conf.config_to_dict()}

    @bind("config", "show", "defaults")
    async def config_show_defaults(self):
        layer_paths = MutableMerger.get_layer_names()
        return {
            "items": {
                "mutable_config": MutableMerger(layer_paths).configs_to_dict(),
                "local_config": LocalConfig().config_to_dict(normalize=False),
                "immutable_config": ImmutableMerger(
                    layer_paths
                ).configs_to_dict(),
            }
        }

    @bind('config', 'update')
    async def config_update(self, items=None, data=None, user=None):
        # workaround for https://cloudlinux.atlassian.net/browse/DEF-3902
        # TODO: remove items from method parameters
        if items:
            data = items[0]
        new_data = json.loads(data)
        await update_config(
            self._sink, new_data, user,
        )
        return await self.config_show(user)

    @bind('config', 'update-ui')
    async def config_update_ui(self, data=None, user=None):
        await update_config(self._sink, data, user)
        return await self.config_show(user)


class LoginEndpoints(CommonEndpoints):
    @bind('login', 'pam')
    async def login_via_pam(self, username, password):
        pam_auth = PamAuth()
        authenticated = pam_auth.authenticate(username, password)
        if not authenticated:
            raise ValidationError('Authentication failed')

        return {
            'items': JWTIssuer().get_token(
                username,
                await pam_auth.get_user_type(username)
            )
        }


class RootLoginEndpoints(RootEndpoints):
    @bind('login', 'get')
    async def login_get(self, username):
        if not getpwnam(username):
            raise ValidationError('User name not found')

        return {
            'items': JWTIssuer().get_token(
                username,
                await PamAuth().get_user_type(username)
            )
        }


class NewsEndpoints(RootEndpoints):
    @bind('get-news')
    async def get_news(self):
        return {
            'items': await NewsFeed.get()
        }


class Endpoints(RootEndpoints):
    license_info = LicenseCLN.license_info

    @bind('register')
    async def register(self, regkey=None):
        if LicenseCLN.is_registered():
            if LicenseCLN.is_valid():
                if not ANTIVIRUS_MODE:
                    raise ValidationError('Agent is already registered')
            else:
                logger.info('Unregistering invalid license: %s' %
                            LicenseCLN.get_token())
                await self.unregister()
        try:
            await CLN.register(regkey)
        except InvalidLicenseError as e:
            raise ValidationError(str(e))
        except CLNError as e:
            logger.warning("Can't register %r as imunify360 key. Trying to "
                           "register it as a web panel key instead", regkey)
            try:
                await CLN.register(
                    await hosting_panel.HostingPanel().retrieve_key())
            except NotImplementedError:
                logger.warning("Registration with web panel's key doesn't "
                               "supported")
                raise ValidationError(str(e))
            except PanelException as panel_e:
                raise ValidationError("{}, {}".format(str(e), str(panel_e)))
            except (CLNError, InvalidLicenseError) as e:
                raise ValidationError(str(e))
        return {}

    @bind('unregister')
    async def unregister(self):
        if not LicenseCLN.is_registered():
            raise ValidationError('Agent is not registered yet')
        if LicenseCLN.is_free():
            raise ValidationError("Free license can not be unregistered")

        await CLN.unregister()
        return {}

    @bind('update-license')
    async def update_license(self):
        if not LicenseCLN.is_registered():
            raise ValidationError('Unregistered (server-id is not assigned)')
        token = LicenseCLN.get_token()
        LicenseCLN.users_count = (await hosting_panel.HostingPanel()
                                  .users_count())
        new_token = await CLN.refresh_token(token)
        if new_token is None:
            raise ValidationError('License does not exist. Agent unregistered')
        return {}

    @bind('rstatus')
    async def rstatus(self):
        LicenseCLN.get_token.cache_clear()
        if not LicenseCLN.is_valid():
            raise ValidationError('License is invalid for current server')
        return self.license_info()

    @bind('version')
    async def version(self):
        return {'items': CoreConfig.VERSION}

    @bind('update')
    async def update_files(self, subj=None, force=False):
        try:
            await files.update(subj, force)
        except (asyncio.TimeoutError, files.UpdateError) as err:
            pass  # the error has been logged in files.update already

    @bind('eula', 'accept')
    async def eula_accept(self):
        await eula.accept()

    @bind('eula', 'show')
    async def eula_show(self):
        return eula.text()

    @bind('checkdb')
    async def checkdb(self):
        check_db.check_and_repair()

    @bind('doctor')
    async def doctor(self):
        key = await _get_doctor_key()
        return 'Please, provide this key:\n%s\n' \
               'to Imunify360 Support Team\n' % key

    @bind('support', 'send')
    async def send_to_support(self,
                              email,
                              subject,
                              description,
                              cln=None,
                              attachments=None):

        # Generating doctor and extracting key from output
        try:
            doctor_key = await _get_doctor_key()
        except CheckRunError:
            doctor_key = None

        # Sending request via Zendesk API
        # https://developer.zendesk.com/rest_api/docs/core/requests#anonymous-requests
        try:
            ticket_url = await send_request(
                email,
                subject,
                description,
                doctor_key,
                cln,
                attachments
            )
        except ZendeskAPIError as e:
            logger.error(
                "Got error from Zendesk API. error=%s, description=%s,"
                " details=%s", e.error, e.description, e.details)
            raise

        return {'items': [ticket_url]}

Zerion Mini Shell 1.0