def _register_core(self, param): # 因为core服务启动了(之前可能非正常终止了),做一下数据库中会话状态的修复操作 record.session_fix() if 'rpc' not in param: return self.write_json(-1, 'invalid param.') app_cfg().core_server_rpc = param['rpc'] # 获取core服务的配置信息 req = {'method': 'get_config', 'param': []} _yr = async_post_http(req) return_data = yield _yr if return_data is None: return self.write_json(-1, 'get config from core service failed.') if 'code' not in return_data: return self.write_json( -2, 'get config from core service return invalid data.') if return_data['code'] != 0: return self.write_json( -3, 'get config from core service return code: {}'.format( return_data['code'])) app_cfg().update_core(return_data['data']) return self.write_json(0)
def delete_log(log_list): try: where = list() for item in log_list: where.append(' `id`={}'.format(item)) db = get_db() sql = 'DELETE FROM `{}log` WHERE{};'.format(db.table_prefix, ' OR'.join(where)) ret = db.exec(sql) if not ret: return False # TODO: 此处应该通过json-rpc接口通知core服务来删除重放文件。 for item in log_list: log_id = int(item) try: record_path = os.path.join(app_cfg().core.replay_path, 'ssh', '{:06d}'.format(log_id)) if os.path.exists(record_path): shutil.rmtree(record_path) record_path = os.path.join(app_cfg().core.replay_path, 'rdp', '{:06d}'.format(log_id)) if os.path.exists(record_path): shutil.rmtree(record_path) except Exception: pass return True except: return False
def get(self): if not app_cfg().core.detected: total_size = 0 free_size = 0 else: total_size, free_size = get_free_space_bytes(app_cfg().core.replay_path) param = { 'user_list': user.get_user_list(with_admin=True), 'total_size': total_size, 'free_size': free_size, } self.render('log/index.mako', page_param=json.dumps(param))
def verify_user(name, password): cfg = app_cfg() db = get_db() sql = 'SELECT `account_id`, `account_type`, `account_name`, `account_pwd`, `account_lock` FROM `{}account` WHERE `account_name`="{}";'.format(db.table_prefix, name) db_ret = db.query(sql) if db_ret is None: # 特别地,如果无法取得数据库连接,有可能是新安装的系统,尚未建立数据库,此时应该处于维护模式 # 因此可以特别地处理用户验证:用户名admin,密码admin可以登录为管理员 if cfg.app_mode == APP_MODE_MAINTENANCE: if name == 'admin' and password == 'admin': return 1, 100, 'admin', 0 return 0, 0, '', 0 if len(db_ret) != 1: return 0, 0, '', 0 user_id = db_ret[0][0] account_type = db_ret[0][1] name = db_ret[0][2] locked = db_ret[0][4] if locked == 1: return 0, 0, '', locked if not sec_verify_password(password, db_ret[0][3]): # 按新方法验证密码失败,可能是旧版本的密码散列格式,再尝试一下 if db_ret[0][3] != hashlib.sha256(password.encode()).hexdigest(): return 0, 0, '', locked else: # 发现此用户的密码散列格式还是旧的,更新成新的吧! _new_sec_password = sec_generate_password(password) sql = 'UPDATE `{}account` SET `account_pwd`="{}" WHERE `account_id`={}'.format(db.table_prefix, _new_sec_password, int(user_id)) db.exec(sql) return user_id, account_type, name, locked
def post(self): code = self.get_session('captcha') if code is None: return self.write_json(-1, '验证码已失效') self.del_session('captcha') args = self.get_argument('args', None) if args is not None: args = json.loads(args) captcha = args['captcha'] username = args['username'] userpwd = args['userpwd'] remember = args['remember'] else: return self.write_json(-1, '参数错误') if code.lower() != captcha.lower(): return self.write_json(-1, '验证码错误') try: user_id, account_type, nickname, locked = user.verify_user( username, userpwd) if locked == 1: return self.write_json(-1, '账号被锁定,请联系管理员!') if user_id == 0: if app_cfg().app_mode == APP_MODE_MAINTENANCE: return self.write_json(-2, '系统维护中,请稍候再试!') else: return self.write_json(-1, '用户名/密码错误!') _user = self.get_session('user') if _user is None: _user = dict() _user['id'] = 0 _user['name'] = 'guest' _user['nick_name'] = '访客' _user['status'] = 0 _user['phone_num'] = '110' _user['type'] = 0 _user['permission'] = 0 _user['is_login'] = False _user['id'] = user_id _user['is_login'] = True _user['name'] = username _user['nick_name'] = nickname _user['type'] = account_type if remember: self.set_session('user', _user, 12 * 60 * 60) else: self.set_session('user', _user) return self.write_json(0) except: log.e('can not set session.') return self.write_json(-1, '发生异常,无法登录!')
def read_record_info(record_id, file_id): record_path = os.path.join(app_cfg().core.replay_path, 'ssh', '{:06d}'.format(int(record_id))) file_info = os.path.join(record_path, 'tp-ssh.{:03d}'.format(int(file_id))) file = None try: file = open(file_info, 'rb') data = file.read() total_size = len(data) offset = 0 data_size, = struct.unpack_from('I', data, offset) offset += 4 data_list = list() while True: action, = struct.unpack_from('B', data, offset) offset += 1 _size, = struct.unpack_from('I', data, offset) offset += 4 _time, = struct.unpack_from('I', data, offset) offset += 4 # skip reserved 3 bytes. offset += 3 _format = '{}s'.format(_size) _data, = struct.unpack_from(_format, data, offset) offset += _size temp = dict() temp['a'] = action temp['t'] = _time if action == 1: # this is window size changed. w, h = struct.unpack_from('HH', _data) temp['w'] = w temp['h'] = h elif action == 2: _data = _data.decode() # this is ssh data. temp['d'] = _data else: return None data_list.append(temp) if offset == total_size: break except Exception as e: log.e('failed to read record file: {}\n'.format(file_info)) return None finally: if file is not None: file.close() return data_list
def get(self): total_size, free_size = get_free_space_bytes(app_cfg().data_path) param = { 'user_list': user.get_user_list(with_admin=True), 'total_size': total_size, 'free_size': free_size, } self.render('log/index.mako', page_param=json.dumps(param))
def get(self, protocol, record_id): header = record.read_record_head(record_id) if header is None: return self.write_json(-3, '操作失败') # ret = dict() # ret['header'] = header # return self.write_json(0, data=ret) param = dict() param['header'] = header param['count'] = 0 param['op'] = list() cmd_type = 0 # 0 = ssh, 1 = sftp protocol = int(protocol) if protocol == 1: pass elif protocol == 2: record_path = os.path.join(app_cfg().core.replay_path, 'ssh', '{:06d}'.format(int(record_id))) file_info = os.path.join(record_path, 'tp-ssh-cmd.txt') try: file = open(file_info, 'r') data = file.readlines() for i in range(len(data)): if 0 == i: cmd = data[i][22:-1] if 'SFTP INITIALIZE' == cmd: cmd_type = 1 continue if cmd_type == 0: param['op'].append({'t': data[i][1:20], 'c': data[i][22:-1]}) else: cmd_info = data[i][22:-1].split(':') if len(cmd_info) != 4: continue param['op'].append({'t': data[i][1:20], 'c': cmd_info[0], 'p1': cmd_info[2], 'p2': cmd_info[3]}) except: pass param['count'] = len(param['op']) if cmd_type == 0: self.render('log/record-ssh-cmd.mako', page_param=json.dumps(param)) else: self.render('log/record-sftp-cmd.mako', page_param=json.dumps(param))
def init(self): cfg = app_cfg() if 'sqlite' == cfg.database.type: if cfg.database.sqlite_file is None: cfg.set_default('database::sqlite-file', os.path.join(cfg.data_path, 'db', 'ts_db.db')) if not self._init_sqlite(cfg.database.sqlite_file): return False elif 'mysql' == cfg.database.type: if not self._init_mysql( cfg.database.mysql_host, cfg.database.mysql_port, cfg.database.mysql_db, cfg.database.mysql_prefix, cfg.database.mysql_user, cfg.database.mysql_password): return False else: log.e('unknown database type `{}`, support sqlite/mysql now.\n'. format(cfg.database.type)) return False # 看看数据库中是否存在指定的数据表(如果不存在,可能是一个空数据库文件),则可能是一个新安装的系统 # ret = self.query('SELECT COUNT(*) FROM `sqlite_master` WHERE `type`="table" AND `name`="{}account";'.format(self._table_prefix)) ret = self.is_table_exists('{}group'.format(self._table_prefix)) if ret is None or not ret: log.w('database need create.\n') self.need_create = True return True # 尝试从配置表中读取当前数据库版本号(如果不存在,说明是比较旧的版本了) ret = self.query( 'SELECT `value` FROM `{}config` WHERE `name`="db_ver";'.format( self._table_prefix)) if ret is None or 0 == len(ret): self.current_ver = 1 else: self.current_ver = int(ret[0][0]) if self.current_ver < self.DB_VERSION: log.w('database need upgrade.\n') self.need_upgrade = True return True # DO TEST # self.alter_table('ts_account', [['account_id', 'id'], ['account_type', 'type']]) return True
def get(self, protocol, record_id): param = dict() param['count'] = 0 param['op'] = list() protocol = int(protocol) if protocol == 1: pass elif protocol == 2: record_path = os.path.join(app_cfg().core.replay_path, 'ssh', '{:06d}'.format(int(record_id))) file_info = os.path.join(record_path, 'tp-ssh-cmd.txt') try: file = open(file_info, 'r') data = file.readlines() for i in range(len(data)): param['op'].append({'t': data[i][1:20], 'c': data[i][22:-1]}) except: pass param['count'] = len(param['op']) self.render('log/record-ssh-cmd.mako', page_param=json.dumps(param))
import time import csv import os import json import threading import tornado.gen import tornado.httpclient from eom_app.app.configs import app_cfg from eom_app.app.util import * from eom_app.module import host from eom_common.eomcore.logger import * from eom_app.app.session import web_session from .base import TPBaseUserAuthHandler, TPBaseAdminAuthHandler, TPBaseUserAuthJsonHandler, TPBaseAdminAuthJsonHandler cfg = app_cfg() # 临时认证ID的基数,每次使用时均递减 tmp_auth_id_base = -1 tmp_auth_id_lock = threading.RLock() class IndexHandler(TPBaseUserAuthHandler): def get(self): _user = self.get_session('user') if _user is None: return self.write(-1) param = dict() param['core'] = {
def initialize(self, path, default_filename=None): super().initialize(path, default_filename) self.root = app_cfg().core.replay_path
def read_record_head(record_id): record_path = os.path.join(app_cfg().core.replay_path, 'ssh', '{:06d}'.format(int(record_id))) header_file_path = os.path.join(record_path, 'tp-ssh.tpr') file = None try: file = open(header_file_path, 'rb') data = file.read() offset = 0 magic, = struct.unpack_from('I', data, offset) # magic must be 1381126228, 'TPPR' offset += 4 ver, = struct.unpack_from('H', data, offset) offset += 2 protocol, = struct.unpack_from('H', data, offset) offset += 2 time_start, = struct.unpack_from('Q', data, offset) offset += 8 pkg_count, = struct.unpack_from('I', data, offset) offset += 4 time_used, = struct.unpack_from('I', data, offset) offset += 4 width, = struct.unpack_from('H', data, offset) offset += 2 height, = struct.unpack_from('H', data, offset) offset += 2 file_count, = struct.unpack_from('H', data, offset) offset += 2 total_size, = struct.unpack_from('I', data, offset) offset += 4 account, = struct.unpack_from('16s', data, offset) account = account.decode() offset += 16 user_name, = struct.unpack_from('16s', data, offset) user_name = user_name.decode() offset += 16 ip, = struct.unpack_from('18s', data, offset) ip = ip.decode() offset += 18 port, = struct.unpack_from('H', data, offset) offset += 2 except Exception as e: log.e(e) return None finally: if file is not None: file.close() header = dict() header['start'] = time_start header['file_count'] = file_count header['time_used'] = time_used header['width'] = width header['height'] = height header['account'] = account header['user_name'] = user_name header['ip'] = ip header['port'] = port return header