Mini Shell

Direktori : /usr/share/lvemanager-xray/plugins/
Upload File :
Current File : //usr/share/lvemanager-xray/plugins/install-xray-plugin.py

#!/opt/cloudlinux/venv/bin/python3 -bb
#coding:utf-8

# Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2021 All Rights Reserved
#
# Licensed under CLOUD LINUX LICENSE AGREEMENT
# http://cloudlinux.com/docs/LICENSE.TXT
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
import os
import re
import sys
import json
import shlex
import shutil
import argparse
import subprocess
import configparser
import cldetectlib as detect
from clcommon.utils import get_rhn_systemid_value
from clcommon.lib.cledition import is_cl_solo_edition
from clcommon.ui_config import UIConfig

SOURCE_PATH_BASE = "/usr/share/lvemanager-xray/"
SOURCE_PATH_ADMIN = "/usr/share/lvemanager-xray/xray-admin/"
SOURCE_PATH_USER = "/usr/share/lvemanager-xray/xray-user/"
LVEMANAGER_SOURCE_PATH = "/usr/share/l.v.e-manager/"
XRAY_MANAGER_UTILITY = "/usr/sbin/cloudlinux-xray-manager"
DYNAMICUI_SYNC_CONFIG_COMMAND = "/usr/share/l.v.e-manager/utils/dynamicui.py --sync-conf=all --silent"
CLOUDLINUX_CONFIG_COMMAND = "/usr/sbin/cloudlinux-config set --data '{\"options\": {\"uiSettings\": {\"hideXrayApp\": true}}}' --json"
PANEL_INTEGRATION_CONFIG = '/opt/cpvendor/etc/integration.ini'
CLOUDLINUX_TRANSLATIONS_DIR = '/usr/share/cloudlinux-translations/'
CHECK_PLUGIN_CRON = {
    "name":  "xray-plugin-check-cron",
    "schedule": "*/10 * * * *",
    "executor": "root",
    "command": "/usr/bin/flock -n /var/run/cloudlinux-xray-plugin-check.cronlock /usr/share/lvemanager-xray/plugins/install-xray-plugin.py --check > /dev/null 2>&1"
}

class Base:
    def __init__(self):
        pass

    def add_cron(self, file_name, schedule, executor, command):
        """
        Create cron job
        :param file_name: cron name
        :param schedule: schedule of execution like "* * * * *"
        :param executor: user to run cron
        :param command: command to execute
        :return: None
        """
        try:
            f = open('/etc/cron.d/' + file_name, 'w')
            f.write("{} {} {}\n".format(schedule, executor, command))
            f.close()
        except Exception as e:
            print('Cannot add cron job. {}'.format(e))

    def remove_cron(self, file_name):
        """
        Remove cron
        :param file_name: cron name
        :return: None
        """
        try:
            if file_name:
                os.remove('/etc/cron.d/' + file_name)
        except Exception as e:
            print('Cannot remove cron job. {}'.format(e))

    def parse_command(self, command):
        """
        Parses a command string into a list of arguments.
        """
        if isinstance(command, str):
            if command.strip() == "":
                return []
            return shlex.split(command)
        elif isinstance(command, list):
            return command
        else:
            return []

    def exec_command(self, command, env=None):
        """
        This function will run passed command
        in command line and returns result
        :param command:
        :param env:
        :return:
        """
        result = []
        try:
            args = self.parse_command(command)
            if not args:
                raise ValueError(f"The provided command is not valid: {command}")
            p = subprocess.Popen(args, stdout=subprocess.PIPE, env=env, text=True)
            while 1:
                output = p.stdout.readline()
                if not output:
                    break
                if output.strip() != "":
                    result.append(output.strip())
        except Exception as e:
            print ("Call process error: " + str(e))
        return result

    def disable_agent(self):
        system_id = self.get_system_id()
        if system_id is None:
            print("Warning: Cannot disable user-agent because system_id is None.")
            return
        self.exec_command("{} {} --system_id {}"
                          .format(XRAY_MANAGER_UTILITY, "disable-user-agent", system_id))

    def enable_agent(self):
        system_id = self.get_system_id()
        if system_id is None:
            print("Warning: Cannot enable user-agent because system_id is None.")
            return
        self.exec_command("{} {} --system_id {}"
                          .format(XRAY_MANAGER_UTILITY, "enable-user-agent", system_id))

    def is_agent_enabled_in_config(self):
        return UIConfig().get_param('hideXrayApp', 'uiSettings') is False

    def sync_ui_config(self):
        self.exec_command(DYNAMICUI_SYNC_CONFIG_COMMAND)

    def configure_plugin(self):
        self.sync_ui_config()
        if self.is_agent_enabled_in_config():
            self.enable_agent()
        # Automatic disable was turned off because we still need
        # xray-user-agent to work in background for smart advice
        # previously this caused issues when this script was triggered in upcp
        # we may revisit this in the future
        # else:
        #     self.disable_agent()

    def get_system_id(self):
        try:
            system_id = get_rhn_systemid_value('system_id').split('-')[1]
            return system_id
        except Exception as e:
            print("Warning: Cannot get system id. It looks like your system is not registered.")
            return

    def reset_ui_config(self):
        if not is_cl_solo_edition(skip_jwt_check=True):
            self.exec_command(CLOUDLINUX_CONFIG_COMMAND)
        self.exec_command(DYNAMICUI_SYNC_CONFIG_COMMAND)

    def remove_file(self, filename):
        try:
            os.remove(filename)
        except OSError:
            pass

    def is_agent_running(self):
        """
        Check if user agent running
        :return: Boolean
        """
        try:
            system_id = self.get_system_id()
            result = json.loads(self.exec_command("{} {} --system_id {}"
                                                  .format(XRAY_MANAGER_UTILITY, "user-agent-status", system_id))[0])
            return result["status"] == "enabled"
        except Exception as e:
            print('Cannot get agent status. {}'.format(e))
            return False

    def check_and_repair_plugin(self):
        """
        Check if there is misconfiguration between UiConfig and agent service and reconfigure plugin
        :return: None
        """
        if self.is_agent_enabled_in_config() and not self.is_agent_running():
            self.configure_plugin()

    def copy_file_or_dir(self, src, dst):
        """
        Copy file or directory to specified location
        """
        try:
            if os.path.isfile(src):
                self.remove_file_or_dir(dst)
                shutil.copy(src, dst)
            elif os.path.isdir(src):
                self.remove_file_or_dir(dst)
                shutil.copytree(src, dst)
        except Exception as e:
            print("An error occurred while copying: {}".format(e))

    def remove_file_or_dir(self, path):
        """
        Remove file or directory
        """
        try:
            if os.path.isfile(path):
                os.remove(path)
            elif os.path.isdir(path):
                shutil.rmtree(path)
        except Exception as e:
            print("An error occurred while copying: {}".format(e))

    def generate_translate_templates(self):
        """
        Prepare translate templates using english as a base.
        """
        source_path = f"{SOURCE_PATH_USER}i18n/en-en.json"
        template_path = f"{CLOUDLINUX_TRANSLATIONS_DIR}xray-user-ui.json"
        self.copy_file_or_dir(source_path, template_path)


class CpanelPluginInstaller(Base):
    def __init__(self):
        self.ROOT_CPANEL_DIR = "/usr/local/cpanel/whostmgr/docroot/"
        self.CPANEL_THEMES_BASE_DIR = "/usr/local/cpanel/base/frontend/"
        self.template_src = SOURCE_PATH_BASE + "plugins/cpanel/xray.live.pl"
        # template_dst should be format with theme name and placed for each theme
        self.template_dst = self.CPANEL_THEMES_BASE_DIR + "{}/lveversion/xray.live.pl"
        self.plugin_tar = SOURCE_PATH_BASE + "plugins/cpanel/cpanel-xray-plugin.tar.bz2"
        self.plugin_installer = "/usr/local/cpanel/scripts/install_plugin"
        self.plugin_uninstaller = "/usr/local/cpanel/scripts/uninstall_plugin"
        self.xray_feature_file = "/usr/local/cpanel/whostmgr/addonfeatures/lvexray"
        self.install_config = SOURCE_PATH_BASE + "plugins/cpanel/plugin/install.json"
        self.destination_admin = "/usr/local/cpanel/whostmgr/docroot/3rdparty/cloudlinux/assets/xray-admin"
        self.destination_user = "/usr/local/cpanel/whostmgr/docroot/3rdparty/cloudlinux/assets/xray-user"

    def cpanel_fix_feature_manager(self):
        if os.path.exists(self.xray_feature_file) and os.path.exists(self.install_config):
            with open(self.install_config) as install_config:
                feature_config = json.load(install_config)
                feature = feature_config[0]  # We have only one item
                try:
                    feature_name_fixed = re.search("\$LANG{'(.*)'}", feature['name']).group(1)
                except AttributeError:
                    feature_name_fixed = ''
                feature_file = open(self.xray_feature_file, 'w')
                feature_file.write(feature['feature'] + ':' + feature_name_fixed)
                feature_file.close()

    def install_plugin(self):
        self.copy_file_or_dir(SOURCE_PATH_ADMIN, self.destination_admin)
        self.copy_file_or_dir(SOURCE_PATH_USER, self.destination_user)
        for theme in self.get_theme_list():
            self.copy_file_or_dir(self.template_src, self.template_dst.format(theme))
            self.exec_command("{} {}  --theme {}".format(self.plugin_installer, self.plugin_tar, theme))
        self.cpanel_fix_feature_manager()

    def uninstall_plugin(self):
        self.remove_file_or_dir(self.destination_admin)
        self.remove_file_or_dir(self.destination_user)
        for theme in self.get_theme_list():
            self.remove_file_or_dir(self.template_dst.format(theme))
            self.exec_command("{} {}  --theme {}".format(self.plugin_uninstaller, self.plugin_tar, theme))

    def get_theme_list(self):
        if os.path.isdir(self.CPANEL_THEMES_BASE_DIR):
            return next(os.walk(self.CPANEL_THEMES_BASE_DIR), (None, None, []))[1]


class PleskPluginInstaller(Base):
    def __init__(self):
        self.ROOT_PLESK_DIR = "/usr/local/psa/admin/"
        self.controller_src = SOURCE_PATH_BASE + "plugins/plesk/XrayController.php"
        self.controller_dst = self.ROOT_PLESK_DIR + "plib/modules/plesk-lvemanager/controllers/XrayController.php"
        self.send_request_controller_src = SOURCE_PATH_BASE + "plugins/plesk/XraySendRequestController.php"
        self.send_request_controller_dst = self.ROOT_PLESK_DIR + "plib/modules/plesk-lvemanager/controllers/XraySendRequestController.php"
        self.destination_admin = "/usr/local/psa/admin/htdocs/modules/plesk-lvemanager/xray-admin"
        self.destination_user = "/usr/local/psa/admin/htdocs/modules/plesk-lvemanager/xray-user"
        self.icon_src = SOURCE_PATH_BASE + "plugins/plesk/xray.svg"
        self.icon_dst = self.ROOT_PLESK_DIR + "htdocs/modules/plesk-lvemanager/images/xray.svg"
        self.views_dir = self.ROOT_PLESK_DIR + "plib/modules/plesk-lvemanager/views/scripts/xray/"
        self.template_src = SOURCE_PATH_BASE + "plugins/plesk/index.phtml"
        self.template_dst = self.ROOT_PLESK_DIR + "plib/modules/plesk-lvemanager/views/scripts/xray/index.phtml"

    def install_plugin(self):
        self.copy_file_or_dir(SOURCE_PATH_ADMIN, self.destination_admin)
        self.copy_file_or_dir(SOURCE_PATH_USER, self.destination_user)
        self.copy_file_or_dir(self.controller_src, self.controller_dst)
        self.copy_file_or_dir(self.send_request_controller_src, self.send_request_controller_dst)
        self.copy_file_or_dir(self.icon_src, self.icon_dst)
        if not os.path.isdir(self.views_dir):
            os.mkdir(self.views_dir)
        self.copy_file_or_dir(self.template_src, self.template_dst)

    def uninstall_plugin(self):
        self.remove_file_or_dir(self.destination_admin)
        self.remove_file_or_dir(self.destination_user)
        self.remove_file_or_dir(self.controller_dst)
        self.remove_file_or_dir(self.send_request_controller_dst)
        self.remove_file_or_dir(self.icon_dst)
        self.remove_file_or_dir(self.views_dir)


class DirectAdminPluginInstaller(Base):
    def __init__(self):
        # Plugin files
        self.source_user_plugin = SOURCE_PATH_BASE + "plugins/directadmin/xray/"
        self.destination_user_plugin = "/usr/local/directadmin/plugins/xray/"
        self.source_index_file = SOURCE_PATH_BASE + "plugins/directadmin/xrayIndex.php"
        self.destination_index_file = "/usr/local/directadmin/plugins/lvemanager_spa/app/View/Spa/index/xrayIndex.php"
        self.plugin_conf_file = self.destination_user_plugin + "/plugin.conf"
        self.destination_admin_spa = "/usr/local/directadmin/plugins/lvemanager_spa/images/assets/xray-admin"
        self.destination_user_spa = "/usr/local/directadmin/plugins/xray/images/xray-user"

    def install_plugin(self):
        self.copy_file_or_dir(SOURCE_PATH_ADMIN, self.destination_admin_spa)
        self.copy_file_or_dir(self.source_user_plugin, self.destination_user_plugin)
        self.copy_file_or_dir(self.source_index_file, self.destination_index_file)
        self.copy_file_or_dir(SOURCE_PATH_USER, self.destination_user_spa)
        self.exec_command("chown -R diradmin:diradmin " + self.destination_user_plugin)
        self.exec_command("chown -R diradmin:diradmin " + self.destination_admin_spa)
        self.exec_command("chmod -R 755 " + self.destination_user_plugin)
        self.exec_command("chmod -R 644 " + self.plugin_conf_file)

    def uninstall_plugin(self):
        self.remove_file_or_dir(self.destination_user_plugin)
        self.remove_file_or_dir(self.destination_admin_spa)


class PanelIntegrationPluginInstaller(Base):
    def __init__(self):
        self.destination_admin_py_plugin = "/usr/share/l.v.e-manager/commons/spa-resources/static/xray-admin"
        self.destination_user_py_plugin = "/usr/share/l.v.e-manager/commons/spa-resources/static/xray-user"

    def get_panel_base_path(self):
        try:
            parser = configparser.ConfigParser(interpolation=None, strict=False)
            parser.read(PANEL_INTEGRATION_CONFIG)
            base_path = parser.get("lvemanager_config", "base_path")
            return base_path
        except Exception as e:
            print('Cannot copy files for no panel version. {}'.format(e))
            sys.exit(1)

    def install_plugin(self):
        base_path = self.get_panel_base_path().rstrip('/')
        self.copy_file_or_dir(SOURCE_PATH_ADMIN, self.destination_admin_py_plugin)
        self.copy_file_or_dir(SOURCE_PATH_USER, self.destination_user_py_plugin)
        self.copy_file_or_dir(SOURCE_PATH_ADMIN, base_path + '/assets/xray-admin')
        self.copy_file_or_dir(SOURCE_PATH_USER, base_path + '/assets/xray-user')

    def uninstall_plugin(self):
        base_path = self.get_panel_base_path().rstrip('/')
        self.remove_file_or_dir(self.destination_admin_py_plugin)
        self.remove_file_or_dir(self.destination_user_py_plugin)
        self.remove_file_or_dir(base_path + '/assets/xray-admin')
        self.remove_file_or_dir(base_path + '/assets/xray-user')


class Main:
    def __init__(self):
        pass

    def make_parser(self):
        parser = argparse.ArgumentParser(description="Script to install|uninstall Xray App for user")
        parser.add_argument("--install", "-i", action="store_true",
                            help="Install Xray App")
        parser.add_argument("--uninstall", "-u", action="store_true",
                            help="Uninstall Xray App")
        parser.add_argument("--check", "-c", action="store_true",
                            help="Check and repair plugin")
        return parser

    def run(self):
        parser = self.make_parser()
        args = parser.parse_args()
        installer_class = None

        if detect.is_cpanel():
            # Cpanel
            installer = CpanelPluginInstaller()
        elif detect.is_da():
            # DirectAdmin
            installer = DirectAdminPluginInstaller()
        elif detect.is_plesk():
            # Plesk
            installer = PleskPluginInstaller()
        elif os.path.isfile(PANEL_INTEGRATION_CONFIG):
             # Custom panel with integration.ini
             installer = PanelIntegrationPluginInstaller()
        else:
            print("X-Ray plugin cannot be installed on your environment")
            sys.exit(0)

        if args.install:
            installer.install_plugin()
            installer.generate_translate_templates()
            installer.configure_plugin()
            installer.add_cron(CHECK_PLUGIN_CRON["name"],
                               CHECK_PLUGIN_CRON["schedule"],
                               CHECK_PLUGIN_CRON["executor"],
                               CHECK_PLUGIN_CRON["command"])
        elif args.uninstall:
            installer.remove_cron(CHECK_PLUGIN_CRON["name"])
            installer.uninstall_plugin()
            installer.reset_ui_config()
        elif args.check:
            installer.check_and_repair_plugin()
        else:
            parser.print_help()


if __name__ == "__main__":
    main = Main()
    main.run()

Zerion Mini Shell 1.0