#coding:utf-8
import os
import sys
import stat
import time
import base64
import shutil
import sunhpc
from sunhpc.core.utils import SafeError
class command(sunhpc.commands.create.command):

    def makeEncrypt(self, filename, path=None, safedir="/etc/safe.d", quiet=0):
        """
        filename: 需要加密的真实文件路径. /etc/safe-security/ssh_host_rsa_key
        path    : 最终实际安装的文件路径. /etc/ssh/ssh_host_rsa_key
        """

        if not os.access(filename, os.R_OK):
            self.msg("I cannot find or see '%s' file" % filename, 'a')

        if not os.access(safedir, os.W_OK):
            self.msg("I do not have permission to write to '%s'" % safedir, 'a')

        # 获取这个文件的类型权限等相关信息.
        s = os.stat(filename)

        # 获取文件类型和权限 十进制数值.
        mode = s[stat.ST_MODE]

        # 将文件类型和权限 转换成八进制数值
        moct = oct(mode)

        # 获取UID和GID
        uid = s[stat.ST_UID]
        gid = s[stat.ST_GID]

        # 获取文件大小
        fsize = s[stat.ST_SIZE]

        # 获取文件最后访问时间
        atime = s[stat.ST_ATIME]

        # 获取文件创建时间
        ctime = s[stat.ST_CTIME]

        # 获取文件最后修改时间
        mtime = s[stat.ST_MTIME]

        # 将uid和gid组合.
        owner = "%d.%d" % (uid, gid)

        # 通过时间戳转换成友好时间格式
        # timeArray = time.localtime(atime)
        # timeFmt = time.strftime("%Y-%m-%d %H:%M:%S", timeArray)
        # 2020-11-26 20:36:28

        # 加密类函数.
        secu = sunhpc.core.security.Security(2048)

        # 获取文件的绝对路径. e.g., /etc/passwd
        # fullpath: /etc/passwd
        fullpath = os.path.abspath(filename)
        if path:
            fullpath = path

        # 获取security Plugin插件 /opt/sunhpc/var/plugins/security
        plugin_path = os.path.join(self.prefix, 'var', 'plugins', 'security')
        sys.path.append(plugin_path)
        mod_file = None
        for plugin_file in os.listdir(plugin_path):
            if not plugin_file.endswith('.py'):
                continue
            mod_name = plugin_file.split('.py')[0]
            # Import the plugin
            mod = __import__(mod_name)
            plugin = mod.Plugin()
            if plugin.get_filename() == fullpath:
                mod_file = plugin_file
                break
            else:
                plugin = None

        # 通过get_filename 函数 获取是处理哪一个文件.将此plugin代码添加到密文中.
        if mod_file == None:
            pycode = None
        else:
            f = open(os.path.join(plugin_path, mod_file), 'r')
            pycode = f.read().encode('UTF-8')
            f.close()

        # e.g., dirs:/etc name:passwd
        dirs, name = os.path.split(filename)
        if path:
            dirs, name = os.path.split(filename)

        # 开始制作xml配置文件.
        header = "<?xml version='1.0' standalone='yes'?>\n"
        header = "<SafeService>\n"
        header += "<name>%s</name>\n"   % fullpath
        header += "<mode>%s</mode>\n"   % moct
        header += "<owner>%s</owner>\n" % owner
        header += "<directory>%s</directory>\n" % dirs

        plaintext = header

        # 如果是一个文件.
        if stat.S_ISREG(mode):

            plaintext += "<content>\n<![CDATA[\n"

            with open(filename, 'r') as f:
                # 将内容转换bytes格式. 否则无法base64.
                content = f.read().encode('UTF-8')

            # 将bytes 转换成 str
            plaintext += str(base64.b64encode(content), encoding="utf-8")
            plaintext += "]]>\n</content>\n"

        elif stat.S_ISDIR(mode):
            pass

        else:
            raise SafeError("I can only publish a regular file or a directory.")

        # 将pycode添加到配置文件中.当使用safeGet命令时调用.
        if pycode is not None:
            plaintext += "<pycode>\n<![CDATA[\n"
            plaintext += str(base64.b64encode(pycode), encoding="utf-8")
            plaintext += "]]>\n</pycode>\n"
        plaintext += '</SafeService>\n'

        # 将plaintext格式的内容进行加密.
        msg = secu.encrypt(plaintext)

        # safe格式文件名 e.g., - /etc/passwd > etc.passwd
        safeFilename = self.tranpath(filename)
        if path:
            safeFilename = self.tranpath(path)

        # 将加密的内容写入到safe目录,e.g., /etc/safe.d/passwd
        fname = os.path.join(safedir, safeFilename)
        with open(fname, 'w') as f:
            f.write(msg)

        if not quiet:
            print ("SafeFile Wrote: %s/%s" % (safedir, safeFilename))


class Command(command):
    """
    Create sunhpc cluster security keys ...

    <arg type='string' name='keyname'>
    supply an name e,g.. rsa, dsa, ecd, and so on.
    </arg>

    <param type='string' name='keyname'>
    supply an name e,g.. rsa, dsa, ecd, and so on.
    </param>

    <param type='Bool' name='force'>
    Force create the keys.
    </param>

    <example cmd='create security rsa'>
    Create an security keypair to /etc/safe-security
    </example>
    """

    def run(self, param, args):

        (keyname, force) = self.fillParams([
            ('keyname', None),
            ('force', 'no')
            ])

        force   = self.str2bool(force)
        safedir = '/etc/safe-security'
        if not keyname:
            if not args:
                self.msg('must supply an keyname.', 'a')
            
            keyname = args[0]

        if keyname not in ['rsa', 'dsa', 'ecdsa']:
            self.msg('supply keyname is not support (rsa, dsa, ecdsa).', 'a')

        if force and os.path.exists(safedir):
            shutil.rmtree(safedir)

        if not os.path.exists(safedir):
            os.makedirs(safedir)

        security = sunhpc.core.security.Security()

        if keyname in ['r', 'rsa']:
            keyspair = security.makeRsaKeyPair()
            self.makeKeys(keyspair, safedir)

        if keyname in ['d', 'dsa']:
            pass

        if keyname in ['e', 'ec', 'ecd', 'ecdsa']:
            pass

    def makeKeys(self, keyspair, safedir):
        plist = ['master.key', 'master.pub', 'shared.key', 'shared.pub']
        for pp in plist:
            filename = os.path.join(safedir, pp)
            if os.path.exists(filename):
                continue
        
            with open(filename, 'wb') as f:
                f.write(keyspair[pp] + b'\n')

            if pp.split('.')[-1] == 'key':
                os.system('chmod 0400 %s' % filename)
            else:
                os.system('chmod 0444 %s' % filename)

RollName = "base"
