# coding: utf-8
# 服务器端每5分钟更改密码，申请的时候管理服务器从服务器端获取token（time + server license）
# 主机名md5[15:] + 用户名md5[15:] + timetoken md5[15:] + server uuid md5  的md5值[15:].upper()
# 服务器端主动上报token至集中管理服务器并记录，每台服务器记录一条，每次都修改上一次的记录，当服务器端更改密码的程序出故障时，使用数据库记录的最后一次token
# 平台登录申请使用google authenticator加password认证
import time
import logging
import logging.config
import socket
import MySQLdb
import hashlib
import subprocess
from config import Config
import redis
import base64
import string
import random




class PWDManager(object):
    def __init__(self, user):
        """

        Dy token Manager
        """

        self.t = int(time.time())
        self.hostname = socket.gethostname()
        self.loginuser = user
        self.serverid = subprocess.Popen(['dmidecode -s system-uuid'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.read().strip()
        logging.config.fileConfig("logging.conf")
        self.logger = logging.getLogger("Main")
        self.conn = MySQLdb.connect(user=decodestr(Config.dbuser), passwd=decodestr(Config.dbpasswd), host=decodestr(Config.dbhost), port=int(decodestr(Config.dbport)))
        self.cursor = self.conn.cursor()
        self.redis_conn = redis.StrictRedis(host=decodestr(Config.redishost), port=int(decodestr(Config.redisport)), db=0)



    @property
    def tokengenerate(self):
        try:
            token_hostname = hashlib.md5(self.hostname).hexdigest()[10:]
            token_loginuser = hashlib.md5(self.loginuser).hexdigest()[10:]
            token_unix_time = hashlib.md5(str(int(self.t) / 300)).hexdigest()[10:]
            #token_serverid = hashlib.md5(self.serverid).hexdigest()[10:]
            token = hashlib.md5(token_hostname + token_loginuser + token_unix_time).hexdigest()[10:].upper()
            token, rd = self.recodepw(token)
            self.rd = '&'.join([str(x) for x in rd])
            self.logger.info('token created success.')
            return token
        except Exception, e:
            self.logger.error("generate token faild!")
            self.logger.debug(e)

    @property
    def modifypwd(self):
        p1 = subprocess.Popen(['echo', self.tokengenerate], stdout=subprocess.PIPE)
        p2 = subprocess.Popen(['passwd', '--stdin', self.loginuser], stdin=p1.stdout, stdout=subprocess.PIPE)
        result = p2.communicate()
        if result[-1]:
            self.logger.error(result[-1])
            return
        else:
            self.logger.debug("change security token success.")
            return True

    @property
    def reporter(self):
        result = True

        # database
        try:
            self.cursor.execute('select id from %s.token_info where host="%s"' % (decodestr(Config.dbname), self.hostname))
            token_id = self.cursor.fetchone()
            if not token_id:
                self.cursor.execute('insert into %s.token_info(host,time,rd_list) VALUES ("%s",%s,%s)' % ( decodestr(Config.dbname), self.hostname, self.t, self.rd))
                self.conn.commit()
            else:
                self.cursor.execute(
                    'update %s.token_info set time = %s,rd_list=%s where host = "%s"' % ( decodestr(Config.dbname), self.t,  self.rd, self.hostname ))
                self.conn.commit()
            self.logger.debug("update database scuess!")
        except Exception, e:
            self.logger.error("update database faild!")
            self.logger.debug(e)
            result = False

        #redis
        try:
            redis_set_t = self.redis_conn.set(self.hostname, self.t)
            redis_set_rd = self.redis_conn.set(self.hostname + 'rd', self.rd)
            if not redis_set_t and not redis_set_rd :
                result = False

        except Exception, e:
            self.logger.error("update redis faild!")
            self.logger.debug(e)
            result = False
        if result:
            self.logger.debug("update redis scuess!")
        return result

    def recodepw(self,token):
        spec_case = [x for x in '~!@#$%^&*()_+{}<>-='] + [x for x in string.lowercase]
        rd = random.sample(range(22),12)
        reset_token = ''
        for x in range(len(token)):
            if x in rd:
                w = spec_case[x]
            else:
                w = token[x]
            reset_token += w
        return reset_token, rd


def decodestr(s):
    dns = s[5:].replace(s[-12:-4], '') + '=='
    return base64.decodestring(dns)

# if __name__ == '__main__':
#     for user in users:
#         Agent = PWDManager(user)
#         token = Agent.tokengenerate
#         if token:
#             rep = Agent.reporter
#             if rep:
#                 Agent.modifypwd
#             else:
#                 continue
#         else:
#             continue

#   ~!@#$%^&*()_+{}<>-= 对应range(11,30)
#  a-z 对应     range(30,56)
