web版RDP录像播放,可以播放鼠标移动的录像了,下一步是显示rdp的图像。
							parent
							
								
									9305953218
								
							
						
					
					
						commit
						39c8fd32d5
					
				
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 1.2 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 63 KiB  | 
| 
						 | 
				
			
			@ -161,10 +161,9 @@ $app.on_table_host_cell_created = function (tbl, row_id, col_key, cell_obj) {
 | 
			
		|||
            var action = $(this).attr('data-action');
 | 
			
		||||
 | 
			
		||||
            if (action === 'replay') {
 | 
			
		||||
                //$app.dlg_edit_host.show_edit(row_id);
 | 
			
		||||
                if (row_data.protocol_type === TP_PROTOCOL_TYPE_RDP) {
 | 
			
		||||
                    // $tp.notify_error('sorry, not impl.');
 | 
			
		||||
                    $app.do_replay_rdp(row_data.id, row_data.user_username, row_data.acc_username, row_data.host_ip, row_data.time_begin);
 | 
			
		||||
                    // $app.do_replay_rdp(row_data.id, row_data.user_username, row_data.acc_username, row_data.host_ip, row_data.time_begin);
 | 
			
		||||
                    window.open('/audit/replay/' + row_data.protocol_type + '/' + row_data.id);
 | 
			
		||||
                } else if (row_data.protocol_type === TP_PROTOCOL_TYPE_SSH) {
 | 
			
		||||
                    window.open('/audit/replay/' + row_data.protocol_type + '/' + row_data.id);
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
						 | 
				
			
			@ -1,29 +1,5 @@
 | 
			
		|||
"use strict";
 | 
			
		||||
 | 
			
		||||
$app.req_record_data = function (record_id, offset) {
 | 
			
		||||
    $tp.ajax_post_json('/audit/get-record-data', {id: record_id, offset: offset},
 | 
			
		||||
        function (ret) {
 | 
			
		||||
            if (ret.code === TPE_OK) {
 | 
			
		||||
                // console.log('data', ret.data);
 | 
			
		||||
                $app.record_data = $app.record_data.concat(ret.data.data_list);
 | 
			
		||||
                $app.record_data_offset += ret.data.data_size;
 | 
			
		||||
 | 
			
		||||
                if ($app.record_data.length < $app.record_hdr.pkg_count) {
 | 
			
		||||
                    $app.req_record_data(record_id, $app.record_data_offset);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                $app.dom.status.text("读取录像数据失败:" + tp_error_msg(ret.code));
 | 
			
		||||
                $tp.notify_error('读取录像数据失败:' + tp_error_msg(ret.code, ret.message));
 | 
			
		||||
                console.log('req_record_info error ', ret.code);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        function () {
 | 
			
		||||
            console.log('req_record_info error');
 | 
			
		||||
        },
 | 
			
		||||
        30 * 1000
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
$app.on_init = function (cb_stack) {
 | 
			
		||||
    var record_id = $app.options.record_id;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +46,7 @@ $app.on_init = function (cb_stack) {
 | 
			
		|||
 | 
			
		||||
    Terminal.cursorBlink = false;
 | 
			
		||||
 | 
			
		||||
    $tp.ajax_post_json('/audit/get-record-header', {id: record_id},
 | 
			
		||||
    $tp.ajax_post_json('/audit/get-record-header', {protocol: TP_PROTOCOL_TYPE_SSH, id: record_id},
 | 
			
		||||
        function (ret) {
 | 
			
		||||
            if (ret.code === TPE_OK) {
 | 
			
		||||
                $app.record_hdr = ret.data;
 | 
			
		||||
| 
						 | 
				
			
			@ -184,6 +160,30 @@ $app.on_init = function (cb_stack) {
 | 
			
		|||
    cb_stack.exec();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
$app.req_record_data = function (record_id, offset) {
 | 
			
		||||
    $tp.ajax_post_json('/audit/get-record-data', {protocol: TP_PROTOCOL_TYPE_SSH, id: record_id, offset: offset},
 | 
			
		||||
        function (ret) {
 | 
			
		||||
            if (ret.code === TPE_OK) {
 | 
			
		||||
                // console.log('data', ret.data);
 | 
			
		||||
                $app.record_data = $app.record_data.concat(ret.data.data_list);
 | 
			
		||||
                $app.record_data_offset += ret.data.data_size;
 | 
			
		||||
 | 
			
		||||
                if ($app.record_data.length < $app.record_hdr.pkg_count) {
 | 
			
		||||
                    $app.req_record_data(record_id, $app.record_data_offset);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                $app.dom.status.text("读取录像数据失败:" + tp_error_msg(ret.code));
 | 
			
		||||
                $tp.notify_error('读取录像数据失败:' + tp_error_msg(ret.code, ret.message));
 | 
			
		||||
                console.log('req_record_info error ', ret.code);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        function () {
 | 
			
		||||
            console.log('req_record_info error');
 | 
			
		||||
        },
 | 
			
		||||
        30 * 1000
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
$app.init_and_play = function() {
 | 
			
		||||
    if (_.isNull($app.player_console_term)) {
 | 
			
		||||
        $app.player_console_term = new Terminal({
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,80 @@
 | 
			
		|||
<%!
 | 
			
		||||
    page_title_ = '录像回放'
 | 
			
		||||
%>
 | 
			
		||||
 | 
			
		||||
<%inherit file="../page_single_base.mako"/>
 | 
			
		||||
 | 
			
		||||
<%block name="extend_js_file">
 | 
			
		||||
    ##     <script type="text/javascript" src="${ static_url('plugins/xterm/xterm.js') }"></script>
 | 
			
		||||
 | 
			
		||||
    <script type="text/javascript" src="${ static_url('js/audit/replay-rdp.js') }"></script>
 | 
			
		||||
</%block>
 | 
			
		||||
 | 
			
		||||
<%block name="extend_css_file">
 | 
			
		||||
##     <link href="${ static_url('plugins/xterm/xterm.css') }" rel="stylesheet" type="text/css"/>
 | 
			
		||||
</%block>
 | 
			
		||||
 | 
			
		||||
<%block name="embed_css">
 | 
			
		||||
    <style type="text/css">
 | 
			
		||||
        #screen {
 | 
			
		||||
            margin-top: 5px;
 | 
			
		||||
            ##background-color: #547cff;
 | 
			
		||||
            background-color: #000;
 | 
			
		||||
            border: 1px solid #525252;
 | 
			
		||||
            border-right-color: #fff;
 | 
			
		||||
            border-bottom-color: #fff;
 | 
			
		||||
##             padding: 1px;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
</%block>
 | 
			
		||||
 | 
			
		||||
<%block name="page_header">
 | 
			
		||||
    <div class="container-fluid top-navbar">
 | 
			
		||||
        <div class="breadcrumb-container">
 | 
			
		||||
            <ol class="breadcrumb">
 | 
			
		||||
                <li><i class="fa fa-server"></i> ${self.attr.page_title_}</li>
 | 
			
		||||
                <li class="sub-title"><span id="recorder-info"></span></li>
 | 
			
		||||
            </ol>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</%block>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<div class="page-content">
 | 
			
		||||
    <div id="toolbar" style="display: inline-block;">
 | 
			
		||||
        <button id="btn-play" type="button" class="btn btn-primary btn-sm" style="width:80px;"><i class="fa fa-pause fa-fw"> 暂停</i></button>
 | 
			
		||||
        <button id="btn-restart" type="button" class="btn btn-success btn-sm"><i class="fa fa-refresh fa-fw"></i> 重新播放</button>
 | 
			
		||||
 | 
			
		||||
        <button id="btn-speed" type="button" class="btn btn-info btn-sm" style="width:80px;">正常速度</button>
 | 
			
		||||
 | 
			
		||||
        <button id="btn-big-font" type="button" class="btn btn-default btn-sm"><i class="fa fa-font fa-fw"></i>+</button>
 | 
			
		||||
        <button id="btn-small-font" type="button" class="btn btn-default btn-sm"><i class="fa fa-font fa-fw"></i>-</button>
 | 
			
		||||
 | 
			
		||||
        <div style="display:inline-block;position:relative;top:4px;margin-left:10px;margin-right:15px;">
 | 
			
		||||
            <span id="btn-skip" style="cursor:pointer;"><i class="fa fa-check-square-o fa-fw"></i> 跳过无操作时间</span>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <span id="play-status" class="badge badge-normal" style="margin-left:5px;">正在获取数据</span>
 | 
			
		||||
        <span id="play-time" class="badge badge-success" style="margin-left:5px;">总时长:未知</span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <input id="progress" type="range" value="0" min=0 max=100 style="margin-top: 10px;"/>
 | 
			
		||||
    ##     <div id="xterm-box"></div>
 | 
			
		||||
 | 
			
		||||
    <div id="screen"></div>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<%block name="extend_content">
 | 
			
		||||
 | 
			
		||||
</%block>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<%block name="embed_js">
 | 
			
		||||
    <script type="text/javascript">
 | 
			
		||||
        $app.add_options(${page_param});
 | 
			
		||||
    </script>
 | 
			
		||||
</%block>
 | 
			
		||||
| 
						 | 
				
			
			@ -494,7 +494,8 @@ class ReplayHandler(TPBaseHandler):
 | 
			
		|||
    def get(self, protocol, record_id):
 | 
			
		||||
        protocol = int(protocol)
 | 
			
		||||
        if protocol == TP_PROTOCOL_TYPE_RDP:
 | 
			
		||||
            return
 | 
			
		||||
            param = {'record_id': record_id}
 | 
			
		||||
            self.render('audit/replay-rdp.mako', page_param=json.dumps(param))
 | 
			
		||||
        elif protocol == TP_PROTOCOL_TYPE_SSH:
 | 
			
		||||
            param = {'record_id': record_id}
 | 
			
		||||
            self.render('audit/replay-ssh.mako', page_param=json.dumps(param))
 | 
			
		||||
| 
						 | 
				
			
			@ -603,12 +604,13 @@ class DoGetRecordHeaderHandler(TPBaseJsonHandler):
 | 
			
		|||
            return self.write_json(TPE_JSON_FORMAT)
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            protocol_type = int(args['protocol'])
 | 
			
		||||
            record_id = int(args['id'])
 | 
			
		||||
        except:
 | 
			
		||||
            log.e('\n')
 | 
			
		||||
            return self.write_json(TPE_PARAM)
 | 
			
		||||
 | 
			
		||||
        header, err = record.read_record_head(record_id)
 | 
			
		||||
        header, err = record.read_record_head(protocol_type, record_id)
 | 
			
		||||
        if header is None:
 | 
			
		||||
            return self.write_json(err)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -627,13 +629,19 @@ class DoGetRecordDataHandler(TPBaseJsonHandler):
 | 
			
		|||
            return self.write_json(TPE_JSON_FORMAT)
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            protocol_type = int(args['protocol'])
 | 
			
		||||
            record_id = int(args['id'])
 | 
			
		||||
            offset = int(args['offset'])
 | 
			
		||||
        except:
 | 
			
		||||
            log.e('\n')
 | 
			
		||||
            return self.write_json(TPE_PARAM)
 | 
			
		||||
 | 
			
		||||
        data_list, data_size, err = record.read_record_data(record_id, offset)
 | 
			
		||||
        if protocol_type == TP_PROTOCOL_TYPE_RDP:
 | 
			
		||||
            data_list, data_size, err = record.read_rdp_record_data(record_id, offset)
 | 
			
		||||
        elif protocol_type == TP_PROTOCOL_TYPE_RDP:
 | 
			
		||||
            data_list, data_size, err = record.read_ssh_record_data(record_id, offset)
 | 
			
		||||
        else:
 | 
			
		||||
            self.write_json(TPE_NOT_EXISTS)
 | 
			
		||||
        self.write_json(err, data={'data_list': data_list, 'data_size': data_size})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -114,12 +114,26 @@ def get_records(handler, sql_filter, sql_order, sql_limit, sql_restrict, sql_exc
 | 
			
		|||
    return err, s.total_count, s.recorder
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def read_record_head(record_id):
 | 
			
		||||
def _remove_padding_space(s):
 | 
			
		||||
    r = []
 | 
			
		||||
    for i in range(len(s)):
 | 
			
		||||
        if s[i] == 0x00:
 | 
			
		||||
            break
 | 
			
		||||
        r.append(s[i])
 | 
			
		||||
    return bytearray(r)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def read_record_head(protocol_type, record_id):
 | 
			
		||||
    if not tp_cfg().core.detected:
 | 
			
		||||
        return None, TPE_NO_CORE_SERVER
 | 
			
		||||
 | 
			
		||||
    record_path = os.path.join(tp_cfg().core.replay_path, 'ssh', '{:09d}'.format(int(record_id)))
 | 
			
		||||
    header_file_path = os.path.join(record_path, 'tp-ssh.tpr')
 | 
			
		||||
    if protocol_type == TP_PROTOCOL_TYPE_RDP:
 | 
			
		||||
        path_name = 'rdp'
 | 
			
		||||
    elif protocol_type == TP_PROTOCOL_TYPE_SSH:
 | 
			
		||||
        path_name = 'ssh'
 | 
			
		||||
 | 
			
		||||
    record_path = os.path.join(tp_cfg().core.replay_path, path_name, '{:09d}'.format(int(record_id)))
 | 
			
		||||
    header_file_path = os.path.join(record_path, 'tp-{}.tpr'.format(path_name))
 | 
			
		||||
 | 
			
		||||
    if not os.path.exists(header_file_path):
 | 
			
		||||
        return None, TPE_NOT_EXISTS
 | 
			
		||||
| 
						 | 
				
			
			@ -156,22 +170,22 @@ def read_record_head(record_id):
 | 
			
		|||
        # offset += 4
 | 
			
		||||
 | 
			
		||||
        user_name, = struct.unpack_from('64s', data, offset)
 | 
			
		||||
        user_name = user_name.decode()
 | 
			
		||||
        user_name = _remove_padding_space(user_name).decode()
 | 
			
		||||
        offset += 64
 | 
			
		||||
        account, = struct.unpack_from('64s', data, offset)
 | 
			
		||||
        account = account.decode()
 | 
			
		||||
        account = _remove_padding_space(account).decode()
 | 
			
		||||
        offset += 64
 | 
			
		||||
 | 
			
		||||
        host_ip, = struct.unpack_from('40s', data, offset)
 | 
			
		||||
        host_ip = host_ip.decode()
 | 
			
		||||
        host_ip = _remove_padding_space(host_ip).decode()
 | 
			
		||||
        offset += 40
 | 
			
		||||
        conn_ip, = struct.unpack_from('40s', data, offset)
 | 
			
		||||
        conn_ip = conn_ip.decode()
 | 
			
		||||
        conn_ip = _remove_padding_space(conn_ip).decode()
 | 
			
		||||
        offset += 40
 | 
			
		||||
        conn_port, = struct.unpack_from('H', data, offset)
 | 
			
		||||
        offset += 2
 | 
			
		||||
        client_ip, = struct.unpack_from('40s', data, offset)
 | 
			
		||||
        client_ip = client_ip.decode()
 | 
			
		||||
        client_ip = _remove_padding_space(client_ip).decode()
 | 
			
		||||
        offset += 40
 | 
			
		||||
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
| 
						 | 
				
			
			@ -197,11 +211,82 @@ def read_record_head(record_id):
 | 
			
		|||
    return header, TPE_OK
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def read_record_data(record_id, offset):
 | 
			
		||||
def read_rdp_record_data(record_id, offset):
 | 
			
		||||
    if not tp_cfg().core.detected:
 | 
			
		||||
        return None, TPE_NO_CORE_SERVER
 | 
			
		||||
 | 
			
		||||
    record_path = os.path.join(tp_cfg().core.replay_path, 'rdp', '{:09d}'.format(int(record_id)))
 | 
			
		||||
    file_data = os.path.join(record_path, 'tp-rdp.dat')
 | 
			
		||||
 | 
			
		||||
    if not os.path.exists(file_data):
 | 
			
		||||
        return None, 0, TPE_NOT_EXISTS
 | 
			
		||||
 | 
			
		||||
    data_list = list()
 | 
			
		||||
    data_size = 0
 | 
			
		||||
    file = None
 | 
			
		||||
    try:
 | 
			
		||||
        file_size = os.path.getsize(file_data)
 | 
			
		||||
        if offset >= file_size:
 | 
			
		||||
            return None, 0, TPE_FAILED
 | 
			
		||||
 | 
			
		||||
        file = open(file_data, 'rb')
 | 
			
		||||
        if offset > 0:
 | 
			
		||||
            file.seek(offset, io.SEEK_SET)
 | 
			
		||||
 | 
			
		||||
        # read 1000 packages one time from offset.
 | 
			
		||||
        for i in range(1000):
 | 
			
		||||
            """
 | 
			
		||||
            // 一个数据包的头
 | 
			
		||||
            typedef struct TS_RECORD_PKG
 | 
			
		||||
            {
 | 
			
		||||
                ex_u8 type;			// 包的数据类型
 | 
			
		||||
                ex_u32 size;		// 这个包的总大小(不含包头)
 | 
			
		||||
                ex_u32 time_ms;		// 这个包距起始时间的时间差(毫秒,意味着一个连接不能持续超过49天)
 | 
			
		||||
                ex_u8 _reserve[3];	// 保留
 | 
			
		||||
            }TS_RECORD_PKG;
 | 
			
		||||
            """
 | 
			
		||||
            _data = file.read(12)
 | 
			
		||||
            data_size += 12
 | 
			
		||||
            _action, _size, _time, = struct.unpack_from('=BII', _data)
 | 
			
		||||
            if offset + data_size + _size > file_size:
 | 
			
		||||
                return None, 0, TPE_FAILED
 | 
			
		||||
 | 
			
		||||
            _data = file.read(_size)
 | 
			
		||||
            data_size += _size
 | 
			
		||||
 | 
			
		||||
            temp = dict()
 | 
			
		||||
            temp['a'] = _action
 | 
			
		||||
            temp['t'] = _time
 | 
			
		||||
            if _action == 0x10:
 | 
			
		||||
                # this is mouse movement event.
 | 
			
		||||
                x, y = struct.unpack_from('HH', _data)
 | 
			
		||||
                temp['x'] = x
 | 
			
		||||
                temp['y'] = y
 | 
			
		||||
            elif _action == 0x11:
 | 
			
		||||
                # this is a data package.
 | 
			
		||||
                _data = base64.b64encode(_data)
 | 
			
		||||
                temp['d'] = _data.decode()
 | 
			
		||||
            else:
 | 
			
		||||
                return None, 0, TPE_FAILED
 | 
			
		||||
 | 
			
		||||
            data_list.append(temp)
 | 
			
		||||
            if offset + data_size == file_size:
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
    except Exception:
 | 
			
		||||
        log.e('failed to read record file: {}\n'.format(file_data))
 | 
			
		||||
        return None, 0, TPE_FAILED
 | 
			
		||||
    finally:
 | 
			
		||||
        if file is not None:
 | 
			
		||||
            file.close()
 | 
			
		||||
 | 
			
		||||
    return data_list, data_size, TPE_OK
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def read_ssh_record_data(record_id, offset):
 | 
			
		||||
    if not tp_cfg().core.detected:
 | 
			
		||||
        return None, TPE_NO_CORE_SERVER
 | 
			
		||||
 | 
			
		||||
    # read 1000 packages one time from offset.
 | 
			
		||||
    record_path = os.path.join(tp_cfg().core.replay_path, 'ssh', '{:09d}'.format(int(record_id)))
 | 
			
		||||
    file_data = os.path.join(record_path, 'tp-ssh.dat')
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -220,6 +305,7 @@ def read_record_data(record_id, offset):
 | 
			
		|||
        if offset > 0:
 | 
			
		||||
            file.seek(offset, io.SEEK_SET)
 | 
			
		||||
 | 
			
		||||
        # read 1000 packages one time from offset.
 | 
			
		||||
        for i in range(1000):
 | 
			
		||||
            """
 | 
			
		||||
            // 一个数据包的头
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue