改进sftp操作的历史记录和展示。

pull/105/head
Apex Liu 2017-11-24 01:35:40 +08:00
parent 49708edd3c
commit 13b9a1ef17
5 changed files with 241 additions and 123 deletions

View File

@ -15,6 +15,7 @@ TP_SSH_CHANNEL_PAIR::TP_SSH_CHANNEL_PAIR() {
db_id = 0; db_id = 0;
channel_id = 0; channel_id = 0;
win_width = 0;
is_first_server_data = true; is_first_server_data = true;
server_ready = false; server_ready = false;
@ -630,7 +631,7 @@ void SshSession::_on_client_channel_close(ssh_session session, ssh_channel chann
int SshSession::_on_client_channel_data(ssh_session session, ssh_channel channel, void *data, unsigned int len, int is_stderr, void *userdata) int SshSession::_on_client_channel_data(ssh_session session, ssh_channel channel, void *data, unsigned int len, int is_stderr, void *userdata)
{ {
EXLOG_BIN((ex_u8*)data, len, "on_client_channel_data [is_stderr=%d]:", is_stderr); //EXLOG_BIN((ex_u8*)data, len, "on_client_channel_data [is_stderr=%d]:", is_stderr);
SshSession *_this = (SshSession *)userdata; SshSession *_this = (SshSession *)userdata;
@ -666,10 +667,10 @@ int SshSession::_on_client_channel_data(ssh_session session, ssh_channel channel
_this->_process_ssh_command(cp, TP_SSH_CLIENT_SIDE, (ex_u8*)data, _len); _this->_process_ssh_command(cp, TP_SSH_CLIENT_SIDE, (ex_u8*)data, _len);
ex_astr str(cp->cmd_char_list.begin(), cp->cmd_char_list.end()); // ex_astr str(cp->cmd_char_list.begin(), cp->cmd_char_list.end());
ex_replace_all(str, "\r", ""); // ex_replace_all(str, "\r", "");
ex_replace_all(str, "\n", ""); // ex_replace_all(str, "\n", "");
EXLOGD("[ssh] -- [%s]\n", str.c_str()); // EXLOGD("[ssh] -- [%s]\n", str.c_str());
} }
else { else {
_this->_process_sftp_command(cp, (ex_u8*)data, _len); _this->_process_sftp_command(cp, (ex_u8*)data, _len);
@ -742,7 +743,7 @@ int SshSession::_on_client_channel_exec_request(ssh_session session, ssh_channel
} }
int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel, void *data, unsigned int len, int is_stderr, void *userdata) { int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel, void *data, unsigned int len, int is_stderr, void *userdata) {
EXLOG_BIN((ex_u8*)data, len, "on_server_channel_data [is_stderr=%d]:", is_stderr); //EXLOG_BIN((ex_u8*)data, len, "on_server_channel_data [is_stderr=%d]:", is_stderr);
SshSession *_this = (SshSession *)userdata; SshSession *_this = (SshSession *)userdata;
@ -781,10 +782,10 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel
} }
_this->_process_ssh_command(cp, TP_SSH_SERVER_SIDE, (ex_u8*)data, len); _this->_process_ssh_command(cp, TP_SSH_SERVER_SIDE, (ex_u8*)data, len);
ex_astr str(cp->cmd_char_list.begin(), cp->cmd_char_list.end()); // ex_astr str(cp->cmd_char_list.begin(), cp->cmd_char_list.end());
ex_replace_all(str, "\r", ""); // ex_replace_all(str, "\r", "");
ex_replace_all(str, "\n", ""); // ex_replace_all(str, "\n", "");
EXLOGD("[ssh] -- [%s]\n", str.c_str()); // EXLOGD("[ssh] -- [%s]\n", str.c_str());
cp->rec.record(TS_RECORD_TYPE_SSH_DATA, (unsigned char *)data, len); cp->rec.record(TS_RECORD_TYPE_SSH_DATA, (unsigned char *)data, len);
} }
@ -811,29 +812,15 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel
int w = min(cp->win_width, 128); int w = min(cp->win_width, 128);
ex_astr line(w, '='); ex_astr line(w, '=');
// char line[129] = { 0 };
// for (int i = 0; i < w; ++i)
// line[i] = '=';
// snprintf(buf, sizeof(buf),
// "\r\n\r\n"\
// "=============================================\r\n"\
// "Welcome to Teleport-SSH-Server...\r\n"\
// " - teleport to %s:%d\r\n"\
// " - authroized by %s\r\n"\
// "=============================================\r\n"\
// "\r\n",
// _this->m_conn_ip.c_str(),
// _this->m_conn_port, auth_mode
// );
snprintf(buf, sizeof(buf), snprintf(buf, sizeof(buf),
"\r\n\r\n"\ "\r\n"\
"%s\r\n"\ "%s\r\n"\
"Welcome to Teleport-SSH-Server...\r\n"\ "Teleport SSH Bastion Server...\r\n"\
" - teleport to %s:%d\r\n"\ " - teleport to %s:%d\r\n"\
" - authroized by %s\r\n"\ " - authroized by %s\r\n"\
"%s\r\n"\ "%s\r\n"\
"\r\n", "\r\n\r\n",
line.c_str(), line.c_str(),
_this->m_conn_ip.c_str(), _this->m_conn_ip.c_str(),
_this->m_conn_port, auth_mode, _this->m_conn_port, auth_mode,
@ -854,15 +841,94 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel
} }
#endif #endif
#if 1
// 直接转发数据到客户端
if (is_stderr) if (is_stderr)
ret = ssh_channel_write_stderr(cp->cli_channel, data, len); ret = ssh_channel_write_stderr(cp->cli_channel, data, len);
else else
ret = ssh_channel_write(cp->cli_channel, data, len); ret = ssh_channel_write(cp->cli_channel, data, len);
#else
// 分析收到的服务端数据包,如果包含类似 \033]0;AABB\007 这样的数据,客户端会根据此改变窗口标题
// 我们需要替换这部分数据,使之显示类似 \033]0;TP#ssh://remote-ip\007 这样的标题。
// 但是这样会降低一些性能,因此目前不启用,保留此部分代码备用。
if (is_stderr) {
ret = ssh_channel_write_stderr(cp->cli_channel, data, len);
}
else if (cp->type != TS_SSH_CHANNEL_TYPE_SHELL) {
ret = ssh_channel_write(cp->cli_channel, data, len);
}
else {
if (len > 5 && len < 256) {
const ex_u8* _begin = ex_memmem((const ex_u8*)data, len, (const ex_u8*)"\033]0;", 4);
if (NULL != _begin) {
size_t len_before = _begin - (const ex_u8*)data;
const ex_u8* _end = ex_memmem(_begin + 4, len - len_before, (const ex_u8*)"\007", 1);
if (NULL != _end)
{
_end++;
// 这个包中含有改变标题的数据,将标题换为我们想要的
EXLOGD("-- found title\n");
size_t len_end = len - (_end - (const ex_u8*)data);
MemBuffer mbuf;
if (len_before > 0)
mbuf.append((ex_u8*)data, len_before);
mbuf.append((ex_u8*)"\033]0;TP#ssh://", 13);
mbuf.append((ex_u8*)_this->m_conn_ip.c_str(), _this->m_conn_ip.length());
mbuf.append((ex_u8*)"\007", 1);
if (len_end > 0)
mbuf.append((ex_u8*)_end, len_end);
if (mbuf.size() > 0)
{
for(;;){
ret = ssh_channel_write(cp->cli_channel, mbuf.data(), mbuf.size());
if (ret == SSH_ERROR)
break;
if (ret == mbuf.size()) {
ret = len; // 表示我们已经处理了所有的数据了。
break;
}
else {
mbuf.pop(ret);
ex_sleep_ms(100);
}
}
// if (ret <= 0)
// EXLOGE("[ssh] send to client failed (1).\n");
// else
// ret = len;
}
else
{
ret = ssh_channel_write(cp->cli_channel, data, len);
}
}
else
{
ret = ssh_channel_write(cp->cli_channel, data, len);
}
}
else {
ret = ssh_channel_write(cp->cli_channel, data, len);
}
}
else {
ret = ssh_channel_write(cp->cli_channel, data, len);
}
}
#endif
if (ret == SSH_ERROR) { if (ret == SSH_ERROR) {
EXLOGE("[ssh] send data(%dB) to client failed. [%d][cli:%s][srv:%s]\n", len, ret, ssh_get_error(_this->m_cli_session), ssh_get_error(_this->m_srv_session)); EXLOGE("[ssh] send data(%dB) to client failed. [%d][cli:%s][srv:%s]\n", len, ret, ssh_get_error(_this->m_cli_session), ssh_get_error(_this->m_srv_session));
ssh_channel_close(channel); ssh_channel_close(channel);
} }
else if (ret != len) {
EXLOGW("[ssh] received server data, got %dB, processed %dB.\n", len, ret);
}
_this->m_recving_from_srv = false; _this->m_recving_from_srv = false;
return ret; return ret;
@ -909,8 +975,8 @@ void SshSession::_process_ssh_command(TP_SSH_CHANNEL_PAIR* cp, int from, const e
// 客户端输入回车时,可能时执行了一条命令,需要根据服务端返回的数据进行进一步判断 // 客户端输入回车时,可能时执行了一条命令,需要根据服务端返回的数据进行进一步判断
cp->maybe_cmd = (data[len - 1] == 0x0d); cp->maybe_cmd = (data[len - 1] == 0x0d);
if (cp->maybe_cmd) // if (cp->maybe_cmd)
EXLOGD("[ssh] maybe cmd.\n"); // EXLOGD("[ssh] maybe cmd.\n");
// 有时在执行类似top命令的情况下输入一个字母'q'就退出程序,没有输入回车,可能会导致后续记录命令时将返回的命令行提示符作为命令 // 有时在执行类似top命令的情况下输入一个字母'q'就退出程序,没有输入回车,可能会导致后续记录命令时将返回的命令行提示符作为命令
// 记录下来了,要避免这种情况,排除的方式是:客户端单个字母,后续服务端如果收到的是控制序列 1b 5b xx xx就不计做命令。 // 记录下来了,要避免这种情况,排除的方式是:客户端单个字母,后续服务端如果收到的是控制序列 1b 5b xx xx就不计做命令。
@ -1065,13 +1131,13 @@ void SshSession::_process_ssh_command(TP_SSH_CHANNEL_PAIR* cp, int from, const e
case 0x0d: case 0x0d:
{ {
if (offset + 1 < len && data[offset + 1] == 0x0a) { if (offset + 1 < len && data[offset + 1] == 0x0a) {
if (cp->maybe_cmd) // if (cp->maybe_cmd)
EXLOGD("[ssh] maybe cmd.\n"); // EXLOGD("[ssh] maybe cmd.\n");
if (cp->maybe_cmd) { if (cp->maybe_cmd) {
if (cp->cmd_char_list.size() > 0) if (cp->cmd_char_list.size() > 0)
{ {
ex_astr str(cp->cmd_char_list.begin(), cp->cmd_char_list.end()); ex_astr str(cp->cmd_char_list.begin(), cp->cmd_char_list.end());
EXLOGD("[ssh] --==--==-- save cmd: [%s]\n", str.c_str()); // EXLOGD("[ssh] --==--==-- save cmd: [%s]\n", str.c_str());
cp->rec.record_command(0, str); cp->rec.record_command(0, str);
} }
@ -1113,6 +1179,12 @@ void SshSession::_process_sftp_command(TP_SSH_CHANNEL_PAIR* cp, const ex_u8* dat
// SFTP protocol: https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13 // SFTP protocol: https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13
//EXLOG_BIN(data, len, "[sftp] client channel data"); //EXLOG_BIN(data, len, "[sftp] client channel data");
// TODO: 根据客户端的请求和服务端的返回,可以进一步判断用户是如何操作文件的,比如读、写等等,以及操作的结果是成功还是失败。
// 记录格式: time-offset,flag,action,result,file-path,[file-path]
// 其中flag目前总是为0可以忽略为保证与ssh-cmd格式一致time-offset/action/result 都是数字
// file-path是被操作的对象规格为 长度:实际内容,例如, 13:/root/abc.txt
if (len < 9) if (len < 9)
return; return;
@ -1133,7 +1205,7 @@ void SshSession::_process_sftp_command(TP_SSH_CHANNEL_PAIR* cp, const ex_u8* dat
// pkg_len + cmd + req_id + string( length + content...) // pkg_len + cmd + req_id + string( length + content...)
if (len < 14) if (len < 14)
return; return;
ex_u8* str1_ptr = (ex_u8*)data + 9; ex_u8* str1_ptr = (ex_u8*)data + 9;
int str1_len = (int)((str1_ptr[0] << 24) | (str1_ptr[1] << 16) | (str1_ptr[2] << 8) | str1_ptr[3]); int str1_len = (int)((str1_ptr[0] << 24) | (str1_ptr[1] << 16) | (str1_ptr[2] << 8) | str1_ptr[3]);
// if (str1_len + 9 != pkg_len) // if (str1_len + 9 != pkg_len)
@ -1142,11 +1214,9 @@ void SshSession::_process_sftp_command(TP_SSH_CHANNEL_PAIR* cp, const ex_u8* dat
int str2_len = 0;// (int)((data[9] << 24) | (data[10] << 16) | (data[11] << 8) | data[12]); int str2_len = 0;// (int)((data[9] << 24) | (data[10] << 16) | (data[11] << 8) | data[12]);
const char* act = NULL;
switch (sftp_cmd) { switch (sftp_cmd) {
case 0x03: case 0x03:
// 0x03 = 3 = SSH_FXP_OPEN // 0x03 = 3 = SSH_FXP_OPEN
act = "open file";
break; break;
// case 0x0b: // case 0x0b:
// // 0x0b = 11 = SSH_FXP_OPENDIR // // 0x0b = 11 = SSH_FXP_OPENDIR
@ -1154,27 +1224,22 @@ void SshSession::_process_sftp_command(TP_SSH_CHANNEL_PAIR* cp, const ex_u8* dat
// break; // break;
case 0x0d: case 0x0d:
// 0x0d = 13 = SSH_FXP_REMOVE // 0x0d = 13 = SSH_FXP_REMOVE
act = "remove file";
break; break;
case 0x0e: case 0x0e:
// 0x0e = 14 = SSH_FXP_MKDIR // 0x0e = 14 = SSH_FXP_MKDIR
act = "create dir";
break; break;
case 0x0f: case 0x0f:
// 0x0f = 15 = SSH_FXP_RMDIR // 0x0f = 15 = SSH_FXP_RMDIR
act = "remove dir";
break; break;
case 0x12: case 0x12:
// 0x12 = 18 = SSH_FXP_RENAME // 0x12 = 18 = SSH_FXP_RENAME
// rename操作数据中包含两个字符串 // rename操作数据中包含两个字符串
act = "rename";
str2_ptr = str1_ptr + str1_len + 4; str2_ptr = str1_ptr + str1_len + 4;
str2_len = (int)((str2_ptr[0] << 24) | (str2_ptr[1] << 16) | (str2_ptr[2] << 8) | str2_ptr[3]); str2_len = (int)((str2_ptr[0] << 24) | (str2_ptr[1] << 16) | (str2_ptr[2] << 8) | str2_ptr[3]);
break; break;
case 0x15: case 0x15:
// 0x15 = 21 = SSH_FXP_LINK // 0x15 = 21 = SSH_FXP_LINK
// link操作数据中包含两个字符串前者是新的链接文件名后者是现有被链接的文件名 // link操作数据中包含两个字符串前者是新的链接文件名后者是现有被链接的文件名
act = "create link";
str2_ptr = str1_ptr + str1_len + 4; str2_ptr = str1_ptr + str1_len + 4;
str2_len = (int)((str2_ptr[0] << 24) | (str2_ptr[1] << 16) | (str2_ptr[2] << 8) | str2_ptr[3]); str2_len = (int)((str2_ptr[0] << 24) | (str2_ptr[1] << 16) | (str2_ptr[2] << 8) | str2_ptr[3]);
break; break;
@ -1191,12 +1256,12 @@ void SshSession::_process_sftp_command(TP_SSH_CHANNEL_PAIR* cp, const ex_u8* dat
char msg[2048] = { 0 }; char msg[2048] = { 0 };
if (str2_len == 0) { if (str2_len == 0) {
ex_astr str1((char*)((ex_u8*)data + 13), str1_len); ex_astr str1((char*)((ex_u8*)data + 13), str1_len);
ex_strformat(msg, 2048, "%d:%s:%s:\r\n", sftp_cmd, act, str1.c_str()); ex_strformat(msg, 2048, "%d,%d,%s", sftp_cmd, 0, str1.c_str());
} }
else { else {
ex_astr str1((char*)(str1_ptr + 4), str1_len); ex_astr str1((char*)(str1_ptr + 4), str1_len);
ex_astr str2((char*)(str2_ptr + 4), str2_len); ex_astr str2((char*)(str2_ptr + 4), str2_len);
ex_strformat(msg, 2048, "%d:%s:%s:%s\r\n", sftp_cmd, act, str1.c_str(), str2.c_str()); ex_strformat(msg, 2048, "%d,%d,%s:%s", sftp_cmd, 0, str1.c_str(), str2.c_str());
} }
cp->rec.record_command(0, msg); cp->rec.record_command(0, msg);

View File

@ -8,9 +8,13 @@
</%block> </%block>
<%block name="extend_css"> <%block name="extend_css">
<style type="text/css"> <style type="text/css">
#no-op-msg { #op-box, #no-op-box {
display: none; display: none;
}
#no-op-box {
padding: 20px; padding: 20px;
margin: 50px; margin: 50px;
background-color: #fffed5; background-color: #fffed5;
@ -18,41 +22,68 @@
font-size: 120%; font-size: 120%;
} }
#op-list { #op-list, .op-msg {
display: none;
padding: 20px; padding: 20px;
margin: 20px 10px 20px 10px; margin: 10px;
background-color: #ffffff; background-color: #ffffff;
font-size: 14px; font-size: 13px;
border-radius: 5px; border-radius: 5px;
box-shadow: 1px 1px 2px rgba(0, 0, 0, .2);
} }
.op-item { .op-item {
margin-bottom: 3px; margin: 2px 3px;
padding: 2px 5px;
}
.op-item.bold {
margin-bottom: 5px;
margin-left: -10px;
} }
.time, .cmd, .path { .time, .cmd, .path {
font-family: Consolas, Lucida Console, Monaco, Courier, 'Courier New', monospace; font-family: Consolas, Lucida Console, Monaco, Courier, 'Courier New', monospace;
font-size:13px;
line-height: 15px; line-height: 15px;
padding: 0 5px; padding: 2px 5px;
border-radius: 3px; border-radius: 3px;
} }
.time { .time {
margin-right: 15px; margin-right: 15px;
background-color: #d8d8d8; background-color: #ececec;
}
.time.multi, .cmd-multi {
background-color: #fff2cb;
} }
.path { .path {
margin:0 5px 0 5px; margin: 0 5px 0 5px;
background-color: #dbffff;
}
.cmd {
display: inline-block;
} }
.cmd-danger { .cmd-danger {
background-color: #ffbba6; background-color: #ffd2c2;
font-weight: bold; font-weight: bold;
} }
.cmd-danger:before {
display: block;
position: relative;
width: 16px;
float: left;
margin-right: 3px;
margin-top: 0px;
color: #ff533e;
font-size: 16px;
content: "\f06a";
font-family: 'FontAwesome';
}
.cmd-info { .cmd-info {
background-color: #b4fdb1; background-color: #b4fdb1;
} }
@ -71,59 +102,89 @@
</%block> </%block>
<div class="page-content"> <div class="page-content">
<div id="no-op-msg"> <div id="no-op-box">
他悄悄地来,又悄悄地走,挥一挥衣袖,没有留下任何操作~~~~ 他悄悄地来,又悄悄地走,挥一挥衣袖,没有留下任何操作~~~~
</div> </div>
<div id="op-list"></div> <div id="op-box">
<div id="op-list"></div>
<div class="op-msg">
<div class="op-item bold">图例说明:</div>
## <div class="op-item"><span class="time multi">YYYY-mm-dd HH:MM:SS</span> <span class="cmd cmd-multi">此记录可能是被复制粘贴到SSH客户端的有可能是批量执行命令也可能是在做文本编辑详情见录像回放。</span></div>
<div class="op-item"><span class="time">YYYY-mm-dd HH:MM:SS</span> <span class="cmd cmd-danger">此命令可能是危险操作。</span></div>
</div>
</div>
</div> </div>
<%block name="embed_js"> <%block name="embed_js">
<script type="text/javascript"> <script type="text/javascript">
"use strict";
var SSH_FXP_OPEN = 3;
var SSH_FXP_REMOVE = 13;
var SSH_FXP_MKDIR = 14;
var SSH_FXP_RMDIR = 15;
var SSH_FXP_RENAME = 18;
var SSH_FXP_LINK = 21;
$app.add_options(${page_param}); $app.add_options(${page_param});
$app.on_init = function (cb_stack, cb_args) { $app.on_init = function (cb_stack, cb_args) {
$app.dom = {
rec_info: $('#recorder-info')
, no_op_box: $('#no-op-box')
, op_box: $('#op-box')
, op_list: $('#op-list')
};
console.log($app.options); console.log($app.options);
var header = $app.options.header; var header = $app.options.header;
$('#recorder-info').html(tp_format_datetime(header.start) + ': ' + header.user_name + '@' + header.client_ip + ' 访问 ' + header.account + '@' + header.conn_ip + ':' + header.conn_port); $app.dom.rec_info.html(tp_format_datetime(header.start) + ': ' + header.user_name + '@' + header.client_ip + ' 访问 ' + header.account + '@' + header.conn_ip + ':' + header.conn_port);
if ($app.options.count === 0) { var op = $app.options.op;
$('#no-op-msg').show(); if (op.length === 0) {
} else { $app.dom.no_op_box.show();
var dom_op_list = $('#op-list'); cb_stack.exec();
var html = []; return;
for (var i = 0; i < $app.options.count; i++) {
html.push('<div class="op-item"><span class="time">' + $app.options.op[i].t + '</span> ');
if ($app.options.op[i].c === '3') {
html.push('<span class="cmd">打开文件</span>');
html.push('<span class="path">' + $app.options.op[i].p1 + '</span>');
} else if ($app.options.op[i].c === '13') {
html.push('<span class="cmd cmd-danger">删除文件</span>');
html.push('<span class="path cmd-danger">' + $app.options.op[i].p1 + '</span>');
} else if ($app.options.op[i].c === '14') {
html.push('<span class="cmd">创建目录</span>');
html.push('<span class="path">' + $app.options.op[i].p1 + '</span>');
} else if ($app.options.op[i].c === '15') {
html.push('<span class="cmd cmd-danger">删除目录</span>');
html.push('<span class="path cmd-danger">' + $app.options.op[i].p1 + '</span>');
} else if ($app.options.op[i].c === '18') {
html.push('<span class="cmd cmd-info">更改名称</span>');
html.push('<span class="path cmd-info">' + $app.options.op[i].p1 + '</span>');
html.push('<i class="fa fa-arrow-circle-right"></i>');
html.push('<span class="path cmd-info">' + $app.options.op[i].p2 + '</span>');
} else if ($app.options.op[i].c === '21') {
html.push('<span class="cmd">创建链接</span>');
html.push('<span class="path">' + $app.options.op[i].p2 + '</span>');
html.push('<i class="fa fa-arrow-right"></i>');
html.push('<span class="path">' + $app.options.op[i].p1 + '</span>');
}
html.push('</div>');
}
dom_op_list.append(html.join(''));
dom_op_list.show();
} }
var html = [];
html.push('<div class="op-item bold">操作历史记录:</div>');
for (var i = 0; i < op.length; i++) {
var t = tp_format_datetime(header.start + parseInt(op[i].t / 1000));
html.push('<div class="op-item"><span class="time">' + t + '</span> ');
if (op[i].c === 3) {
html.push('<span class="cmd">打开文件</span>');
html.push('<span class="path">' + op[i].p1 + '</span>');
} else if (op[i].c === 13) {
html.push('<span class="cmd cmd-danger">删除文件</span>');
html.push('<span class="path">' + op[i].p1 + '</span>');
} else if (op[i].c === 14) {
html.push('<span class="cmd">创建目录</span>');
html.push('<span class="path">' + op[i].p1 + '</span>');
} else if (op[i].c === 15) {
html.push('<span class="cmd cmd-danger">删除目录</span>');
html.push('<span class="path">' + op[i].p1 + '</span>');
} else if (op[i].c === 18) {
html.push('<span class="cmd cmd-info">更改名称</span>');
html.push('<span class="path">' + op[i].p1 + '</span>');
html.push(' <i class="fa fa-long-arrow-right fa-fw"></i> ');
html.push('<span class="path">' + op[i].p2 + '</span>');
} else if (op[i].c === 21) {
html.push('<span class="cmd">创建链接</span>');
html.push('<span class="path">' + op[i].p2 + '</span>');
html.push(' <i class="fa fa-arrow-right fa-fw"></i> ');
html.push('<span class="path">' + op[i].p1 + '</span>');
}
html.push('</div>');
}
$app.dom.op_list.append(html.join(''));
$app.dom.op_box.show();
cb_stack.exec(); cb_stack.exec();
}; };
</script> </script>

View File

@ -9,11 +9,11 @@
<%block name="extend_css"> <%block name="extend_css">
<style type="text/css"> <style type="text/css">
#err-box, #op-box, #no-msg-box { #err-box, #op-box, #no-op-box {
display: none; display: none;
} }
#no-msg-box { #no-op-box {
padding: 20px; padding: 20px;
margin: 50px; margin: 50px;
background-color: #fffed5; background-color: #fffed5;
@ -102,7 +102,7 @@
错误原因:<span id="err-more-info" class="bold"></span> 错误原因:<span id="err-more-info" class="bold"></span>
</div> </div>
</div> </div>
<div id="no-msg-box"> <div id="no-op-box">
他悄悄地来,又悄悄地走,挥一挥衣袖,没有留下任何操作~~~~ 他悄悄地来,又悄悄地走,挥一挥衣袖,没有留下任何操作~~~~
</div> </div>
<div id="op-box"> <div id="op-box">
@ -117,6 +117,7 @@
<%block name="embed_js"> <%block name="embed_js">
<script type="text/javascript"> <script type="text/javascript">
"use strict";
$app.add_options(${page_param}); $app.add_options(${page_param});
@ -130,7 +131,7 @@
, rec_info: $('#recorder-info') , rec_info: $('#recorder-info')
, err_box: $('#err-box') , err_box: $('#err-box')
, err_more: $('#err-more-info') , err_more: $('#err-more-info')
, no_msg_box: $('#no-op-msg') , no_op_box: $('#no-op-box')
, op_box: $('#op-box') , op_box: $('#op-box')
, op_list: $('#op-list') , op_list: $('#op-list')
}; };
@ -151,7 +152,7 @@
var op = $app.options.op; var op = $app.options.op;
if (op.length === 0) { if (op.length === 0) {
$app.dom.no_msg_box.show(); $app.dom.no_op_box.show();
cb_stack.exec(); cb_stack.exec();
return; return;
} }

View File

@ -136,6 +136,11 @@
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-md-4">
<ul class="list"> <ul class="list">
<li>微信小程序
<ul class="list">
<li><a href="javascript:;" data-switch="wechat"><i class="fa fa-wechat fa-fw"></i> 二次验证码</a> <span class="label label-success">推荐</span></li>
</ul>
</li>
<li>谷歌身份验证器 <li>谷歌身份验证器
<ul class="list"> <ul class="list">
<li><a href="javascript:;" data-switch="g-ios-appstore"><i class="fa fa-apple fa-fw"></i> iOSApple Store</a></li> <li><a href="javascript:;" data-switch="g-ios-appstore"><i class="fa fa-apple fa-fw"></i> iOSApple Store</a></li>
@ -149,11 +154,6 @@
<li><a href="javascript:;" data-switch="mi-android-mi"><i class="fa fa-android fa-fw"></i> Android小米应用商店</a></li> <li><a href="javascript:;" data-switch="mi-android-mi"><i class="fa fa-android fa-fw"></i> Android小米应用商店</a></li>
</ul> </ul>
</li> </li>
<li>微信小程序
<ul class="list">
<li><a href="javascript:;" data-switch="wechat"><i class="fa fa-wechat fa-fw"></i> 二次验证码</a> <span class="label label-success">推荐</span></li>
</ul>
</li>
</ul> </ul>
</div> </div>
<div class="col-md-8"> <div class="col-md-8">

View File

@ -201,7 +201,7 @@ class ComandLogHandler(TPBaseHandler):
file = open(file_info, 'r') file = open(file_info, 'r')
data = file.readlines() data = file.readlines()
for i in range(len(data)): for i in range(len(data)):
cmd = data[i].split(',', 2) cmd = data[i].rstrip('\r\n').split(',', 2)
if len(cmd) != 3: if len(cmd) != 3:
continue continue
if 0 == i: if 0 == i:
@ -215,13 +215,20 @@ class ComandLogHandler(TPBaseHandler):
if cmd_type == 0: if cmd_type == 0:
param['op'].append({'t': t, 'f': f, 'c': cmd[2]}) param['op'].append({'t': t, 'f': f, 'c': cmd[2]})
else: else:
cmd_info = cmd[2].split(':') cmd_info = cmd[2].split(',', 2)
if len(cmd_info) != 4: if len(cmd_info) != 3:
continue continue
param['op'].append({'t': t, 'c': cmd[2], 'p1': cmd_info[2], 'p2': cmd_info[3]}) c = int(cmd_info[0])
r = int(cmd_info[1])
p = cmd_info[2].split(':')
p1 = p[0]
p2 = ''
if len(p) > 1:
p2 = p[1]
param['op'].append({'t': t, 'c': c, 'r': r, 'p1': p1, 'p2': p2})
except: except:
pass pass
param['count'] = len(param['op']) # param['count'] = len(param['op'])
if cmd_type == 0: if cmd_type == 0:
self.render('audit/record-ssh-cmd.mako', page_param=json.dumps(param)) self.render('audit/record-ssh-cmd.mako', page_param=json.dumps(param))
@ -277,19 +284,3 @@ class DoGetRecordDataHandler(TPBaseJsonHandler):
data_list, data_size, err = record.read_record_data(record_id, offset) data_list, data_size, err = record.read_record_data(record_id, offset)
self.write_json(err, data={'data_list': data_list, 'data_size': data_size}) self.write_json(err, data={'data_list': data_list, 'data_size': data_size})
# class DeleteLog(TPBaseAdminAuthJsonHandler):
# # TODO: 用户可能会批量删除大量录像文件因此io操作可能会比较耗时这里应该改为异步方式。
# def post(self):
# args = self.get_argument('args', None)
# if args is not None:
# args = json.loads(args)
# else:
# return self.write_json(-1, '参数错误')
#
# log_list = args['log_list']
#
# if not record.delete_log(log_list):
# return self.write_json(-3, '操作失败')
#
# return self.write_json(0)