#!/usr/bin/python3
# -*- coding: utf-8 -*-

import os
import sys
import pwd

import logging
import configparser
import traceback
from gi.repository import GLib
import dbus
import dbus.service
import dbus.mainloop.glib

import requests
import platform
import json
import socket
import random
import shutil
import subprocess
from urllib import parse
import uuid
import time

from datetime import datetime
import base64

import gettext

gettext.bindtextdomain('kim-domain', '/usr/share/kim-client/locale')
gettext.textdomain('kim-domain')
_ = gettext.gettext

logger = logging.getLogger()

SUCCESS = 0
NETWORK_ERROR = 100
REQUEST_ERROR = 101
JOIN_ERROR = 200
UNENROLL_ERROR = 300
KCM_ERROR = 400

USER_PWD_EXPIRE = 201

kim_dbus = None
KIM_RPC_PORT = 31443
KCM_JOIN_PORT = 30234
KCM_RPC_PORT = 30234

JOIN_ERR_UNKNOW = 100101                #未知错误
JOIN_ERR_NOTJOIN = 100102               #未加域
JOIN_ERR_CONFIG = 100103                #配置错误
JOIN_ERR_TIME_SKEW = 100104             #客户端与服务端时间相差过大
JOIN_ERR_RUN_NOPERM = 100105            #脚本需要root权限
JOIN_ERR_CLIENT_ERR = 100106            #客户端未安装或服务异常
JOIN_ERR_PARAM_ERR = 100107             #脚本参数错误
JOIN_ERR_ALREADY_JOIN = 100108          #已加域

JOIN_ERR_NET_URL = 100201               #访问地址异常
JOIN_ERR_NET_TIMEOUT = 100202           #连接服务端超时
JOIN_ERR_NET_CONN = 100203              #连接网络异常
JOIN_ERR_NET_REQUEST = 100204           #请求错误
JOIN_ERR_NET_STATUS = 100205            #http请求状态码异常

JOIN_ERR_KCM = 100301                   #KCM调用错误
JOIN_ERR_KCM_SSH_KEY = 100302           #获取kcm ssh公钥失败

HTTP_SCHEMA = 'https'

kim_config_path = "/etc/kim/default.conf"

kim_nss_service = ('su', 'lightdm', 'ukui-greeter', 'login', 'sshd', 'id', 'getent')

# Used by standard_logging_setup() for console message
LOGGING_FORMAT_STANDARD_CONSOLE = '%(name)-12s: %(levelname)-8s %(message)s'
# Used by standard_logging_setup() for file message
LOGGING_FORMAT_STANDARD_FILE = '%(asctime)s %(levelname)s %(message)s'

auth_type = None
remote_server = None
new_hostname = None
auth_token = None

requests.packages.urllib3.disable_warnings()

class InstallError(Exception):

    def __init__(self, msg = '', rval = JOIN_ERR_UNKNOW):
        if msg is None:
            msg = _('undefined error') #'未定义错误'
        super(InstallError, self).__init__(msg)
        self.rval = rval

    @property
    def msg(self):
        return str(self)

def cmd_run(args, skip_output=False):
    p_in = None
    p_out = None
    p_err = None
    p_in = subprocess.PIPE
    if skip_output:
        p_out = p_err = open(os.devnull, 'w')
    else:
        p_out = subprocess.PIPE
        p_err = subprocess.PIPE
    try:
        # pylint: disable=subprocess-popen-preexec-fn
        p = subprocess.Popen(args, stdin=p_in, stdout=p_out, stderr=p_err)
        stdout, stderr = p.communicate(timeout=5)
    except KeyboardInterrupt as error_message:
        logger.debug('Process interrupted : %s' % error_message)
        p.wait()
        raise
    except Exception as error_message:
        logger.debug('Process execution failed : %s'%error_message)
        raise
    finally:
        if skip_output:
            p_out.close()
    logger.info("%s %s %s"%(p.returncode, stdout.decode(), stderr.decode()))
    return p.returncode, stdout.decode(), stderr.decode()

def simple_cmd(cmd):
    result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
    return result.stdout

def standard_logging_setup(filename=None, verbose=False, debug=False,
                           filemode='w', console_format=None):
    if console_format is None:
        console_format = LOGGING_FORMAT_STANDARD_CONSOLE

    root_logger = logging.getLogger()
    root_logger.setLevel(logging.DEBUG)

    # File output is always logged at debug level
    if filename is not None:
        umask = os.umask(0o133)
        try:
            file_handler = logging.FileHandler(filename, mode=filemode)
        finally:
            os.umask(umask)
        file_handler.setLevel(logging.DEBUG)
        file_handler.setFormatter(logging.Formatter(LOGGING_FORMAT_STANDARD_FILE))
        root_logger.addHandler(file_handler)

    level = logging.ERROR
    if verbose:
        level = logging.INFO
    if debug:
        level = logging.DEBUG

    console_handler = logging.StreamHandler()
    console_handler.setLevel(level)
    console_handler.setFormatter(logging.Formatter(console_format))
    root_logger.addHandler(console_handler)

def extract_ip():
    st = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        st.connect(('10.255.255.255', 1))
        IP = st.getsockname()[0]
    except Exception:
        IP = '127.0.0.1'
    finally:
        st.close()
    return IP

# 获取登录用户是否为域用户
def have_domain_user_login():
    # 获取所有登录tty的用户
    out1 = simple_cmd("who | grep tty | cut -d' ' -f1")
    # 获取本地可登录用户列表
    out2  = simple_cmd("cat /etc/passwd | grep -v nologin | cut -d':' -f1")
    logger.info('logined users [%s].' % out1)
    all_user = out1.split() if out1 else []
    local_user = [one.strip() for one in out2.split()]
    for user in all_user:
        if user.strip() not in local_user:
            return True
    return False


### 获取终端序列号sn
def get_device_serialno():
    run_args = ['/usr/sbin/dmidecode', '-s', 'system-serial-number']
    try:
        ret, out, err = cmd_run(run_args)
    except Exception:
        return ''
    else:
        return out.rstrip('\n')

def get_devsn():
    try:
        devsn = get_devsn_file()
    except Exception as e:
        devsn = get_devsn_dbus()
        if get_domain_status() == 0:
            set_devsn_file(devsn)
    return devsn

kcmdevsnfile = '/etc/kcmdevsn.txt'

def set_devsn_file(devsn):
    with open(kcmdevsnfile, 'w') as f:
        f.write(devsn)
    run_args = ['/usr/bin/chattr', '+i', kcmdevsnfile]

def get_devsn_file():
    with open(kcmdevsnfile, 'r') as f:
        devsn = f.readline().rstrip('\n')
    return devsn

def get_devsn_cli():
    run_args = ['/usr/bin/kylin_gen_register']
    try:
        ret, out, err = cmd_run(run_args)
    except Exception:
        return ''
    else:
        return out.rstrip('\n')


def get_devsn_dbus():
    devsn = 'undefined'
    system_bus = dbus.SystemBus()
    try:
        proxy = system_bus.get_object('org.freedesktop.activation',
                       '/org/freedesktop/activation')
        act = dbus.Interface(proxy,dbus_interface="org.freedesktop.activation.interface")
        devsn, ret = act.register_number(timeout=5)
        if ret != 0:
            logger.error('Dbus get register number failed code: %d' % ret)
    except Exception as e:
        logger.error('Dbus get register number failed: %s' % str(e))
    return devsn

#获取系统版本
def get_os_version():
    os_version = 'Unknow'
    with open('/etc/os-release', 'r') as orl:
        for line in orl:
            if line.startswith('VERSION'):
                os_version=line.split('=')[1].rstrip('\n').strip('"')
                break
    return os_version

#获取运行环境PC、Server、Cloud
def get_run_env():
    if os.path.exists('/usr/bin/dpkg'):
        return 'PC'
    elif os.path.exists('/usr/bin/rpm'):
        return 'Server'
    else:
        return 'Cloud'

#获取客户端版本
def get_client_version():
    client_version = ''
    run_env = get_run_env()
    if run_env == 'PC':
        cmd = 'dpkg -s hedron-client'
    elif run_env == 'Server':
        cmd = 'rpm -qi kim-client'
    else:
        cmd = 'dpkg -s kim-client'
    with os.popen(cmd) as cv:
        for line in cv:
            if line.startswith('Version'):
                client_version = line.split(':')[1].rstrip('\n').strip(' ')
                break
    return client_version

def get_mac_address():
    mac_num = hex(uuid.getnode()).replace('0x', '')
    mac = ':'.join(mac_num[i: i + 2] for i in range(0, 11, 2))
    return mac

def check_if_keyring_support():
    run_args = ['/usr/bin/keyctl', 'get_persistent', '@u']
    try:
        ret, out, err = cmd_run(run_args)
    except Exception:
        return False
    else:
        return ret == 0

### 获取默认的服务器配置
def get_server_info():
    global KIM_RPC_PORT
    global KCM_JOIN_PORT
    global KCM_RPC_PORT
    config = configparser.ConfigParser()
    config.read('/etc/.kimserver.conf', encoding='utf-8')
    server = config.get('default', 'server')
    port = config.getint('default', 'port')
    if KIM_RPC_PORT != port:
        KIM_RPC_PORT = port
    if KCM_JOIN_PORT != port:
        KCM_JOIN_PORT = port
        KCM_RPC_PORT = KCM_JOIN_PORT
    return server, port

def get_kcm_server(sect='kcm'):
    config = configparser.ConfigParser()
    config.read('/etc/kim/default.conf', encoding='utf-8')
    try:
        server = config.get(sect, 'server')
        port = config.getint(sect, 'port')
    except Exception:
        raise InstallError('Not enrolled.', rval=JOIN_ERR_NOTJOIN)
    return server, port

def update_server_info(server, port=None):
    config = configparser.ConfigParser()
    config.read('/etc/.kimserver.conf', encoding='utf-8')
    if not config.has_section('default'):
        config.add_section('default')
    config.set('default', 'server', server)
    if port is None:
        port = KIM_RPC_PORT
    config.set('default', 'port', str(port))
    with open('/etc/.kimserver.conf', 'w') as f:
        config.write(f)

def enable_kimbackend():
    cmd_run(['/usr/bin/systemctl', 'restart', 'kimbackend.service'])
    cmd_run(['/usr/bin/systemctl', 'enable', 'kimbackend.service'])

def disable_kimbackend():
    cmd_run(['/usr/bin/systemctl', 'disable', 'kimbackend.service'])
    cmd_run(['/usr/bin/systemctl', 'stop', 'kimbackend.service'])

def kim_access_control(enable):
    pol_link_dist = '/var/lib/polkit-1/localauthority/40-domain.d'
    pol_file_dir = '/usr/share/kim-daemon/pkla'
    sudo_link_dist = '/usr/lib/%s-linux-gnu/libsss_sudo.so' % platform.machine()
    sudo_file_path = '/usr/lib/libsudo-kim.so'
    sudo_bak_dist = '/var/lib/kim/bak/libsss_sudo.so'

    netconf = '/lib/NetworkManager/conf.d/10-polkit-false.conf'
    netconf_bak = '/var/lib/kim/bak/10-polkit-false.conf'
    if enable:
        if not os.path.islink(pol_link_dist):
            os.symlink(pol_file_dir, pol_link_dist)
        #if not os.path.islink(sudo_link_dist):
        #    os.symlink(sudo_file_path, sudo_link_dist)
        if os.path.exists(sudo_link_dist):
            if not os.path.islink(sudo_link_dist):
                shutil.move(sudo_link_dist, sudo_bak_dist)
                os.symlink(sudo_file_path, sudo_link_dist)
        else:
            os.symlink(sudo_file_path, sudo_link_dist)
        if os.path.exists(netconf):
            shutil.move(netconf, netconf_bak)
    else:
        if os.path.exists(pol_link_dist):
            os.unlink(pol_link_dist)
        if os.path.islink(sudo_link_dist):
            os.unlink(sudo_link_dist)
        if os.path.exists(sudo_bak_dist) and not os.path.exists(sudo_link_dist):
            shutil.move(sudo_bak_dist, sudo_link_dist)
        if os.path.exists(netconf_bak):
            shutil.move(netconf_bak, netconf)

def kim_configure(server, port, provider='kim', nossl = False):
    config = configparser.ConfigParser()
    config.add_section('global')
    config.set('global', 'provider', provider)
    config.set('global', 'cachetime', '900')
    config.set('global', 'nss', ','.join(kim_nss_service))
    config.set('global', 'autohome', 'true')
    config.add_section(provider)
    config.set(provider, 'server', server)
    if port == 0:
        port = KCM_JOIN_PORT
    config.set(provider, 'port', str(port))
    config.set(provider, 'nossl', str(nossl))
    with open(kim_config_path, 'w') as f:
        config.write(f)
    kim_config_krb5()
    #kim_pam_enable()
    #kim_nss_insert()
    #kim_access_control(True)
    enable_kimbackend()

def kim_unconfigure():
    #kim_access_control(False)
    #kim_nss_remove()
    #kim_pam_disable()
    disable_kimbackend()

def kim_config_krb5():
    config = configparser.RawConfigParser()
    config.add_section('libdefaults')
    #config.set('libdefaults', 'default_realm', None)
    config.set('libdefaults', 'dns_lookup_realm', 'false')
    config.set('libdefaults', 'dns_lookup_kdc', 'true')
    config.set('libdefaults', 'rdns', 'false')
    config.set('libdefaults', 'dns_canonicalize_hostname', 'false')
    config.set('libdefaults', 'ticket_lifetime', '24h')
    config.set('libdefaults', 'forwardable', 'true')
    config.set('libdefaults', 'udp_preference_limit', '0')
    if check_if_keyring_support():
        config.set('libdefaults', 'default_ccache_name', 'KEYRING:persistent:%{uid}')
    with open('/etc/krb5.conf', 'w') as f:
        config.write(f)



FIREFOX_PREFERENCES_FILENAME = "all-kimsso.js"
FIREFOX_PREFERENCES_REL_PATH = "browser/defaults/preferences"

FIREFOX_ESR_PATH = "/usr/lib/firefox-esr"


def configure_firefox(domain, firefox_dir = None):
    try:
        logger.debug("Setting up Firefox configuration.")

        preferences_dir = None

        # Check user specified location of firefox install directory
        if firefox_dir is not None:
            pref_path = os.path.join(firefox_dir,
                                     FIREFOX_PREFERENCES_REL_PATH)
            if os.path.isdir(pref_path):
                preferences_dir = pref_path
            else:
                logger.error("Directory '%s' does not exists.", pref_path)
        else:
            # test if firefox is installed
            if os.path.isdir(FIREFOX_ESR_PATH):
                pref_path = os.path.join(FIREFOX_ESR_PATH, FIREFOX_PREFERENCES_REL_PATH)
                if os.path.isdir(pref_path):
                    preferences_dir = pref_path

            else:
                logger.error(
                    "Firefox configuration skipped (Firefox not found).")
                return

        # setting up firefox
        if preferences_dir is not None:

            # user could specify relative path, we need to store absolute
            preferences_dir = os.path.abspath(preferences_dir)
            logger.debug(
                "Firefox preferences directory found '%s'.", preferences_dir)
            preferences_fname = os.path.join(
                preferences_dir, FIREFOX_PREFERENCES_FILENAME)
            logger.debug(
                "Firefox trusted uris will be set as '.%s' domain.", domain)
            logger.debug(
                "Firefox configuration will be stored in '%s' file.",
                preferences_fname)

            try:
                with open(preferences_fname, 'w') as f:
                    f.write('\n/* Kerberos SSO configuration */\n')
                    f.write('\n/* These are the defaults */\n')
                    f.write('pref("network.negotiate-auth.gsslib", "");\n')
                    f.write('pref("network.negotiate-auth.trusted-uris", ".%s");\n' % domain)
                    f.write('pref("network.negotiate-auth.using-native-gsslib", true);\n')
                    f.write('pref("network.negotiate-auth.allow-proxies", true);\n')
                logger.info("Firefox sucessfully configured.")
            except Exception as e:
                logger.debug(
                    "An error occured during creating preferences file: %s.",
                    e)
                logger.error("Firefox configuration failed.")
        else:
            logger.debug("Firefox preferences directory not found.")
            logger.error("Firefox configuration failed.")

    except Exception as e:
        logger.debug("%s", str(e))
        logger.error("Firefox configuration failed.")

CHROMIUM_PREFERENCES_FILENAME = "kimsso.json"
CHROMIUM_PREFERENCES_REL_PATH = "policies/managed"

CHROMIUM_PATH = "/etc/chromium-browser"

def configure_chromium(domain, chromium_dir=None):
    try:
        logger.debug("Setting up Chrome configuration.")
        preferences_dir = None
        if chromium_dir is not None:
            pref_path = os.path.join(chromium_dir, CHROMIUM_PREFERENCES_REL_PATH)
            if os.path.isdir(pref_path):
                preferences_dir = pref_path
            else:
                logger.error("Directory '%s' does not exists.", pref_path)
        else:
            if os.path.isdir(CHROMIUM_PATH):
                pref_path = os.path.join(CHROMIUM_PATH, CHROMIUM_PREFERENCES_REL_PATH)
                if os.path.isdir(pref_path):
                    preferences_dir = pref_path
            else:
                logger.error("Chromium configuration skipped (Chromium not found).")

        if preferences_dir is not None:
            preferences_dir = os.path.abspath(preferences_dir)
            logger.debug(
                "Chromium preferences directory found '%s'.", preferences_dir)
            preferences_fname = os.path.join(
                preferences_dir, CHROMIUM_PREFERENCES_FILENAME)
            logger.debug(
                "Chromium trusted uris will be set as '.%s' domain.", domain)
            logger.debug(
                "Chromium configuration will be stored in '%s' file.", preferences_fname)

            try:
                with open(preferences_fname, 'w') as f:
                    f.write('{\n')
                    f.write('  "AuthServerWhitelist":  "*.%s",\n' % domain)
                    f.write('  "AuthServerAllowlist": "*.%s",\n' % domain)
                    f.write('  "AuthNegotiateDelegateAllowlist": "*.%s"\n' % domain)
                    f.write('}\n')
                logger.info("Chromium sucessfully configured.")
            except Exception as e:
                logger.debug(
                    "An error occured during creating preferences file: %s.",
                    e)
                logger.error("Chromium configuration failed.")
    except Exception as e:
        logger.debug("%s", str(e))
        logger.error("chrome configuration failed.")

def kim_browser_configure(domain):
    configure_chromium(domain)
    configure_firefox(domain)
    configure_chromium(domain, '/etc/opt/chromium')
    qax_path = '/etc/chromium'
    if not os.path.exists(qax_path):
        pref_path = os.path.join(qax_path, CHROMIUM_PREFERENCES_REL_PATH)
        os.makedirs(pref_path)
    configure_chromium(domain, qax_path)

KRB_CONF_DIR = "/var/lib/kim/krbconf"

def kim_add_krbconf(domain, server):
    realm = domain.upper()
    kdcfile = os.path.join(KRB_CONF_DIR, 'kdcinfo.%s' % realm)
    kpassfile = os.path.join(KRB_CONF_DIR, 'kpasswdinfo.%s' % realm)

    try:
        with open(kdcfile, 'w') as f:
            f.write('%s:30288"\n' % server)
        logger.info("kdcconf sucessfully configured.")

    except Exception as e:
        logger.error("kdc configuration failed.")

def kim_krb5_setall(server):
    domain = None
    if '.' in server:
        short_name, _sep, domain = server.partition('.')
    if domain is None:
        logger.error("need fqdn servername")
        return
    kim_add_krbconf(domain, server)
    kim_browser_configure(domain)

def kim_sethostname(hostname, domain = None):
    if '.' in hostname:
        short_name, _sep, hostdomain = hostname.partition('.')
        if domain is None:
            domain = hostdomain
    else:
        short_name = hostname
        if domain is None:
            logger.warning('Invalid hostname %s.', hostname)
            #raise InstallError(_('Invalid hostname, use fqdn format.'), rval=REQUEST_ERROR) #请指定域名或者设定fqdn格式主机名
    if domain is None:
        fqdn = short_name
    else:
        fqdn = '%s.%s' % (short_name, domain)
    orig_hostname = ''
    try:
        orig_hostname = socket.gethostname()
    except Exception:
        pass
    if orig_hostname != fqdn:
        #ipautil.run([paths.BIN_HOSTNAMECTL, 'set-hostname', hostname])
        cmd_run(['/usr/bin/hostnamectl', 'set-hostname', fqdn])
        with open('/etc/hosts', 'r') as hf:
            with open('/etc/hosts.kimbak', 'w') as fw:
                modify = False
                for line in hf:
                    if line.startswith('127.0.1.1'):
                        new_line = '127.0.1.1\t%s %s\n' % (fqdn, short_name)
                        modify = True
                    else:
                        new_line = line
                    fw.write(new_line)
                if not modify:
                    fw.write('127.0.1.1\t%s %s\n' % (fqdn, short_name))
        shutil.move('/etc/hosts.kimbak', '/etc/hosts')


def kim_setmkhomedir():
    new_config = []
    edited = False
    with open('/usr/share/pam-configs/mkhomedir', 'r') as fr:
        for line in fr:
            if 'pam_mkhomedir.so' in line and 'umask=0077' not in line:
                edited = True
                new_config.append('     optional                        pam_mkhomedir.so umask=0077\n')
            else:
                new_config.append(line)
    if edited:
        with open('/usr/share/pam-configs/mkhomedir', 'w') as fw:
            for lw in new_config:
                fw.write(lw)
    try:
        cmd_run(['/usr/sbin/pam-auth-update', '--package', '--enable', 'mkhomedir'])
    except Exception as e:
        raise InstallError(_('set auto create home directtory failed.'), rval = JOIN_ERR_CONFIG)


def kim_pam_enable():
    try:
        cmd_run(['/usr/sbin/pam-auth-update', '--package', '--enable', 'kim'])
    except Exception as e:
        logger.error('Enable kim auth module failed: %s' % str(e))
        raise InstallError(_('Enable kim auth module failed.'), rval = JOIN_ERR_CONFIG)

def kim_pam_disable():
    try:
        cmd_run(['/usr/sbin/pam-auth-update', '--package', '--remove', 'kim'])
    except Exception as e:
        logger.error('Disable kim auth module failed: %s' % str(e))
        raise InstallError(_('Disable kim auth module failed.'), rval = JOIN_ERR_CONFIG)

NS_SWITCH_CONF = '/etc/nsswitch.conf'

def kim_nss_insert():
    bak_file = NS_SWITCH_CONF + '.kimbak'
    with open(NS_SWITCH_CONF, 'r') as nf:
        sudo_found = False
        with open(bak_file, 'w') as fw:
            for line in nf:
                if line.startswith('passwd:') and 'kim' not in line:
                    new_line = '%s %s\n' % (line.rstrip('\n').rstrip(' '), 'kim')
                elif line.startswith('group:') and 'kim' not in line:
                    new_line = '%s %s\n' % (line.rstrip('\n').rstrip(' '), 'kim')
                elif line.startswith('sudoers:'):
                    new_line = 'sudoers:        files sss'
                    sudo_found = True
                else:
                    new_line = line
                fw.write(new_line)
            if not sudo_found:
                fw.write('sudoers:        files sss\n')
    shutil.move(bak_file, NS_SWITCH_CONF)

def kim_nss_remove():
    bak_file = NS_SWITCH_CONF + '.kimbak1'
    with open(NS_SWITCH_CONF, 'r') as nf:
        with open(bak_file, 'w') as fw:
            for line in nf:
                if line.startswith('passwd:'):
                    new_line = line.replace('kim', '')
                elif line.startswith('group:'):
                    new_line = line.replace('kim', '')
                elif line.startswith('sudoers:'):
                    new_line = ''
                else:
                    new_line = line
                fw.write(new_line)
    shutil.move(bak_file, NS_SWITCH_CONF)

### 获取当前管控状态，1表示已加域，0表示未加域
def get_domain_status():
    status = os.path.exists(kim_config_path)
    return 1 if status else 0

### 是否存在电池，用于判断是否为笔记本
def get_battery_status():
    system_bus = dbus.SystemBus()
    try:
        proxy = system_bus.get_object('org.freedesktop.UPower',
                       '/org/freedesktop/UPower')
        upower = dbus.Interface(proxy,dbus_interface="org.freedesktop.UPower")
        devices = upower.EnumerateDevices()
        for dvc in devices:
            if dvc.startswith('/org/freedesktop/UPower/devices/battery'):
                return True
    except Exception as e:
        pass
    return False

### 判断设备类型为笔记本还是台式机
def get_device_type():
    run_args = ['/usr/sbin/dmidecode', '-s', 'chassis-type']
    notebook_type = ['Notebook', 'Laptop', 'Portable']
    chassis_type = None
    try:
        _ret, out, _err = cmd_run(run_args)
    except Exception:
        out = ''
    else:
        chassis_type = out.rstrip('\n')
    if chassis_type and chassis_type in notebook_type:
        if get_battery_status():
            return 'Notebook'
    return 'Desktop'

def kim_extra_config(server):
    url = "https://%s:%d/aptserver/icbc_config.json" % (server, KCM_RPC_PORT)
    dest_file = '/usr/lib/biometric-authentication/drivers/extra/icbc/configs/icbc_config.json'
    shutil.copy(dest_file, dest_file + '.kimbak')
    try:
        resp = requests.get(url, verify=False, timeout=8)
        if resp.status_code != 200:
            raise InstallError(_('Failed to get config'), rval = REQUEST_ERROR)
        with open(dest_file, 'w') as f:
            f.write(resp.text)
    except InstallError:
        raise
    except Exception as e:
        raise InstallError(_('Failed to get config'), rval = REQUEST_ERROR)


### 退出域，通过dbus调用之前的接口
def unrolling_host(rollback = False):
    #hostname = socket.getfqdn()
    if rollback:
        ret = kcm_force_uninstall()
    else:
        #ret, msg = uninstall_kcm()
        ret, msg = kcm_unrolled_v2()
    if ret != 0 and not rollback:
        logger.error('uninstall failed:%s' % msg)
        raise InstallError(msg, rval = ret)
    if ret != 0:
        logger.warning('rollback failed')
    if os.path.exists(kim_config_path):
        kim_unconfigure()
        os.remove(kim_config_path)
    if os.path.exists('/var/lib/kim/data/kimcd.db'):
        os.remove('/var/lib/kim/data/kimcd.db')
    if os.path.exists('/var/lib/kim/private/pri.db'):
        os.remove('/var/lib/kim/private/pri.db')


def get_err_from_code(code):
    msg = '未知错误，请查看日志'
    if code == 300000:
        msg = '请求成功'
    elif code == 300001:
        msg = '关联用户不存在'
    elif code == 300002:
        msg = 'sn不存在'
    elif code == 300003:
        msg = 'sn关联主机失败'
    elif code == 300004:
        msg = '主机名已存在或无效的主机名'
    elif code == 300005:
        msg = '用户不存在'
    elif code == 300007:
        msg = '激活注册码不存在'
    elif code == 300008:
        msg = '激活注册码已存在'
    elif code == 300009:
        msg = '添加主机记录失败'
    elif code == 300010:
        msg = '主机关联组织失败'
    elif code == 300011:
        msg = '添加访问规则失败'
    elif code == 300012:
        msg = '用户不在组织内'
    elif code == 300013:
        msg = '发布策略错误'
    elif code == 300014:
        msg = '参数错误，密码编码无效'
    elif code == 300400:
        msg = '用户认证失败，请检查用户名和密码'
    elif code == 300401:
        msg = '请求未认证，请重新认证'
    elif code == 300403:
        msg = '用户权限不足'
    elif code == 300500:
        msg = '服务器错误'
    return msg

def change_system_time(dt):
    cli_dt = dt.strftime('%Y-%m-%d %H:%M:%S')
    cmd_run(['/usr/bin/timedatectl', 'set-ntp', 'false'])
    ret, msg, emsg = cmd_run(['/usr/bin/timedatectl', 'set-time', cli_dt])
    if ret != 0:
        logger.warning('change system time error:%s' % emsg)
    cmd_run(['/usr/bin/timedatectl', 'set-ntp', 'true'])

def http_check_server_info(server):
    global auth_type
    global remote_server
    remote_server = server
    url = '%s://%s:%d/kim/checkServer' % (HTTP_SCHEMA, server, KCM_JOIN_PORT)
    kim_dbus.joinProgress(3)
    resp_data = send_kcm_request(url, timeout=8, method='Get')
    server_time = resp_data['nowtime']
    dt_server = datetime.fromisoformat(server_time)
    #datetime.strptime(server_time,"%Y-%m-%dT%H:%M:%S%z")
    dt_now = datetime.now()
    dt_delta = dt_now.timestamp() - dt_server.timestamp()
    if(dt_delta > 60):
        logger.warning('get server time: %s' % server_time)
        change_system_time(dt_server)
        #raise InstallError(_('check server failed: The client and server time skews too large.'), rval = REQUEST_ERROR)
    auth_type = resp_data['authtype']
    remote_server = server
    #kim_sethostname(resp_hostname)


def get_hostname_by_sn(server, sn):
    url = 'https://%s:%d/kim/validateSN' % (server, KCM_JOIN_PORT)
    language = os.environ['LANGUAGE']
    headers = {
        'Accept-Language': language.replace('_', '-')
    }
    datas = {
        "sn": sn,
        "device_type": get_device_type(),
        "devsn": get_devsn()
    }
    try:
        kim_dbus.joinProgress(3)
        resp = requests.post(url=url, json=datas, headers=headers, verify=False, timeout=8)
        if resp.status_code != 200:
            raise InstallError(_('Validate sn error: server request error[%d]') % resp.status_code, rval = JOIN_ERR_NET_REQUEST)
        #resp_json = resp.json
        resp_json = json.loads(resp.text)
        print(resp_json)
        resp_ret = resp_json['ret']
        resp_msg = resp_json['msg']
        if resp_ret != 300000:
            logger.error('Validate sn error: %s.', resp_msg)
            join_msg = _('unknow error, please see the infomation in log file')
            if resp_ret == 300002:
                join_msg = _('Host authenticaion failed, please input sn to server.')
            elif resp_ret == 300001:
                join_msg = _('Host authentication failed, please bind an employee number.')
            elif resp_ret == 300008:
                join_msg = _('Host authentication failed, devsn has already exists.')
            elif resp_ret == 300500:
                join_msg = _('Host authentication failed, remote server error.')
            raise InstallError(join_msg, rval = REQUEST_ERROR)
        resp_data = resp_json['data']
        print(resp_data)
        resp_hostname = resp_data['hostname']
        kim_sethostname(resp_hostname)
    except InstallError:
        raise
    except requests.exceptions.InvalidURL:
        raise InstallError(_('invalid server url'), rval = REQUEST_ERROR) #无效的服务器地址
    except requests.exceptions.ConnectTimeout:
        raise InstallError(_('connect to server failed: timeout.'), rval = REQUEST_ERROR)
    except requests.exceptions.ReadTimeout:
        raise InstallError(_('connect to server failed: timeout.'), rval = REQUEST_ERROR)
    except requests.exceptions.ConnectionError as conn_e:
        logger.error(conn_e)
        raise InstallError(_('connect to server failed, please check your network'), rval = REQUEST_ERROR) #'连接服务器失败，请检查网络状态'
    except Exception as e:
        print('%s:%s' % (type(e), str(e)))
        raise InstallError(_('unknow error, please see the infomation in log file'), rval = REQUEST_ERROR)

def kcm_init(servername):
    
    try:
        # modify_client_conf(servername)
        config_kcm_server()
        cmd_run(['/usr/bin/systemctl', 'restart', 'hedron-client'])
        time.sleep(3)
        system_bus = dbus.SystemBus()
        proxy = system_bus.get_object('com.kylin.kydevmonit.domainhook',
                       '/com/kylin/kydevmonit/domainhook')
        kcm = dbus.Interface(proxy,dbus_interface="com.kylin.kydevmonit.domainhook")
        ret, msg = kcm.init_kcm(servername, str(KCM_RPC_PORT), timeout=10)
        if ret != 0:
            raise InstallError(_('Client configure error:%s') % msg,rval = JOIN_ERR_KCM)
    except Exception as e:
        logger.error('kcm init error %s' % str(e))
        #raise InstallError(_('unknow error, please see the infomation in log file'), rval = JOIN_ERR_UNKNOW)


def http_join_comfirm(server):
    url = '%s://%s:%d/kim/reportRegistrationStatus' % (HTTP_SCHEMA, server, KCM_JOIN_PORT)
    language = os.environ['LANGUAGE']
    headers = {
        'Accept-Language': language.replace('_', '-'),
        'Authorization': auth_token
    }
    datas = {
        #"sn": sn,
        "hostname": new_hostname,
        "devsn": get_devsn()
    }
    try:
        kim_dbus.joinProgress(80)
        resp = requests.post(url=url, json=datas, headers=headers, verify=False, timeout=8)
        if resp.status_code != 200:
            raise InstallError(_('Confirm error: server request error[%d]') % resp.status_code, rval = REQUEST_ERROR)
        #resp_json = resp.json
        resp_json = json.loads(resp.text)
        print(resp.text)
        resp_ret = resp_json['ret']
        resp_msg = resp_json['msg']
        if resp_ret != 300000:
            logger.error('Validate sn error: %s.', resp_msg)
            join_msg = _('unknow error, please see the infomation in log file')
            if resp_ret == 300003:
                join_msg = _('Enrolled failed, can not bind a user and organization')
            elif resp_ret == 300002:
                join_msg = _('Host authentication failed, please bind an employee number.')
            elif resp_ret == 300003:
                join_msg = _('Enrolled failed, host related error.')
            elif resp_ret == 300004:
                join_msg = _('Enrolled failed, hostname is already exist or invalid, please try again.')
            elif resp_ret == 300009:
                join_msg = _('Enrolled failed, add host error, please try again.')
            elif resp_ret == 300010:
                join_msg = _('Enrolled failed, add host to organization failed.')
            elif resp_ret == 300011:
                join_msg = _('Enrolled failed, bind to user failed.')
            elif resp_ret == 300500:
                join_msg = _('Enrolled failed, remote server error')
            raise InstallError(join_msg, rval = JOIN_ERROR)
        resp_data = resp_json['data']
        resp_hostname = resp_data['hostname']
        print(resp_hostname)
        #kim_sethostname(resp_hostname)
    except InstallError:
        raise
    except requests.exceptions.InvalidURL:
        raise InstallError(_('invalid server url'), rval = JOIN_ERROR) #无效的服务器地址
    except requests.exceptions.ConnectTimeout:
        raise InstallError(_('connect to server failed: timeout.'), rval = JOIN_ERROR)
    except requests.exceptions.ReadTimeout:
        raise InstallError(_('connect to server failed: timeout.'), rval = JOIN_ERROR)
    except requests.exceptions.ConnectionError as conn_e:
        logger.error(conn_e)
        raise InstallError(_('connect to server failed, please check your network'), rval = JOIN_ERROR) #'连接服务器失败，请检查网络状态'
    except Exception as e:
        print('%s:%s' % (type(e), str(e)))
        raise InstallError(_('unknow error, please see the infomation in log file'), rval = JOIN_ERROR)

def admin_confirm_join_http(server):
    url = '%s://%s:%d/kim/regconfirm' % (HTTP_SCHEMA, server, KCM_JOIN_PORT)
    datas = {
        #"sn": sn,
        "hostname": new_hostname,
        "devsn": get_devsn(),
        "macaddr": get_mac_address(),
        "osVersion": get_os_version(),
        "hardwarePlatform": platform.machine(),
        "kernel": platform.release(),
        "clientVersion": get_client_version(),
        "environment": get_run_env(),
        "ipaddr": extract_ip()
    }
    kim_dbus.joinProgress(80)
    send_kcm_request(url, datas=datas, token=auth_token)

def check_kcm_availability(server):
    kim_server = server
    #try:
    #    url = 'http://%s:%d' % (server, KCM_RPC_PORT)
    #    resp = requests.get(url=url, allow_redirects=False, verify=False, timeout=8)
    #    if resp.status_code > 300 and resp.status_code < 310:
    #        real_addr = resp.headers.get('Location')
    #        kim_server = real_addr.split('//')[-1].split(':')[0]
    #except Exception as e:
    #    pass
    system_bus = dbus.SystemBus()
    try:
        proxy = system_bus.get_object('com.kylin.kydevmonit.domainhook',
                       '/com/kylin/kydevmonit/domainhook')
        kcm = dbus.Interface(proxy,dbus_interface="com.kylin.kydevmonit.domainhook")
        ret, msg = kcm.check_kcm_availability(kim_server, str(KCM_RPC_PORT))
        if ret != SUCCESS:
            raise InstallError(msg, rval = JOIN_ERR_KCM)
    except InstallError:
        raise
    except dbus.exceptions.DBusException as dbus_e:
        logger.error(dbus_e)
        #raise InstallError(_('dbus error, please check the service status'), rval = JOIN_ERR_KCM)
    except Exception as e:
        logger.error(e)
        #raise InstallError(_('unknow error, please see the infomation in log file'), rval = JOIN_ERR_UNKNOW)

def set_lang(lang):
    os.environ['LANGUAGE'] = lang
    system_bus = dbus.SystemBus()
    try:
        proxy = system_bus.get_object('com.kylin.kydevmonit.domainhook',
                       '/com/kylin/kydevmonit/domainhook')
        kcm = dbus.Interface(proxy,dbus_interface="com.kylin.kydevmonit.domainhook")
        kcm.set_lang(lang)
    except dbus.exceptions.DBusException as dbus_e:
        logger.error(dbus_e)
    except Exception as e:
        logger.error(e)

def kcm_restore_policy():
    system_bus = dbus.SystemBus()
    try:
        proxy = system_bus.get_object('com.kylin.kydevmonit.domainhook',
                       '/com/kylin/kydevmonit/domainhook')
        kcm = dbus.Interface(proxy,dbus_interface="com.kylin.kydevmonit.domainhook")
        kcm.restore_policy()
    except dbus.exceptions.DBusException as dbus_e:
        logger.error(dbus_e)
    except Exception as e:
        logger.error(e)

def uninstall_kcm():
    system_bus = dbus.SystemBus()
    ret = 0
    msg = 'uncall'
    try:
        proxy = system_bus.get_object('com.kylin.kydevmonit.domainhook',
                       '/com/kylin/kydevmonit/domainhook')
        kcm = dbus.Interface(proxy,dbus_interface="com.kylin.kydevmonit.domainhook")
        ret, msg = kcm.uninstall()
    except dbus.exceptions.DBusException as dbus_e:
        logger.error(dbus_e)
    except Exception as e:
        logger.error(e)
    return ret, msg

def kcm_force_uninstall():
    system_bus = dbus.SystemBus()
    ret = -1
    try:
        proxy = system_bus.get_object('com.kylin.kydevmonit.domainhook',
                       '/com/kylin/kydevmonit/domainhook')
        kcm = dbus.Interface(proxy,dbus_interface="com.kylin.kydevmonit.domainhook")
        ret = kcm.force_uninstall()
    except dbus.exceptions.UnknownMethodException:
        ret = 0
    except dbus.exceptions.DBusException as dbus_e:
        logger.error(dbus_e)
    except Exception as e:
        logger.error(e)
    return ret

def device_sn_join(server):
    try:
        cmd_run(['setstatus', '-f', 'netctl', 'off', '-p'])
    except Exception as e:
        print(e)
    sn = get_device_serialno()
    try:
        kim_dbus.joinProgress(5)
        get_hostname_by_sn(server, sn)
        kim_dbus.joinProgress(20)
        check_kcm_availability(server)
        #http_join_by_sn(server, sn)
        kim_dbus.joinProgress(40)
        kim_extra_config(server)
        kim_configure(server, KCM_JOIN_PORT, provider='kcm')
        kim_setmkhomedir()
        kim_dbus.joinProgress(60)
        kcm_init(server)
        kim_dbus.joinProgress(80)
        http_join_comfirm(server, sn)
        update_server_info(server, KCM_JOIN_PORT)
        kim_dbus.joinProgress(100)
    except InstallError as ie:
        if ie.rval == JOIN_ERROR:
            try:
                unrolling_host()
            except Exception as e:
                print(e)
    except Exception as e:
        print(e)
        raise InstallError(_('unknow error, please see the infomation in log file'), rval = JOIN_ERROR)

def check_server_info(server, hostname):
    global new_hostname
    http_check_server_info(server)
    new_hostname = hostname

def user_auth_proxy(server, username, password):
    global auth_token
    if server is None:
        raise InstallError(_('can not get server, please check server first.'), rval = JOIN_ERR_CONFIG)
    if auth_type is None:
        auth_plugin = "HTTP"
    else:
        auth_plugin = auth_type
    url = '%s://%s:%d/kim/auth' % (HTTP_SCHEMA, server, KCM_JOIN_PORT)
    datas = {
        'username': str(username),
        'btoken': base64.b64encode(password.encode('utf-8')).decode('utf-8'),
        'authplugin': auth_plugin,
        'ipaddr': extract_ip()
    }
    kim_dbus.joinProgress(20)
    resp_data = send_kcm_request(url, datas=datas, timeout=8)
    auth_token = resp_data['token']

def send_kcm_request(url, datas=None, user=None, pwd=None, timeout=8, token=None, method='Post'):
    language = os.environ['LANGUAGE']
    headers = {
        'Accept-Language': language.replace('_', '-')
    }
    if token is not None:
        headers['Authorization'] = token
    try:
        print(datas)
        if method == 'Get':
            resp = requests.get(url=url, json=datas, headers=headers, verify=False,timeout=timeout)
        elif method == 'Post':
            resp = requests.post(url=url, json=datas, headers=headers, verify=False,timeout=timeout)
        elif method == 'Delete':
            resp = requests.delete(url=url, json=datas, headers=headers, verify=False,timeout=timeout)
        else:
            resp = requests.post(url=url, json=datas, headers=headers, verify=False,timeout=timeout)
        if resp.status_code != 200:
            raise InstallError(_('Request error[%d]') % resp.status_code, rval = JOIN_ERR_NET_REQUEST)
        print(resp.text)
        resp_json = json.loads(resp.text)
        #print(resp.text)
        resp_ret = resp_json['ret']
        resp_msg = resp_json['msg']
        if resp_ret != 300000:
            logger.error('Error: [%d] %s' % (resp_ret, resp_msg))
            if 'describe' in resp_json:
                msg = resp_json['describe']
            elif 'chinese' in resp_json:
                msg = resp_json['chinese']
            else:
                msg = get_err_from_code(resp_ret)
            raise InstallError(msg, rval = resp_ret)
        print('success')
        if 'data' in resp_json:
            return resp_json['data']
    except InstallError:
        raise
    except requests.exceptions.InvalidURL:
        raise InstallError(_('invalid server url'), rval = JOIN_ERR_NET_URL) #无效的服务器地址
    except requests.exceptions.ConnectTimeout:
        raise InstallError(_('connect to server failed: timeout.'), rval = JOIN_ERR_NET_TIMEOUT)
    except requests.exceptions.ReadTimeout:
        raise InstallError(_('connect to server failed: timeout.'), rval = JOIN_ERR_NET_TIMEOUT)
    except requests.exceptions.ConnectionError as conn_e:
        logger.error(conn_e)
        raise InstallError(_('connect to server failed, please check your network'), rval = JOIN_ERR_NET_CONN) #'连接服务器失败，请检查网络状态'
    except Exception as e:
        logger.error('%s:%s' % (type(e), str(e)))
        raise InstallError(_('unknow error, please see the infomation in log file'), rval = JOIN_ERR_UNKNOW)

def change_password(user, oldpwd, newpwd):
    if auth_type is None:
        auth_plugin = "HTTP"
    else:
        auth_plugin = auth_type
    if remote_server is None:
        server, _port = get_kcm_server()
    else:
        server = remote_server
    url = '%s://%s:%d/kim/modifypwd' % (HTTP_SCHEMA, server, KCM_JOIN_PORT)
    datas = {
        'username': user,
        'btoken': base64.b64encode(oldpwd.encode('utf-8')),
        'nbtoken': base64.b64encode(newpwd.encode('utf-8'))
    }
    resp_data = send_kcm_request(url, datas=datas, timeout=8)

def get_join_user(server):
    url = '%s://%s:%d/kim/getConfigs' % (HTTP_SCHEMA, server, KCM_JOIN_PORT)
    resp_data = send_kcm_request(url, timeout=8, method='Get')
    join_user = resp_data['usn'] if 'usn' in resp_data else ''
    return join_user

def unenroll_http(server):
    hostname = socket.gethostname()
    url = '%s://%s:%d/kim/exitdomain' % (HTTP_SCHEMA, server, KCM_JOIN_PORT)
    datas = {
        "hostname": hostname,
        "devsn": get_devsn()
    }
    send_kcm_request(url, datas, token=auth_token, method='Delete')

def kcm_unrolled_v2():
    serv, _port = get_kcm_server()
    try:
        unenroll_http(serv)
        kcm_restore_policy()
    except InstallError as ie:
        return ie.rval, ie.msg
    except Exception as e:
        logger.error('Unrolled unknow error: %s' % str(e))
        return JOIN_ERR_UNKNOW, str(e)
    return 0, 'success'

def admin_verify_join_GSSAPI(server, user, password):
    pass

def admin_verify_join_http(server, hostname):
    url = '%s://%s:%d/kim/hostreg' % (HTTP_SCHEMA, server, KCM_JOIN_PORT)
    datas = {
        #"sn": sn,
        "hostname": hostname,
        "devsn": get_devsn(),
        "ipaddr": extract_ip()
    }
    kim_dbus.joinProgress(50)
    resp_data = send_kcm_request(url, datas=datas, timeout=8, token=auth_token)
    resp_hostname = resp_data['hostname']
    print(resp_hostname)
    kim_krb5_setall(server)

def system_message():

    system_message = {"system_type": "unknown"}
    r_package_app = "/usr/bin/yum"
    u_package_app = "/usr/bin/apt"

    r_exists = os.path.exists(r_package_app)
    u_exists = os.path.exists(u_package_app)

    if r_exists is True and u_exists is False:
        system_message["system_type"] = "Server"
        logger.info("The current system is the server operating system")
    if r_exists is False and u_exists is True:
        system_message["system_type"] = "Desktop"
        logger.info("The current system is a desktop operating system")

    return system_message

def check_and_write_to_file(filename,content):
    try:
        # 检查文件是否存在
        if os.path.exists(filename):
            # 文件存在，则读取文件内容
            with open(filename, 'r') as file:
                file_content = file.read()
            # 如果文件内容中包含要检查的字符串，不进行写入
            if content in file_content:
                logger.info("The string is already present in the file. Not writing.")
                return True
        # 文件不存在或文件内容中不包含要检查的字符串，进行写入操作
        with open(filename, 'a') as file:
            file.write(content)
        logger.info("Content successfully written to", filename)
        return True
    except Exception as e:
        logger.info("An error occurred:", e)
        return False

def fetch_text_from_url(url): 
    try: 
        response = requests.get(url,verify=False) 
        if response.status_code == 200: 
            return response.text 
        else: 
            logger.error("Failed to fetch data from URL:", url) 
            return None 
    except Exception as e: 
        logger.error("An error occurred:", e) 
        return None

def fetch_ssh_key():
    try:
        if system_message().get("system_type") == "Server":
            kcm_ssh_url="https://%s:30234/aptserver/sshKeys/id_rsa.pub"%remote_server
            logger.info("Get the kcm ssh key from %s "%kcm_ssh_url)
            kcm_ssh_result=fetch_text_from_url(kcm_ssh_url)
            logger.info(kcm_ssh_result)
            if kcm_ssh_result:
                if check_and_write_to_file("/root/.ssh/authorized_keys",kcm_ssh_result) is False:
                    kcm_ssh_result=None
    except Exception as error_message:
        logger.error(_('Failed to obtain the ssh public key : %s') %error_message)
        return False
        # raise InstallError(_('Failed to obtain the ssh public key : %s') %error_message, rval = JOIN_ERR_KCM_SSH_KEY)
    
    if kcm_ssh_result is None:
        logger.error(_('Failed to obtain the ssh public key.'))
        return False
        # raise InstallError(_('Failed to obtain the ssh public key.'), rval = JOIN_ERR_KCM_SSH_KEY)
    return True

import yaml

def config_kcm_server():
    try:
        config = configparser.ConfigParser()
        config.read(kim_config_path)
        
        kcm_server=config.get("kcm",'server')
        kcm_port= config.get("kcm",'port')
        kcm_connect_address="https://" +kcm_server + ":" + kcm_port+ "/aptserver/kcm.yaml"
        logger.info('kcm.yaml - {%s}'%kcm_connect_address)
        
        kcm_info=fetch_text_from_url(kcm_connect_address)   
    except Exception as error_message:
        logger.error('faild to fetch kcm info from %s: %s' %(kcm_connect_address,error_message))
        raise InstallError('faild to fetch kcm info from %s: %s' %(kcm_connect_address,error_message), rval = JOIN_ERR_NET_URL) 
        
    try:
        yaml_data = yaml.safe_load(kcm_info)
        yaml_kcm_server=yaml_data['kcm']['kcm-server-domain']
        yaml_kcm_port=yaml_data['kcm']['kcm-server-port']        
        
        hedron_config = configparser.ConfigParser()
        hedron_config_path='/etc/hedron/client.conf'
        hedron_config.read(hedron_config_path)
        
        hedron_client_url='https://%s:%s/'%(yaml_kcm_server,yaml_kcm_port)
        hedron_config.set("hedron-client","url",hedron_client_url)
        
        with open(hedron_config_path, 'w') as configfile:
            hedron_config.write(configfile)
        
    except Exception as error_message:
        logger.error('faild to fetch kcm info from %s: %s' %(kcm_connect_address,error_message))
        raise InstallError('faild to fetch kcm info from %s: %s' %(kcm_connect_address,error_message), rval = JOIN_ERR_NET_URL) 
        
    return True

def remove_string_from_file(filename, string_to_remove):
    try:
        # 读取文件内容
        with open(filename, 'r') as file:
            file_content = file.read()

        # 删除指定字符串
        modified_content = file_content.replace(string_to_remove, '')

        # 将修改后的内容写回文件
        with open(filename, 'w') as file:
            file.write(modified_content)

        print("String successfully removed from", filename)
        return True
    except Exception as e:
        print("An error occurred:", e)
        return False

def delete_ssh_key():
    try:
        if system_message().get("system_type") == "Server":
            remote_server,remote_port=get_kcm_server()
            kcm_ssh_url="https://%s:30234/aptserver/sshKeys/id_rsa.pub"%remote_server
            logger.info("Get the kcm ssh key from %s "%kcm_ssh_url)
            kcm_ssh_result=fetch_text_from_url(kcm_ssh_url)
            logger.info(kcm_ssh_result)
            if kcm_ssh_result:
                if remove_string_from_file("/root/.ssh/authorized_keys",kcm_ssh_result) is False:
                    kcm_ssh_result=None
    except Exception as error_message:
        logger.error(_('Failed to delete the ssh public key : %s') %error_message)
        # raise InstallError(_('Failed to delete the ssh public key : %s') %error_message, rval = JOIN_ERR_KCM_SSH_KEY)
        return False
        
    if kcm_ssh_result is None:
        logger.error(_('Failed to delete the ssh public key.'))
        # raise InstallError(_('Failed to delete the ssh public key.'), rval = JOIN_ERR_KCM_SSH_KEY)
        return False
    
    return True

def modify_client_conf(name):
    file = '/etc/hedron/client.conf'

    if os.path.isfile(file):
        file_data = ''
        with open(file, "r", encoding="utf-8") as f:
            for line in f:
                if line.startswith('url'):
                    line = line.replace(line, "url=https://" + name + ':30234/' + '\n')

                file_data += line
        with open(file, "w", encoding="utf-8") as f:
            f.write(file_data)

def admin_verify_join(user, password):
    if auth_type == 'GSSAPI':
        pass
    else:
        user_auth_proxy(remote_server, user, password)
    check_kcm_availability(remote_server)
    admin_verify_join_http(remote_server, new_hostname)

def admin_join_confirm():
    try:
        kim_configure(remote_server, KCM_JOIN_PORT, provider='kcm')
        #kim_setmkhomedir()
        kim_dbus.joinProgress(60)
        
        fetch_ssh_key()
        kcm_init(remote_server)
        kim_dbus.joinProgress(80)
        kim_sethostname(new_hostname)
        admin_confirm_join_http(remote_server)
        #update_server_info(remote_server, KCM_JOIN_PORT)
        kim_dbus.joinProgress(100)

    except InstallError as ie:
        try:
            unrolling_host(rollback = True)
        except Exception as e:
            logger.error(e)
        raise ie
    except Exception as e:
        logger.error(e)
        raise InstallError(_('unknow error, please see the infomation in log file'), rval = JOIN_ERR_UNKNOW)

class KimDomain(dbus.service.Object):
    def __init__(self, bus, object_path):
        logger.info('kim service start.')
        dbus.service.Object.__init__(self, bus, object_path)
        self._last_input = None

    def getSenderLang(self, sender):
        lang = 'zh_CN'
        try:
            system_bus = dbus.SystemBus()
            send_uid = system_bus.get_unix_user(sender)
            path = '/org/freedesktop/Accounts/User%d' % send_uid
            proxy = system_bus.get_object('org.freedesktop.Accounts', path)
            auser = dbus.Interface(proxy,dbus_interface="org.freedesktop.DBus.Properties")
            lang = auser.Get('org.freedesktop.Accounts.User', 'Language')
        except Exception as e:
            print(e)
        return lang

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='', out_signature='s')
    def getDefaultServer(self):
        try:
            server, _port = get_server_info()
            return server
        except Exception as e:
            return ''

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='', out_signature='s')
    def getSerialNo(self):
        try:
            sn = get_device_serialno()
            return sn
        except Exception as e:
            return ''

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='s', out_signature='is', sender_keyword='sender')
    def deviceSNJoin(self, server, sender = None):
        logger.info('start join server[%s].' % server)
        try:
            lang = self.getSenderLang(sender)
            #os.environ['LANGUAGE'] = lang
            set_lang(lang)
            device_sn_join(server)
        except InstallError as ie:
            return ie.rval, ie.msg
        return SUCCESS, _('register success') #'注册成功'

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='ss', out_signature='is', sender_keyword='sender')
    def checkServer(self, server, hostname, sender = None):
        logger.info('start check server[%s].' % server)
        try:
            lang = self.getSenderLang(sender)
            set_lang(lang)
            check_server_info(server, hostname)
        except InstallError as ie:
            return ie.rval, ie.msg
        return SUCCESS, _('success')

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='ss', out_signature='is', sender_keyword='sender')
    def userVerifyJoin(self, user, password, sender = None):
        logger.info('start join server.')
        try:
            lang = self.getSenderLang(sender)
            #os.environ['LANGUAGE'] = lang
            set_lang(lang)
            admin_verify_join(user, password)
        except InstallError as ie:
            print(ie.rval)
            return ie.rval, ie.msg
        return SUCCESS, _('success')

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='', out_signature='is', sender_keyword='sender')
    def joinComfirm(self, sender = None):
        logger.info('comfirm join server.')
        try:
            lang = self.getSenderLang(sender)
            #os.environ['LANGUAGE'] = lang
            set_lang(lang)
            admin_join_confirm()
        except InstallError as ie:
            return ie.rval, ie.msg
        return SUCCESS, _('success')

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='ssss', out_signature='is', sender_keyword='sender')
    def userJoinCommand(self, server, hostname, user, password, sender = None):
        logger.info('start join server[%s].' % server)
        try:
            lang = self.getSenderLang(sender)
            #os.environ['LANGUAGE'] = lang
            set_lang(lang)
            check_server_info(server, hostname)
            admin_verify_join(user, password)
            admin_join_confirm()
        except InstallError as ie:
            return ie.rval, ie.msg
        return SUCCESS, _('success')

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='ss', out_signature='is', sender_keyword='sender')
    def userAuthRemote(self, user, password, sender = None):
        logger.info('start authenticaion [%s].' % user)
        try:
            lang = self.getSenderLang(sender)
            os.environ['LANGUAGE'] = lang
            serv, _port = get_kcm_server()
            user_auth_proxy(serv, user, password)
        except InstallError as ie:
            return ie.rval, ie.msg
        return SUCCESS, _('success')

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='sss', out_signature='is', sender_keyword='sender')
    def userChangePwd(self, user, oldpwd, newpwd, sender = None):
        logger.info('start changing password [%s].' % user)
        try:
            lang = self.getSenderLang(sender)
            os.environ['LANGUAGE'] = lang
            change_password(user, oldpwd, newpwd)
        except InstallError as ie:
            return ie.rval, ie.msg
        return SUCCESS, _('success')

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='', out_signature='i')
    def getDomainStatus(self):
        return get_domain_status()

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='', out_signature='is', sender_keyword='sender')
    def unenroll(self, sender = None):
        logger.info('start unenroll.')
        try:
            delete_ssh_key()
            lang = self.getSenderLang(sender)
            #os.environ['LANGUAGE'] = lang
            set_lang(lang)
            unrolling_host()
        except InstallError as ie:
            return ie.rval, ie.msg
        if have_domain_user_login():
            # 有域用户登录， 则重启
            os.system("setsid sleep 10s && shutdown -r now &")
        return SUCCESS, _('unenroll success') #'注销成功'

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='', out_signature='is', sender_keyword='sender')
    def unenroll_local(self, sender = None):
        logger.info('start unenroll_local.')
        try:
            lang = self.getSenderLang(sender)
            #os.environ['LANGUAGE'] = lang
            set_lang(lang)
            unrolling_host(rollback = True)
        except InstallError as ie:
            return ie.rval, ie.msg
        return SUCCESS, _('unenroll success') #'注销成功'

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='s', out_signature='is', sender_keyword='sender')
    def getDefaultUser(self, server, sender = None):
        logger.info('get default user.')
        join_name = ''
        try:
            lang = self.getSenderLang(sender)
            set_lang(lang)
            join_name = get_join_user(server)
        except InstallError as ie:
            return ie.rval, ie.msg
        return SUCCESS, join_name #'注销成功'

    @dbus.service.signal(dbus_interface='com.kylin.kim.domain', signature='i')
    def joinProgress(self, prog):
        print('join:%d%%' % prog)


def kcmcfg2kim():
    if get_domain_status() != 0:
        return
    kcm_file = '/etc/hedron/client.conf'
    config = configparser.ConfigParser()
    config.read(kcm_file, encoding='utf-8')
    url = config.get('hedron-client', 'url')
    up = parse.urlparse(url)
    kim_configure(up.hostname, up.port, provider='kcm')

def updatekimconfig():
    if get_domain_status() != 0:
        return
    try:
        server, port = get_server_info()
        kim_configure(server, port, provider='kcm')
    except Exception:
        pass

def main():
    global kim_dbus
    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
    standard_logging_setup('/var/log/kim-domain.log', filemode='a')

    sys_bus = dbus.SystemBus()
    name = dbus.service.BusName('com.kylin.kim.domain', sys_bus)
    kim_dbus = KimDomain(sys_bus, '/')
    mainloop = GLib.MainLoop()
    mainloop.run()


if __name__ == "__main__":
    if len(sys.argv) > 1 and sys.argv[1] == 'kcm2kim':
        kcmcfg2kim()
    elif len(sys.argv) > 1 and sys.argv[1] == 'kimupdate':
        updatekimconfig()
    else:
        main()
