配置远程账号时可以不设置密码,让用户在进行远程连接时手动输入。

feature/assist-websocket
Apex Liu 2022-05-29 03:46:34 +08:00
parent fef0e95846
commit 5c286811c9
35 changed files with 827 additions and 517 deletions

View File

@ -21,7 +21,7 @@
"name": "securecrt",
"display": "SecureCRT",
"app": "/Applications/SecureCRT.app/Contents/MacOS/SecureCRT",
"cmdline": "/T /N \"TP#ssh://{real_ip}\" /SSH2 /L {user_name} /PASSWORD **** {host_ip}:{host_port}",
"cmdline": "/T /N \"TP#ssh://{real_ip}\" /SSH2 /L {user_name} {password:/PASSWORD ****} {host_ip}:{host_port}",
"desc": []
},
{
@ -41,14 +41,14 @@
"name": "securefx",
"display": "SecureFX",
"app": "/Applications/SecureFX.app/Contents/MacOS/SecureFX",
"cmdline": "sftp://{user_name}:****@{host_ip}:{host_port}",
"cmdline": "sftp://{user_name}{password::****}@{host_ip}:{host_port}",
"desc": []
},
{
"name": "filezilla",
"display": "FileZilla",
"app": "/Applications/FileZilla.app/Contents/MacOS/filezilla",
"cmdline": "sftp://{user_name}:****@{host_ip}:{host_port}",
"cmdline": "{interactive:-l ask} sftp://{user_name}{password::****}@{host_ip}:{host_port}",
"desc": []
},
{

View File

@ -6,28 +6,28 @@
"name": "putty",
"display": "PuTTY内置",
"app": "{assist_tools_path}\\putty\\putty.exe",
"cmdline": "-ssh -pw **** -P {host_port} -l {user_name} {host_ip}",
"cmdline": "-ssh {password:-pw ****} -P {host_port} -l {user_name} {host_ip}",
"desc": []
},
{
"name": "crt",
"display": "SecureCRT",
"app": "",
"cmdline": "/T /N \"TP#ssh://{real_ip}\" /SSH2 /P {host_port} /PASSWORD **** {user_name}@{host_ip}",
"cmdline": "/T /N \"TP#ssh://{real_ip}\" /SSH2 /P {host_port} {password:/PASSWORD ****} {user_name}@{host_ip}",
"desc": []
},
{
"name": "xshell",
"display": "Xshell",
"app": "",
"cmdline": "-newtab \"TP#ssh://{real_ip}\" -url ssh://{user_name}:****@{host_ip}:{host_port}",
"cmdline": "-newtab \"TP#ssh://{real_ip}\" -url ssh://{user_name}{password::****}@{host_ip}:{host_port}",
"desc": []
},
{
"name": "mobaxterm",
"display": "MobaXterm",
"app": "",
"cmdline": "-newtab \"sshpass -p**** ssh {user_name}@{host_ip} -p {host_port}\"",
"cmdline": "-newtab \"sshpass {password:-p****} ssh {user_name}@{host_ip} -p {host_port}\"",
"desc": []
},
{
@ -45,7 +45,7 @@
"name": "winscp",
"display": "WinSCP内置",
"app": "{assist_tools_path}\\winscp\\winscp.exe",
"cmdline": "/sessionname=\"TP#{real_ip}\" {user_name}:****@{host_ip}:{host_port}",
"cmdline": "/sessionname=\"TP#{real_ip}\" {user_name}{password::****}@{host_ip}:{host_port}",
"desc": []
},
{
@ -100,4 +100,4 @@
],
"selected": "mstsc"
}
}
}

View File

@ -1,11 +1,11 @@
on scriptRun(argsCmd, argsProfile, argsTitle)
on scriptRun(argsCmd, argsProfile, argsTitle, argsInteractiveMode)
set theCmd to (argsCmd)
set theProfile to (argsProfile)
set theTitle to (argsTitle)
CommandRun(theCmd, theProfile, theTitle)
CommandRun(theCmd, theProfile, theTitle, argsInteractiveMode)
end scriptRun
on CommandRun(theCmd, theProfile, theTitle)
on CommandRun(theCmd, theProfile, theTitle, theInteractiveMode)
try
tell application "iTerm"
if it is not running then
@ -29,8 +29,10 @@ on CommandRun(theCmd, theProfile, theTitle)
set name to theTitle
set profile to theProfile
write text theCmd
delay 0.5
write text ""
if theInteractiveMode = "no" then
delay 0.5
write text ""
end if
end tell
end tell
end tell
@ -50,8 +52,10 @@ on CommandRun(theCmd, theProfile, theTitle)
delay 0.5
set name to theTitle
write text theCmd
delay 0.5
write text ""
if theInteractiveMode = "no" then
delay 0.5
write text ""
end if
end tell
end tell
end tell
@ -70,8 +74,10 @@ on CommandRun(theCmd, theProfile, theTitle)
delay 0.5
set name to theTitle
write text theCmd
delay 0.5
write text ""
if theInteractiveMode = "no" then
delay 0.5
write text ""
end if
end tell
end tell
end tell

View File

@ -1,26 +1,29 @@
on scriptRun(argsCmd, argsProfile, argsTitle)
on scriptRun(argsCmd, argsProfile, argsTitle, argsInteractiveMode)
set theCmd to (argsCmd)
set theProfile to (argsProfile)
set theTitle to (argsTitle)
CommandRun(theCmd, theProfile, theTitle)
CommandRun(theCmd, theProfile, theTitle, argsInteractiveMode)
end scriptRun
on CommandRun(theCmd, theProfile, theTitle)
on CommandRun(theCmd, theProfile, theTitle, theInteractiveMode)
try
tell application "Terminal"
if it is not running then
--if this is the first time Terminal is running you have specify window 1
--if you dont do this you will get two windows and the title wont be set
activate
activate
delay 3.0
set newTerm to do script theCmd in window 1
set newTerm's current settings to settings set theProfile
set newTerm's current settings to settings set theProfile
set custom title of front window to theTitle
delay 1.0
reopen
activate
tell application "System Events" to key code 36
if theInteractiveMode = "no"
delay 1.0
reopen
activate
tell application "System Events" to key code 36
end if
else
--Terminal is running get the window count
set windowCount to (count every window)
@ -31,26 +34,26 @@ on CommandRun(theCmd, theProfile, theTitle)
activate
do script theCmd in window 1
set current settings of selected tab of front window to settings set theProfile
set title displays custom title of front window to true
set custom title of selected tab of front window to theTitle
delay 1.0
reopen
activate
tell application "System Events" to key code 36
if theInteractiveMode = "no"
delay 1.0
reopen
activate
tell application "System Events" to key code 36
end if
else
--Terminal is running and we have a window run in a new tab
delay 1.0
reopen
activate
tell application "System Events"
tell process "Terminal"
delay 0.5
keystroke "t" using {command down}
end tell
-- Command+T = new tab.
key code 17 using {command down}
end tell
reopen
@ -61,16 +64,14 @@ on CommandRun(theCmd, theProfile, theTitle)
set title displays custom title of front window to true
set custom title of selected tab of front window to theTitle
delay 1.0
reopen
activate
tell application "System Events" to key code 36
if theInteractiveMode = "no"
delay 1.0
reopen
activate
tell application "System Events" to key code 36
end if
end if
--set current settings of selected tab of front window to settings set theProfile
--set title displays custom title of front window to true
--set custom title of selected tab of front window to theTitle
end if
end tell

View File

@ -12,7 +12,7 @@
extern void* g_app;
int AppDelegate_start_ssh_client (void *_self, const char* cmd_line, const char* term_type, const char* term_theme, const char* term_title);
int AppDelegate_start_ssh_client (void *_self, const char* cmd_line, const char* term_type, const char* term_theme, const char* term_title, const char* interactive_mode);
int AppDelegate_select_app (void *_self);
// for cpp global object initialize.

View File

@ -29,13 +29,14 @@
@implementation AppDelegate
int AppDelegate_start_ssh_client (void *_self, const char* cmd_line, const char* term_type, const char* term_theme, const char* term_title) {
int AppDelegate_start_ssh_client (void *_self, const char* cmd_line, const char* term_type, const char* term_theme, const char* term_title, const char* interactive_mode) {
NSString* cmdLine = [NSString stringWithUTF8String:cmd_line];
NSString* termType = [NSString stringWithUTF8String:term_type];
NSString* termTheme = [NSString stringWithUTF8String:term_theme];
NSString* termTitle = [NSString stringWithUTF8String:term_title];
NSString* interactiveMode = [NSString stringWithUTF8String:interactive_mode];
return [(__bridge id)_self start_ssh_client:cmdLine termType:termType termTheme:termTheme termTitle:termTitle];
return [(__bridge id)_self start_ssh_client:cmdLine termType:termType termTheme:termTheme termTitle:termTitle interactiveMode:interactiveMode];
}
int AppDelegate_select_app (void *_self) {
@ -118,14 +119,14 @@ int AppDelegate_select_app (void *_self) {
}
}
- (int) start_ssh_client:(NSString*)cmd_line termType:(NSString*)term_type termTheme:(NSString*)term_theme termTitle:(NSString*)term_title {
- (int) start_ssh_client:(NSString*)cmd_line termType:(NSString*)term_type termTheme:(NSString*)term_theme termTitle:(NSString*)term_title interactiveMode:(NSString*)interactive_mode {
NSString *term = [[NSBundle mainBundle] pathForResource:term_type ofType:@"scpt"];
if(!term)
return 1;
NSString *handlerName = @"scriptRun";
NSArray *passParameters = @[cmd_line, term_theme, term_title];
NSArray *passParameters = @[cmd_line, term_theme, term_title, interactive_mode];
[self runScript:term handler:handlerName parameters:passParameters];
return 0;

View File

@ -31,49 +31,49 @@ void TsWsClient::url_scheme_handler(const std::string& url)
{
// e.g.:
// url: teleport://register?param={"ws_url":"ws://127.0.0.1:7190/ws/assist/","assist_id":1234,"session_id":"tp_5678"}
EXLOGV("url-schema: %s\n", url.c_str());
std::string protocol;
std::string method;
std::string param;
std::string::size_type pos_protocol = url.find("://");
if (pos_protocol == std::string::npos)
{
EXLOGE("[ws] invalid url: %s\n", url.c_str());
return;
}
std::string::size_type pos_method = url.find('?');
if (pos_method == std::string::npos)
{
EXLOGE("[ws] invalid url: %s\n", url.c_str());
return;
}
protocol.assign(url, 0, pos_protocol);
if (protocol != "teleport")
{
EXLOGE("[ws] invalid protocol: %s\n", protocol.c_str());
return;
}
method.assign(url, pos_protocol + 3, pos_method - pos_protocol - 3);
if(method.empty())
{
EXLOGE("[ws] no method, what should I do now?\n");
return;
}
param.assign(url, pos_method + 7); // ?param=
if (param.empty())
{
EXLOGE("[ws] invalid protocol: %s\n", protocol.c_str());
return;
}
// decode param with url-decode.
size_t len = param.length() * 2;
ex_chars sztmp;
@ -85,13 +85,13 @@ void TsWsClient::url_scheme_handler(const std::string& url)
return;
}
param = &sztmp[0];
EXLOGV("[rpc] method=%s, json_param=%s\n", method.c_str(), param.c_str());
Json::CharReaderBuilder jcrb;
std::unique_ptr<Json::CharReader> const jreader(jcrb.newCharReader());
const char* str_json_begin = param.c_str();
Json::Value js_root;
ex_astr err;
if (!jreader->parse(str_json_begin, str_json_begin + param.length(), &js_root, &err))
@ -104,7 +104,7 @@ void TsWsClient::url_scheme_handler(const std::string& url)
EXLOGE("[ws] invalid param, need json object: %s\n", param.c_str());
return;
}
if (method == "register")
{
_process_register(param, js_root);
@ -127,18 +127,18 @@ void TsWsClient::url_scheme_handler(const std::string& url)
void TsWsClient::_process_register(const std::string& param, Json::Value& js_root)
{
// {"ws_url":"ws://127.0.0.1:7190/ws/assist/","assist_id":1234,"session_id":"tp_5678"}
// check param
if (!js_root["ws_url"].isString() || !js_root["assist_id"].isNumeric() || !js_root["session_id"].isString())
{
EXLOGE("[ws] invalid param: %s\n", param.c_str());
return;
}
std::string ws_url = js_root["ws_url"].asCString();
uint32_t assist_id = js_root["assist_id"].asUInt();
std::string session_id = js_root["session_id"].asCString();
std::string protocol;
protocol.assign(ws_url, 0, 5);
if (protocol == "ws://" || protocol == "wss:/")
@ -155,7 +155,7 @@ void TsWsClient::_process_register(const std::string& param, Json::Value& js_roo
void TsWsClient::_process_run(const std::string& param, Json::Value& js_root)
{
// wrapper for _rpc_func_run_client().
Json::Value js_param;
js_param["method"] = "run";
js_param["param"] = js_root;
@ -168,7 +168,7 @@ void TsWsClient::_process_run(const std::string& param, Json::Value& js_root)
void TsWsClient::_process_replay_rdp(const std::string& param, Json::Value& js_root)
{
// wrapper for _rpc_func_replay_rdp().
Json::Value js_param;
js_param["method"] = "replay_rdp";
js_param["param"] = js_root;
@ -181,9 +181,9 @@ void TsWsClient::_process_replay_rdp(const std::string& param, Json::Value& js_r
// ============================================================================
TsWsClient::TsWsClient() :
ExThreadBase("ws-client-thread"),
m_nc(NULL),
m_assist_id(0)
ExThreadBase("ws-client-thread"),
m_nc(NULL),
m_assist_id(0)
{
mg_mgr_init(&m_mg_mgr, NULL);
}
@ -199,7 +199,7 @@ void TsWsClient::_thread_loop(void)
{
mg_mgr_poll(&m_mg_mgr, 500);
}
EXLOGV("[ws] main loop end.\n");
}
@ -207,23 +207,23 @@ void TsWsClient::_register(const std::string& ws_url, uint32_t assist_id, const
{
if (m_assist_id == 0)
m_assist_id = assist_id;
ex_wstr w_ver(TP_ASSIST_VER);
ex_astr a_ver;
ex_wstr2astr(w_ver, a_ver);
//
char msg[256] = {0};
ex_strformat(
msg, 256, "{\"type\":0,\"method\":\"register\",\"param\":{\"client\":\"assist\",\"sid\":\"%s\",\"request_assist_id\":%u,\"assist_id\":%u,\"assist_ver\":\"%s\"}}",
session_id.c_str(), assist_id, m_assist_id, a_ver.c_str());
msg, 256, "{\"type\":0,\"method\":\"register\",\"param\":{\"client\":\"assist\",\"sid\":\"%s\",\"request_assist_id\":%u,\"assist_id\":%u,\"assist_ver\":\"%s\"}}",
session_id.c_str(), assist_id, m_assist_id, a_ver.c_str());
if (!m_is_running)
{
// not start yet.
std::string url = ws_url;
url += msg;
m_nc = mg_connect_ws(&m_mg_mgr, _mg_event_handler, url.c_str(), NULL, NULL);
if (!m_nc)
{
@ -231,12 +231,12 @@ void TsWsClient::_register(const std::string& ws_url, uint32_t assist_id, const
return;
}
m_nc->user_data = this;
start();
return;
}
EXLOGV("[ws] send: %s\n", msg);
mg_send_websocket_frame(m_nc, WEBSOCKET_OP_TEXT, msg, strlen(msg));
}
@ -250,60 +250,60 @@ void TsWsClient::_mg_event_handler(struct mg_connection* nc, int ev, void* ev_da
EXLOGE("[ERROR] invalid request.\n");
return;
}
switch (ev)
{
case MG_EV_CONNECT:
{
int status = *((int*)ev_data);
if (status != 0)
case MG_EV_CONNECT:
{
EXLOGE("[ERROR] -- connect to ws server failed: %d\n", status);
int status = *((int*)ev_data);
if (status != 0)
{
EXLOGE("[ERROR] -- connect to ws server failed: %d\n", status);
}
break;
}
break;
}
case MG_EV_WEBSOCKET_HANDSHAKE_DONE:
{
auto* hm = (struct http_message*)ev_data;
if (hm->resp_code == 101)
case MG_EV_WEBSOCKET_HANDSHAKE_DONE:
{
EXLOGV("-- ws server connected\n");
auto* hm = (struct http_message*)ev_data;
if (hm->resp_code == 101)
{
EXLOGV("-- ws server connected\n");
}
else
{
EXLOGE("[ERROR] -- connect to ws server failed, HTTP code: %d\n", hm->resp_code);
}
break;
}
else
case MG_EV_WEBSOCKET_FRAME:
{
EXLOGE("[ERROR] -- connect to ws server failed, HTTP code: %d\n", hm->resp_code);
// on_message().
auto* wm = (struct websocket_message*)ev_data;
// EXLOGV("%d: %s\n", wm->size, wm->data);
std::string message;
message.assign((const char*)wm->data, wm->size);
std::string buf;
_this->_on_message(message, buf);
if (!buf.empty())
{
mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, buf.c_str(), buf.length());
}
break;
}
break;
}
case MG_EV_WEBSOCKET_FRAME:
{
// on_message().
auto* wm = (struct websocket_message*)ev_data;
// EXLOGV("%d: %s\n", wm->size, wm->data);
std::string message;
message.assign((const char*)wm->data, wm->size);
std::string buf;
_this->_on_message(message, buf);
if (!buf.empty())
case MG_EV_CLOSE:
{
mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, buf.c_str(), buf.length());
EXLOGV("-- ws server disconnected\n");
_this->m_need_stop = true;
break;
}
break;
}
case MG_EV_CLOSE:
{
EXLOGV("-- ws server disconnected\n");
_this->m_need_stop = true;
break;
}
}
}
@ -328,7 +328,7 @@ void TsWsClient::_create_response(ex_astr& buf, const AssistMessage& msg_ret, in
js_ret["code"] = err_code;
js_ret["message"] = message;
js_ret["data"] = data;
Json::StreamWriterBuilder jwb;
jwb["indentation"] = ""; // 压缩格式,没有换行和不必要的空白字符
std::unique_ptr<Json::StreamWriter> js_writer(jwb.newStreamWriter());
@ -349,15 +349,15 @@ void TsWsClient::_on_message(const std::string& message, std::string& buf)
// "protocol_sub_type":200,"protocol_flag":4294967295
// }
// }
EXLOGV("on_message: %s\n", message.c_str());
AssistMessage msg_req;
Json::CharReaderBuilder jrb;
std::unique_ptr<Json::CharReader> const js_reader(jrb.newCharReader());
const char* str_json_begin = message.c_str();
Json::Value js_root;
ex_astr err;
if (!js_reader->parse(str_json_begin, str_json_begin + message.length(), &js_root, &err))
@ -370,40 +370,40 @@ void TsWsClient::_on_message(const std::string& message, std::string& buf)
_create_response(buf, msg_req, TPE_PARAM);
return;
}
if (js_root["type"].isNull() || !js_root["type"].isInt())
{
_create_response(buf, msg_req, TPE_PARAM);
return;
}
int cmd_type = js_root["type"].asInt();
if (!(cmd_type == MESSAGE_TYPE_REQUEST || cmd_type == MESSAGE_TYPE_RESPONSE))
{
_create_response(buf, msg_req, TPE_PARAM);
return;
}
// 收到的信息已经是“返回值”了,说明已经是一条命令的结束了,不用继续处理
// todo: 可能需要记录日志,或者展示结果。
if (cmd_type == MESSAGE_TYPE_RESPONSE)
return;
if (js_root["method"].isNull() || !js_root["method"].isString() || js_root["command_id"].isNull() || !js_root["command_id"].isInt())
{
_create_response(buf, msg_req, TPE_PARAM);
return;
}
msg_req.command_id = js_root["command_id"].asInt();
msg_req.method = js_root["method"].asString();
if (msg_req.command_id == 0 || msg_req.method.empty())
{
_create_response(buf, msg_req, TPE_PARAM);
return;
}
if (msg_req.method == "run")
{
_rpc_func_run_client(buf, msg_req, js_root);
@ -436,7 +436,7 @@ void TsWsClient::_rpc_func_get_config(ex_astr& buf, AssistMessage& msg_req, Json
Json::Value& ret = g_cfg.get_root();
if(ret["os_type"].isNull())
ret["os_type"] = "macos";
_create_response(buf, msg_req, TPE_OK, "", ret);
}
@ -448,12 +448,12 @@ void TsWsClient::_rpc_func_set_config(ex_astr& buf, AssistMessage& msg_req, Json
return;
}
Json::Value& js_param = js_root["param"];
Json::StreamWriterBuilder jwb;
std::unique_ptr<Json::StreamWriter> js_writer(jwb.newStreamWriter());
ex_aoss os;
js_writer->write(js_param, &os);
if (!g_cfg.save(os.str()))
_create_response(buf, msg_req, TPE_FAILED);
else
@ -476,26 +476,26 @@ void TsWsClient::_rpc_func_replay_rdp(ex_astr& buf, AssistMessage& msg_req, Json
// "sid":"tp_1622707094_1c8e4fd4006c6ad5"
// }
// }
if (js_root["param"].isNull() || !js_root["param"].isObject())
{
_create_response(buf, msg_req, TPE_PARAM);
return;
}
Json::Value& js_param = js_root["param"];
// check param
if (!js_param["rid"].isNumeric()
|| !js_param["web"].isString()
|| !js_param["sid"].isString()
)
)
{
_create_response(buf, msg_req, TPE_PARAM);
return;
}
ex_astrs s_argv;
ex_wstr w_exec_file = g_env.m_bundle_path;
ex_path_join(w_exec_file, false, L"Contents", L"Resources", L"tp-player.app", L"Contents", L"MacOS", L"tp-player", nullptr);
// ex_path_join(w_exec_file, false, L"tp-player.app", L"Contents", L"MacOS", L"tp-player", nullptr);
@ -503,16 +503,16 @@ void TsWsClient::_rpc_func_replay_rdp(ex_astr& buf, AssistMessage& msg_req, Json
ex_wstr2astr(w_exec_file, exec_file);
s_argv.push_back(exec_file);
int rid = js_param["rid"].asInt();
ex_astr a_url_base = js_param["web"].asCString();
ex_astr a_sid = js_param["sid"].asCString();
char cmd_args[1024] = { 0 };
ex_strformat(cmd_args, 1023, "%s/%s/%d", a_url_base.c_str(), a_sid.c_str(), rid);
s_argv.push_back(cmd_args);
ex_wstr w_cmd_args;
ex_astr2wstr(cmd_args, w_cmd_args);
@ -520,47 +520,47 @@ void TsWsClient::_rpc_func_replay_rdp(ex_astr& buf, AssistMessage& msg_req, Json
ex_strformat(total_cmd, 1023, "%s %s", exec_file.c_str(), cmd_args);
Json::Value js_ret;
ex_astr utf8_path;
//ex_wstr2astr(total_cmd, utf8_path, EX_CODEPAGE_UTF8);
js_ret["cmdline"] = total_cmd;
// EXLOGD(utf8_path.c_str());
// for macOS, Create Process should be fork()/exec()...
int ret_code = TPE_OK;
pid_t processId;
if ((processId = fork()) == 0) {
int i = 0;
char** _argv = (char**)calloc(s_argv.size()+1, sizeof(char*));
if (!_argv)
return;
for (i = 0; i < s_argv.size(); ++i)
{
_argv[i] = ex_strdup(s_argv[i].c_str());
}
_argv[i] = NULL;
execv(exec_file.c_str(), _argv);
for(i = 0; i < s_argv.size(); ++i) {
if(_argv[i] != NULL) {
free(_argv[i]);
}
}
free(_argv);
} else if (processId < 0) {
ret_code = TPE_FAILED;
} else {
ret_code = TPE_OK;
}
// _create_json_ret(buf, root_ret);
_create_response(buf, msg_req, ret_code, "", js_ret);
}
void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json::Value& js_root)
@ -573,71 +573,84 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json
// "protocol_sub_type":200,"protocol_flag":4294967295
// }
// }
if (js_root["param"].isNull() || !js_root["param"].isObject())
{
_create_response(buf, msg_req, TPE_PARAM);
return;
}
Json::Value& js_param = js_root["param"];
// check param
if (!js_param["teleport_ip"].isString()
|| !js_param["teleport_port"].isNumeric() || !js_param["remote_host_ip"].isString()
|| !js_param["session_id"].isString() || !js_param["protocol_type"].isNumeric() || !js_param["protocol_sub_type"].isNumeric()
|| !js_param["protocol_flag"].isNumeric()
)
)
{
_create_response(buf, msg_req, TPE_PARAM);
return;
}
const char* interactive_mode = "no";
bool is_interactive_mode = false;
if(!js_param["is_interactive"].isNull()) {
if(!js_param["is_interactive"].isBool()) {
_create_response(buf, msg_req, TPE_PARAM);
return;
}
if(js_param["is_interactive"].asBool()) {
interactive_mode = "yes";
is_interactive_mode = true;
}
}
int pro_type = js_param["protocol_type"].asUInt();
int pro_sub = js_param["protocol_sub_type"].asInt();
ex_u32 protocol_flag = js_param["protocol_flag"].asUInt();
ex_astr teleport_ip = js_param["teleport_ip"].asCString();
int teleport_port = js_param["teleport_port"].asUInt();
char _port[64] = {0};
ex_strformat(_port, 64, "%d", teleport_port);
ex_astr str_teleport_port = _port;
ex_astr real_host_ip = js_param["remote_host_ip"].asCString();
ex_astr real_host_name = js_param["remote_host_name"].asCString();
ex_astr sid = js_param["session_id"].asCString();
ex_astr s_exec;
ex_astr s_arg;
ex_astrs s_argv;
if (pro_type == TP_PROTOCOL_TYPE_RDP)
{
//==============================================
// RDP
//==============================================
if (g_cfg.rdp.application.length() == 0)
{
_create_response(buf, msg_req, TPE_NOT_EXISTS, "助手未配置本地RDP客户端请检查您的助手设置。");
return;
}
if (!ex_is_file_exists(g_cfg.rdp.application.c_str()))
{
_create_response(buf, msg_req, TPE_NOT_EXISTS, "无法定位助手配置的RDP客户端请检查您的助手设置。");
return;
}
bool flag_clipboard = ((protocol_flag & TP_FLAG_RDP_CLIPBOARD) == TP_FLAG_RDP_CLIPBOARD);
bool flag_disk = ((protocol_flag & TP_FLAG_RDP_DISK) == TP_FLAG_RDP_DISK);
bool flag_console = ((protocol_flag & TP_FLAG_RDP_CONSOLE) == TP_FLAG_RDP_CONSOLE);
int rdp_w = 800;
int rdp_h = 640;
bool rdp_console = false;
if (!js_param["rdp_width"].isNull())
{
if (js_param["rdp_width"].isNumeric())
@ -650,7 +663,7 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json
return;
}
}
if (!js_param["rdp_height"].isNull())
{
if (js_param["rdp_height"].isNumeric())
@ -663,7 +676,7 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json
return;
}
}
if (!js_param["rdp_console"].isNull())
{
if (js_param["rdp_console"].isBool())
@ -676,11 +689,11 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json
return;
}
}
if (!flag_console)
rdp_console = false;
size_t split_pos = sid.length() - 2;
ex_astr real_sid = sid.substr(0, split_pos);
ex_astr str_pwd_len = sid.substr(split_pos, sid.length());
@ -692,9 +705,9 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json
{
szPwd[i] = '*';
}
//ex_astr2wstr(real_sid, w_sid);
//w_exe_path = _T("\"");
//w_exe_path += g_cfg.rdp_app + _T("\" ");
//w_exe_path += g_cfg.rdp_cmdline;
@ -704,10 +717,10 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json
//s_exec = "/usr/local/Cellar/freerdp/1.0.2_1/bin/xfreerdp";
s_exec = g_cfg.rdp.application;
s_arg = g_cfg.rdp.cmdline;
sid = "02" + real_sid;
// s_argv.push_back("/f");
s_argv.push_back("/sec:tls");
s_argv.push_back("-wallpaper");
s_argv.push_back("-themes");
@ -715,20 +728,20 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json
s_argv.push_back("/cert-ignore");
// Automatically accept certificate on first connect
s_argv.push_back("/cert-tofu");
ex_astr _tmp_pass = "/p:PLACEHOLDER";
//_tmp_pass += szPwd;
s_argv.push_back(_tmp_pass);
//#if 0
//s_argv.push_back(s_exec.c_str());
{
// ex_astr username = "02" + real_sid;
// s_argv.push_back("/u:");
// s_argv.push_back(username.c_str());
if (rdp_w == 0 || rdp_h == 0)
{
s_argv.push_back("/f");
@ -742,20 +755,20 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json
char sz_width[64] = {0};
ex_strformat(sz_width, 63, "/w:%d", rdp_w);
s_argv.push_back(sz_width);
char sz_height[64] = {0};
ex_strformat(sz_height, 63, "/h:%d", rdp_h);
s_argv.push_back(sz_height);
}
if (flag_console && rdp_console)
s_argv.push_back("/admin");
// if(flag_clipboard)
// s_argv.push_back("+clipboard");
// else
// s_argv.push_back("-clipboard");
// if(flag_disk)
// s_argv.push_back("+drives");
// else
@ -774,52 +787,52 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json
//==============================================
// SSH
//==============================================
if (pro_sub == TP_PROTOCOL_TYPE_SSH_SHELL)
{
if (g_cfg.ssh.name == "terminal" || g_cfg.ssh.name == "iterm2")
{
char szCmd[1024] = {0};
ex_strformat(szCmd, 1023, "ssh %s@%s -p %d -o \"StrictHostKeyChecking no\"", sid.c_str(), teleport_ip.c_str(), teleport_port);
char szTitle[128] = {0};
ex_strformat(szTitle, 127, "TP#%s", real_host_ip.c_str());
int ret = AppDelegate_start_ssh_client(g_app, szCmd, g_cfg.ssh.name.c_str(), g_cfg.ssh.cmdline.c_str(), szTitle);
int ret = AppDelegate_start_ssh_client(g_app, szCmd, g_cfg.ssh.name.c_str(), g_cfg.ssh.cmdline.c_str(), szTitle, interactive_mode);
if (ret == 0)
_create_response(buf, msg_req, TPE_OK);
else
_create_response(buf, msg_req, TPE_FAILED);
return;
}
if (g_cfg.ssh.application.length() == 0)
{
_create_response(buf, msg_req, TPE_NOT_EXISTS);
return;
}
s_exec = g_cfg.ssh.application;
s_argv.push_back(s_exec.c_str());
s_arg = g_cfg.ssh.cmdline;
}
else
{
// sorry, SFTP not supported yet for macOS.
// _create_json_ret(buf, TPE_NOT_IMPLEMENT);
// return;
if (g_cfg.sftp.application.length() == 0)
{
_create_response(buf, msg_req, TPE_NOT_EXISTS);
return;
}
s_exec = g_cfg.sftp.application;
s_argv.push_back(s_exec.c_str());
s_arg = g_cfg.sftp.cmdline;
}
}
@ -828,46 +841,96 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json
//==============================================
// TELNET
//==============================================
// sorry, TELNET not supported yet for macOS.
// _create_json_ret(buf, TPE_NOT_IMPLEMENT);
// return;
g_cfg.telnet.name = "iterm2";
if (g_cfg.telnet.name == "terminal" || g_cfg.telnet.name == "iterm2")
{
char szCmd[1024] = {0};
ex_strformat(szCmd, 1023, "telnet -l %s %s %d", sid.c_str(), teleport_ip.c_str(), teleport_port);
char szTitle[128] = {0};
ex_strformat(szTitle, 127, "TP#%s", real_host_ip.c_str());
int ret = AppDelegate_start_ssh_client(g_app, szCmd, g_cfg.telnet.name.c_str(), g_cfg.telnet.cmdline.c_str(), szTitle);
int ret = AppDelegate_start_ssh_client(g_app, szCmd, g_cfg.telnet.name.c_str(), g_cfg.telnet.cmdline.c_str(), szTitle, interactive_mode);
if (ret == 0)
_create_response(buf, msg_req, TPE_OK);
else
_create_response(buf, msg_req, TPE_FAILED);
return;
}
if (g_cfg.telnet.application.length() == 0)
{
_create_response(buf, msg_req, TPE_NOT_EXISTS);
return;
}
s_exec = g_cfg.telnet.application;
s_argv.push_back(s_exec.c_str());
s_arg = g_cfg.telnet.cmdline;
}
//---- split s_arg and push to s_argv ---
ex_astr::size_type p1 = 0;
ex_astr::size_type p2 = 0;
ex_astr tmp = s_arg;
ex_astr tmp;
for(;;){
p1 = s_arg.find("{password:");
if(p1 != ex_astr::npos) {
p2 = s_arg.find('}', p1+10);
if(p2 == ex_astr::npos) {
_create_response(buf, msg_req, TPE_PARAM);
return;
}
if(is_interactive_mode) {
// 如果需要用户自己输入密码,则客户端命令行就不能带密码字段,需要抹去这个参数
s_arg.erase(p1, p2-p1+1);
}
else{
s_arg.erase(p2, 1);
s_arg.erase(p1, 10);
}
}
else
{
break;
}
}
for(;;){
p1 = s_arg.find("{interactive:");
if(p1 != ex_astr::npos) {
p2 = s_arg.find('}', p1+13);
if(p2 == ex_astr::npos) {
_create_response(buf, msg_req, TPE_PARAM);
return;
}
if(!is_interactive_mode) {
// 如果无需用户自己输入密码,则需要抹去这个参数
s_arg.erase(p1, p2-p1+1);
}
else{
s_arg.erase(p2, 1);
s_arg.erase(p1, 13);
}
}
else
{
break;
}
}
tmp = s_arg;
for (;;)
{
ex_remove_white_space(tmp, EX_RSC_BEGIN);
@ -875,48 +938,48 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json
{
break;
}
if (tmp[0] == '"')
{
p1 = 1;
p2 = tmp.find('"', p1);
if (p2 == ex_astr::npos)
{
_create_response(buf, msg_req, TPE_PARAM);
return;
}
ex_astr _t;
_t.assign(tmp, p1, p2 - p1);
tmp.erase(0, p2 + 2);
s_argv.push_back(_t);
}
else
{
p1 = 0;
p2 = tmp.find(' ', p1);
if (p2 == ex_astr::npos)
{
s_argv.push_back(tmp);
tmp.clear();
break;
}
ex_astr _t;
_t.assign(tmp, p1, p2 - p1);
tmp.erase(0, p2 + 1);
s_argv.push_back(_t);
}
}
Json::Value js_data;
ex_astr utf8_path = s_exec;
ex_astrs::iterator it = s_argv.begin();
for (; it != s_argv.end(); ++it)
{
@ -926,31 +989,31 @@ void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json
ex_replace_all((*it), "{real_ip}", real_host_ip);
ex_replace_all((*it), "{host_name}", real_host_name);
//ex_replace_all(utf8_path, _T("{assist_tools_path}"), g_env.m_tools_path.c_str());
utf8_path += " ";
utf8_path += (*it);
}
js_data["path"] = utf8_path;
// for macOS, Create Process should be fork()/exec()...
pid_t processId;
if ((processId = fork()) == 0)
{
int i = 0;
char** _argv = (char**)calloc(s_argv.size() + 1, sizeof(char*));
if (!_argv)
return;
for (i = 0; i < s_argv.size(); ++i)
{
_argv[i] = ex_strdup(s_argv[i].c_str());
}
_argv[i] = NULL;
execv(s_exec.c_str(), _argv);
for (i = 0; i < s_argv.size(); ++i)
{
if (_argv[i] != NULL)

View File

@ -440,7 +440,7 @@ void TsHttpRpc::_rpc_func_enc(const Json::Value& json_param, ex_astr& buf)
is_enc = false;
plain_text = json_param["p"].asCString();
if (plain_text.length() == 0)
if (plain_text.empty())
{
_create_json_ret(buf, TPE_PARAM);
return;

View File

@ -4,6 +4,9 @@
#include <mbedtls/sha1.h>
#include <teleport_const.h>
// 临时会话ID有效期毫秒
#define TEMP_SESSION_ID_VALID_TIME 60000
TsSessionManager g_session_mgr;
TsSessionManager::TsSessionManager() :
@ -44,7 +47,7 @@ void TsSessionManager::_remove_expired_connect_info()
for (; it != m_connections.end();)
{
//EXLOGD("[core] check expired connect info: [%s] %d, %d %d %d\n", it->first.c_str(), it->second->ref_count, int(_now), int(it->second->ticket_start), int(_now - it->second->ticket_start));
if (it->second->ref_count == 0 && _now - 15000 > it->second->ticket_start)
if (it->second->ref_count == 0 && _now - TEMP_SESSION_ID_VALID_TIME > it->second->ticket_start)
{
EXLOGD("[core] remove connection info, because timeout: %s\n", it->first.c_str());
delete it->second;
@ -100,7 +103,8 @@ bool TsSessionManager::free_connect_info(const ex_astr& sid)
it->second->ref_count--;
// 对于RDP来说此时不要移除连接信息系统自带RDP客户端在第一次连接时进行协议协商然后马上会断开之后立即重新连接一次第二次连接之前可能会提示证书信息如果用户长时间不操作可能会导致超时
// 对于RDP来说此时不要移除连接信息系统自带RDP客户端在第一次连接时进行协议协商然后马上会断开之后立即重新连接
// 一次(第二次连接之前可能会提示证书信息,如果用户长时间不操作,可能会导致超时)。
// 因此,我们将其引用计数减低,并更新一下最后访问时间,让定时器来移除它。
if (it->second->protocol_type != TP_PROTOCOL_TYPE_RDP)
{
@ -116,10 +120,10 @@ bool TsSessionManager::free_connect_info(const ex_astr& sid)
{
if (it->second->ref_count == 1)
it->second->ref_count = 0;
it->second->ticket_start = ex_get_tick_count() + 45000; // 我们将时间向后移动45秒这样如果没有发生RDP的第二次连接这个连接信息就会在一分钟后被清除。
// 我们将启动时间向后一段这样如果没有发生RDP的第二次连接这个连接信息过一会儿就会被清除。
it->second->ticket_start = ex_get_tick_count() + TEMP_SESSION_ID_VALID_TIME;
}
return true;
}

View File

@ -60,7 +60,7 @@ int ts_web_rpc_get_conn_info(int conn_id, TS_CONNECT_INFO& info)
EXLOGE("[core] get conn info from web-server failed: can not connect to web-server.\n");
return TPE_NETWORK;
}
if (body.length() == 0)
if (body.empty())
{
EXLOGE("[core] get conn info from web-server failed: got nothing.\n");
return TPE_NETWORK;
@ -191,10 +191,10 @@ int ts_web_rpc_get_conn_info(int conn_id, TS_CONNECT_INFO& info)
// 注意account_id可以为-1表示这是一次测试连接。
// if (user_id <= 0 || host_id <= 0
// ||
if (user_username.length() == 0
|| host_ip.length() == 0 || conn_ip.length() == 0 || client_ip.length() == 0
if (user_username.empty()
|| host_ip.empty() || conn_ip.empty() || client_ip.empty()
|| conn_port <= 0 || conn_port >= 65535
|| acc_username.length() == 0
|| acc_username.empty()
|| !(protocol_type == TP_PROTOCOL_TYPE_RDP || protocol_type == TP_PROTOCOL_TYPE_SSH || protocol_type == TP_PROTOCOL_TYPE_TELNET)
|| !(auth_type == TP_AUTH_TYPE_NONE || auth_type == TP_AUTH_TYPE_PASSWORD || auth_type == TP_AUTH_TYPE_PRIVATE_KEY)
)
@ -202,10 +202,14 @@ int ts_web_rpc_get_conn_info(int conn_id, TS_CONNECT_INFO& info)
return TPE_PARAM;
}
if (auth_type != TP_AUTH_TYPE_NONE && acc_secret.length() == 0)
{
// 认证方式为密码时,允许不设置密码,而是连接时由用户手动输入
if(acc_secret.empty() && !(auth_type == TP_AUTH_TYPE_NONE || auth_type == TP_AUTH_TYPE_PASSWORD))
return TPE_PARAM;
}
// if (auth_type != TP_AUTH_TYPE_NONE && acc_secret.length() == 0)
// {
// return TPE_PARAM;
// }
if (_enc && !acc_secret.empty())
{

View File

@ -15,8 +15,8 @@ SshSession::SshSession(SshProxy* proxy, ssh_session rs_tp2cli, uint32_t dbg_id,
m_conn_info(nullptr),
m_conn_port(0),
m_flags(0),
m_auth_type(TP_AUTH_TYPE_NONE),
m_allow_user_input_password(false)
m_auth_type(TP_AUTH_TYPE_NONE)
// , m_allow_user_input_password(false)
{
ex_strformat(m_dbg_name, 128, "ssh-%d", dbg_id);
ex_strformat(m_dbg_client, 128, "%s:%d", client_ip, client_port);
@ -455,6 +455,7 @@ int SshSession::_on_auth_password_request(ssh_session /*session*/, const char* u
int SshSession::_do_auth(const char* user, const char* secret)
{
EXLOGD("[%s] authenticating, user: %s\n", m_dbg_name.c_str(), user);
// EXLOGD("[%s] authenticating, user: %s, secret: %s\n", m_dbg_name.c_str(), user, secret);
// v3.6.0
// 场景
@ -591,12 +592,12 @@ int SshSession::_do_auth(const char* user, const char* secret)
if (m_acc_secret.empty())
{
// 如果TP中未设置远程账号密码表示允许用户自行输入密码
m_allow_user_input_password = true;
// m_allow_user_input_password = true;
// 如果传入的password为特定值应该是由助手调用客户端填写的密码
// 直接返回认证失败,这样客户端会让用户输入密码
if (0 == strcmp(secret, "INTERACTIVE_USER"))
return SSH_AUTH_DENIED;
// // 如果传入的password为特定值应该是由助手调用客户端填写的密码
// // 直接返回认证失败,这样客户端会让用户输入密码
// if (0 == strcmp(secret, "INTERACTIVE_USER"))
// return SSH_AUTH_DENIED;
// 用户脱离TP-WEB直接使用客户端输入的密码
m_acc_secret = secret;
@ -761,7 +762,7 @@ int SshSession::_do_auth(const char* user, const char* secret)
// about 'echo':
// This is an optional variable. You can obtain a boolean if the user input should be echoed or
// hidden. For passwords it is usually hidden.
// hidden. For password it is usually hidden.
EXLOGV("[%s] interactive login prompt(%s): %s\n", m_dbg_name.c_str(), echo ? "hidden" : "not hidden", prompt);
if (echo)

View File

@ -151,7 +151,7 @@ private:
std::string m_acc_secret;
uint32_t m_flags;
int m_auth_type;
bool m_allow_user_input_password;
// bool m_allow_user_input_password;
bool m_first_auth;
// 远程主机认证是否通过

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -33,7 +33,7 @@ $app.create_controls = function (cb_stack) {
//-------------------------------
// 主机列表表格
//-------------------------------
var table_host_options = {
let table_host_options = {
dom_id: 'table-host',
data_source: {
type: 'ajax-post',
@ -190,7 +190,7 @@ $app.create_controls = function (cb_stack) {
$app.dom.dlg_import_asset.modal({backdrop: 'static'});
});
$app.dom.chkbox_host_select_all.click(function () {
var _objects = $('#' + $app.table_host.dom_id + ' tbody').find('[data-check-box]');
let _objects = $('#' + $app.table_host.dom_id + ' tbody').find('[data-check-box]');
if ($(this).is(':checked')) {
$.each(_objects, function (i, _obj) {
$(_obj).prop('checked', true);
@ -227,8 +227,8 @@ $app.on_table_host_cell_created = function (tbl, row_id, col_key, cell_obj) {
} else if (col_key === 'action') {
// 绑定系统选择框事件
cell_obj.find('[data-action]').click(function () {
var host = $app.table_host.get_row(row_id);
var action = $(this).attr('data-action');
let host = $app.table_host.get_row(row_id);
let action = $(this).attr('data-action');
if (action === 'edit') {
$app.dlg_edit_host.show_edit(row_id);
} else if (action === 'account') {
@ -265,12 +265,12 @@ $app.on_table_host_cell_created = function (tbl, row_id, col_key, cell_obj) {
$app.on_table_host_render_created = function (render) {
render.filter_state = function (header, title, col) {
var _ret = ['<div class="tp-table-filter tp-table-filter-' + col.cell_align + '">'];
let _ret = ['<div class="tp-table-filter tp-table-filter-' + col.cell_align + '">'];
_ret.push('<div class="tp-table-filter-inner">');
_ret.push('<div class="search-title">' + title + '</div>');
// 表格内嵌过滤器的DOM实体在这时生成
var filter_ctrl = header._table_ctrl.get_filter_ctrl('state');
let filter_ctrl = header._table_ctrl.get_filter_ctrl('state');
_ret.push(filter_ctrl.render());
_ret.push('</div></div>');
@ -279,12 +279,12 @@ $app.on_table_host_render_created = function (render) {
};
render.filter_search = function (header, title, col) {
var _ret = ['<div class="tp-table-filter tp-table-filter-input">'];
let _ret = ['<div class="tp-table-filter tp-table-filter-input">'];
_ret.push('<div class="tp-table-filter-inner">');
_ret.push('<div class="search-title">' + title + '</div>');
// 表格内嵌过滤器的DOM实体在这时生成
var filter_ctrl = header._table_ctrl.get_filter_ctrl('search');
let filter_ctrl = header._table_ctrl.get_filter_ctrl('search');
_ret.push(filter_ctrl.render());
_ret.push('</div></div>');
@ -297,7 +297,7 @@ $app.on_table_host_render_created = function (render) {
};
render.host_info = function (row_id, fields) {
var title, sub_title;
let title, sub_title;
title = fields.name;
sub_title = fields.ip;
@ -306,7 +306,7 @@ $app.on_table_host_render_created = function (render) {
title = fields.ip;
}
var desc = [];
let desc = [];
if (fields.desc.length > 0) {
desc.push(fields.desc.replace(/\r/ig, "").replace(/\n/ig, "<br/>"));
}
@ -314,7 +314,7 @@ $app.on_table_host_render_created = function (render) {
sub_title += ',由 ' + fields.router_ip + ':' + fields.router_port + ' 路由';
}
var ret = [];
let ret = [];
// ret.push('<div><span class="host-name" href="javascript:;">' + title + '</span>');
// if (desc.length > 0) {
// ret.push('<a class="host-id-desc" data-toggle="popover" data-placement="right"');
@ -347,9 +347,9 @@ $app.on_table_host_render_created = function (render) {
};
render.host_state = function (row_id, fields) {
var _style, _state;
let i, _style, _state;
for (var i = 0; i < $app.obj_states.length; ++i) {
for (i = 0; i < $app.obj_states.length; ++i) {
if ($app.obj_states[i].id === fields.state) {
_style = $app.obj_states[i].style;
_state = $app.obj_states[i].name;
@ -365,7 +365,7 @@ $app.on_table_host_render_created = function (render) {
};
render.host_alive = function (row_id, fields) {
var _style, _alive;
let _style, _alive;
if (fields.alive === -1) {
_style = 'alive-unknown';
@ -391,7 +391,7 @@ $app.on_table_host_render_created = function (render) {
_alive = '正在检测';
}
var ret = [];
let ret = [];
ret.push('<div><a class="alive ' + _style + '" data-toggle="popover" data-placement="left"');
ret.push(' data-html="true"');
@ -403,7 +403,7 @@ $app.on_table_host_render_created = function (render) {
};
render.make_host_action_btn = function (row_id, fields) {
var h = [];
let h = [];
h.push('<div class="btn-group btn-group-sm">');
h.push('<button type="button" class="btn btn-no-border dropdown-toggle" data-toggle="dropdown">');
h.push('<span data-selected-action>操作</span> <i class="fa fa-caret-right"></i></button>');
@ -433,7 +433,7 @@ $app.on_table_host_header_created = function (header) {
});
// TODO: 当过滤器不是默认值时,让“重置过滤器按钮”有呼吸效果,避免用户混淆 - 实验性质
// var t1 = function(){
// let t1 = function(){
// $app.dom.btn_table_host_reset_filter.fadeTo(1000, 1.0, function(){
// $app.dom.btn_table_host_reset_filter.fadeTo(1000, 0.2, t1);
// });
@ -447,8 +447,8 @@ $app.on_table_host_header_created = function (header) {
};
$app.check_host_all_selected = function (cb_stack) {
var _all_checked = true;
var _objs = $('#' + $app.table_host.dom_id + ' tbody').find('[data-check-box]');
let _all_checked = true;
let _objs = $('#' + $app.table_host.dom_id + ' tbody').find('[data-check-box]');
if (_objs.length === 0) {
_all_checked = false;
} else {
@ -472,15 +472,15 @@ $app.check_host_all_selected = function (cb_stack) {
$app.on_btn_select_file_click = function () {
var html = '<input id="file-selector" type="file" name="csvfile" accept=".csv,text/csv,text/comma-separated-values" class="hidden" value="" style="display: none;"/>';
let html = '<input id="file-selector" type="file" name="csvfile" accept=".csv,text/csv,text/comma-separated-values" class="hidden" value="" style="display: none;"/>';
$('body').after($(html));
var btn_file_selector = $("#file-selector");
let btn_file_selector = $("#file-selector");
btn_file_selector.change(function () {
$app.dom.upload_file_message.hide();
// var dom_file_name = $('#upload-file-name');
// let dom_file_name = $('#upload-file-name');
var file = null;
let file = null;
if (btn_file_selector[0].files && btn_file_selector[0].files[0]) {
file = btn_file_selector[0].files[0];
} else if (btn_file_selector[0].files && btn_file_selector[0].files.item(0)) {
@ -492,7 +492,7 @@ $app.on_btn_select_file_click = function () {
return;
}
var _ext = file.name.substring(file.name.lastIndexOf('.')).toLocaleLowerCase();
let _ext = file.name.substring(file.name.lastIndexOf('.')).toLocaleLowerCase();
if (_ext !== '.csv') {
$app.dom.upload_file_info.html('抱歉,仅支持导入 csv 格式的文件!');
return;
@ -503,7 +503,7 @@ $app.on_btn_select_file_click = function () {
return;
}
var fileInfo = '';
let fileInfo = '';
fileInfo += file.name;
fileInfo += '<br/>';
fileInfo += tp_size2str(file.size, 2);
@ -526,7 +526,7 @@ $app.on_btn_do_upload_click = function () {
.show();
var param = {};
let param = {};
$.ajaxFileUpload({
url: "/asset/upload-import",// 需要链接到服务器地址
fileElementId: "file-selector", // 文件选择框的id属性
@ -538,7 +538,7 @@ $app.on_btn_do_upload_click = function () {
console.log(data);
$('#file-selector').remove();
var ret = JSON.parse(data);
let ret = JSON.parse(data);
console.log(ret);
if (ret.code === TPE_OK) {
@ -549,10 +549,10 @@ $app.on_btn_do_upload_click = function () {
$app.table_host.load_data();
} else {
var err_msg = ['<i class="far fa-times-circle fa-fw"></i> 资产导入失败:' + ret.message];
let err_msg = ['<i class="far fa-times-circle fa-fw"></i> 资产导入失败:' + ret.message];
if (!_.isUndefined(ret.data)) {
err_msg.push('<div style="max-height:280px;overflow:auto;margin-left:20px;">');
var err_lines = [];
let err_lines = [];
$.each(ret.data, function (i, item) {
err_lines.push('第' + item.line + '行:' + item.error);
});
@ -580,11 +580,11 @@ $app.show_user_info = function (row_id) {
};
$app.get_selected_host = function (tbl) {
var items = [];
var _objs = $('#' + $app.table_host.dom_id + ' tbody tr td input[data-check-box]');
let items = [];
let _objs = $('#' + $app.table_host.dom_id + ' tbody tr td input[data-check-box]');
$.each(_objs, function (i, _obj) {
if ($(_obj).is(':checked')) {
var _row_data = tbl.get_row(_obj);
let _row_data = tbl.get_row(_obj);
// _all_checked = false;
items.push(_row_data.id);
}
@ -609,7 +609,7 @@ $app._lock_hosts = function (host_ids) {
};
$app.on_btn_lock_host_click = function () {
var items = $app.get_selected_host($app.table_host);
let items = $app.get_selected_host($app.table_host);
if (items.length === 0) {
$tp.notify_error('请选择要禁用的主机!');
return;
@ -635,7 +635,7 @@ $app._unlock_hosts = function (host_ids) {
};
$app.on_btn_unlock_host_click = function () {
var items = $app.get_selected_host($app.table_host);
let items = $app.get_selected_host($app.table_host);
if (items.length === 0) {
$tp.notify_error('请选择要解禁的主机!');
return;
@ -645,7 +645,7 @@ $app.on_btn_unlock_host_click = function () {
};
$app._remove_hosts = function (host_ids) {
var _fn_sure = function (cb_stack) {
let _fn_sure = function (cb_stack) {
$tp.ajax_post_json('/asset/update-hosts', {action: 'remove', hosts: host_ids},
function (ret) {
if (ret.code === TPE_OK) {
@ -665,7 +665,7 @@ $app._remove_hosts = function (host_ids) {
);
};
var cb_stack = CALLBACK_STACK.create();
let cb_stack = CALLBACK_STACK.create();
$tp.dlg_confirm(cb_stack, {
msg: '<div class="alert alert-danger"><p><strong>注意:删除操作不可恢复!!</strong></p><p>删除主机将同时删除与之相关的账号,并将主机和账号从所在分组中移除,同时删除所有相关授权!</p></div><p>如果您希望临时禁止登录指定主机,可将其“禁用”!</p><p>您确定要移除选定的' + host_ids.length + '个主机吗?</p>',
fn_yes: _fn_sure
@ -673,7 +673,7 @@ $app._remove_hosts = function (host_ids) {
};
$app.on_btn_remove_host_click = function () {
var items = $app.get_selected_host($app.table_host);
let items = $app.get_selected_host($app.table_host);
if (items.length === 0) {
$tp.notify_error('请选择要删除的主机!');
return;
@ -683,7 +683,7 @@ $app.on_btn_remove_host_click = function () {
};
$app.create_dlg_edit_host = function () {
var dlg = {};
let dlg = {};
dlg.dom_id = 'dlg-edit-host';
dlg.field_id = -1; // 主机id仅编辑模式
// dlg.field_type = -1;
@ -716,7 +716,7 @@ $app.create_dlg_edit_host = function () {
};
dlg.init = function (cb_stack) {
var html = [];
let html = [];
// // 创建类型选择框
// html.push('<button type="button" class="btn btn-sm dropdown-toggle" data-toggle="dropdown">');
// html.push('<span data-selected-type>选择主机类型</span> <i class="fa fa-caret-right"></i></button>');
@ -730,10 +730,10 @@ $app.create_dlg_edit_host = function () {
//
// // 绑定类型选择框事件
// $('#' + dlg.dom_id + ' li a[data-type-selector]').click(function () {
// var select = parseInt($(this).attr('data-type-selector'));
// let select = parseInt($(this).attr('data-type-selector'));
// if (dlg.field_type === select)
// return;
// var name = $app.id2name($app.host_types, select);
// let name = $app.id2name($app.host_types, select);
// if (_.isUndefined(name)) {
// name = '选择主机类型角色';
// dlg.field_type = -1;
@ -772,9 +772,9 @@ $app.create_dlg_edit_host = function () {
};
dlg.init_fields = function (host) {
// var type_name = '选择主机类型';
// let type_name = '选择主机类型';
// dlg.field_type = -1;
// var os_name = '选择操作系统';
// let os_name = '选择操作系统';
dlg.field_id = -1;
dlg.field_os_type = -1;
@ -792,7 +792,7 @@ $app.create_dlg_edit_host = function () {
dlg.field_id = host.id;
dlg.dom.dlg_title.html('编辑主机:');
var _name = $app.id2name($app.host_os_type, host.os_type);
let _name = $app.id2name($app.host_os_type, host.os_type);
if (!_.isUndefined(_name)) {
// os_name = _name;
}
@ -831,7 +831,7 @@ $app.create_dlg_edit_host = function () {
};
dlg.show_edit = function (row_id) {
var host = $app.table_host.get_row(row_id);
let host = $app.table_host.get_row(row_id);
dlg.init_fields(host);
dlg.dom.dialog.modal({backdrop: 'static'});
};
@ -909,14 +909,14 @@ $app.create_dlg_edit_host = function () {
if (!dlg.check_input())
return;
var action = (dlg.field_id === -1) ? '添加' : '更新';
let action = (dlg.field_id === -1) ? '添加' : '更新';
// var router_addr = '';
// let router_addr = '';
// if (dlg.field_conn_mode === 1) {
// router_addr = dlg.field_router_ip + ':' + dlg.field_router_port;
// }
var args = {
let args = {
id: dlg.field_id,
os_type: dlg.field_os_type,
ip: dlg.field_ip,
@ -948,7 +948,7 @@ $app.create_dlg_edit_host = function () {
};
$app.create_dlg_accounts = function () {
var dlg = {};
let dlg = {};
dlg.dom_id = 'dlg-accounts';
dlg.host_row_id = -1;
dlg.host = null;
@ -977,7 +977,7 @@ $app.create_dlg_accounts = function () {
// 账号列表表格
//-------------------------------
var table_acc_options = {
let table_acc_options = {
dom_id: 'table-acc',
data_source: {
type: 'none'
@ -1069,7 +1069,7 @@ $app.create_dlg_accounts = function () {
});
dlg.dom.chkbox_acc_select_all.click(function () {
var _objects = $('#' + $app.table_acc.dom_id + ' tbody').find('[data-check-box]');
let _objects = $('#' + $app.table_acc.dom_id + ' tbody').find('[data-check-box]');
if ($(this).is(':checked')) {
$.each(_objects, function (i, _obj) {
$(_obj).prop('checked', true);
@ -1085,11 +1085,11 @@ $app.create_dlg_accounts = function () {
};
dlg.get_selected_acc = function (tbl) {
var items = [];
var _objs = $('#' + tbl.dom_id + ' tbody tr td input[data-check-box]');
let items = [];
let _objs = $('#' + tbl.dom_id + ' tbody tr td input[data-check-box]');
$.each(_objs, function (i, _obj) {
if ($(_obj).is(':checked')) {
var _row_data = tbl.get_row(_obj);
let _row_data = tbl.get_row(_obj);
items.push(_row_data.id);
}
});
@ -1116,7 +1116,7 @@ $app.create_dlg_accounts = function () {
};
dlg.on_btn_lock_acc_click = function () {
var items = dlg.get_selected_acc($app.table_acc);
let items = dlg.get_selected_acc($app.table_acc);
if (items.length === 0) {
$tp.notify_error('请选择要禁用的账号!');
return;
@ -1146,7 +1146,7 @@ $app.create_dlg_accounts = function () {
};
dlg.on_btn_unlock_acc_click = function () {
var items = dlg.get_selected_acc($app.table_acc);
let items = dlg.get_selected_acc($app.table_acc);
if (items.length === 0) {
$tp.notify_error('请选择要解禁的账号!');
return;
@ -1156,7 +1156,7 @@ $app.create_dlg_accounts = function () {
};
dlg._remove_acc = function (acc_ids) {
var _fn_sure = function (cb_stack) {
let _fn_sure = function (cb_stack) {
$tp.ajax_post_json('/asset/update-accounts', {action: 'remove', host_id: dlg.host.id, accounts: acc_ids},
function (ret) {
if (ret.code === TPE_OK) {
@ -1166,7 +1166,7 @@ $app.create_dlg_accounts = function () {
.exec();
$tp.notify_success('删除主机操作成功!');
var update_args = {
let update_args = {
acc_count: dlg.host.acc_count - acc_ids.length
};
$app.table_host.update_row(dlg.host_row_id, update_args);
@ -1184,7 +1184,7 @@ $app.create_dlg_accounts = function () {
);
};
var cb_stack = CALLBACK_STACK.create();
let cb_stack = CALLBACK_STACK.create();
$tp.dlg_confirm(cb_stack, {
msg: '<div class="alert alert-danger"><p><strong>注意:删除操作不可恢复!!</strong></p></div><p>如果您希望临时禁止以指定账号登录远程主机,可将其“禁用”!</p><p>您确定要移除选定的' + acc_ids.length + '个账号吗?</p>',
fn_yes: _fn_sure
@ -1192,7 +1192,7 @@ $app.create_dlg_accounts = function () {
};
dlg.on_btn_remove_acc_click = function () {
var items = dlg.get_selected_acc($app.table_acc);
let items = dlg.get_selected_acc($app.table_acc);
if (items.length === 0) {
$tp.notify_error('请选择要删除的账号!');
return;
@ -1241,9 +1241,9 @@ $app.create_dlg_accounts = function () {
// 绑定系统选择框事件
cell_obj.find('[data-action]').click(function () {
var action = $(this).attr('data-action');
var acc_id = $(this).attr('data-id');
var acc = tbl.get_row(row_id);
let action = $(this).attr('data-action');
let acc_id = $(this).attr('data-id');
let acc = tbl.get_row(row_id);
if (action === 'edit') {
$app.dlg_edit_account.show_edit(dlg.host_row_id, acc);
@ -1261,12 +1261,12 @@ $app.create_dlg_accounts = function () {
dlg.on_table_acc_render_created = function (render) {
// render.filter_state = function (header, title, col) {
// var _ret = ['<div class="tp-table-filter tp-table-filter-' + col.cell_align + '">'];
// let _ret = ['<div class="tp-table-filter tp-table-filter-' + col.cell_align + '">'];
// _ret.push('<div class="tp-table-filter-inner">');
// _ret.push('<div class="search-title">' + title + '</div>');
//
// // 表格内嵌过滤器的DOM实体在这时生成
// var filter_ctrl = header._table_ctrl.get_filter_ctrl('state');
// let filter_ctrl = header._table_ctrl.get_filter_ctrl('state');
// _ret.push(filter_ctrl.render());
//
// _ret.push('</div></div>');
@ -1275,12 +1275,12 @@ $app.create_dlg_accounts = function () {
// };
//
// render.filter_search = function (header, title, col) {
// var _ret = ['<div class="tp-table-filter tp-table-filter-input">'];
// let _ret = ['<div class="tp-table-filter tp-table-filter-input">'];
// _ret.push('<div class="tp-table-filter-inner">');
// _ret.push('<div class="search-title">' + title + '</div>');
//
// // 表格内嵌过滤器的DOM实体在这时生成
// var filter_ctrl = header._table_ctrl.get_filter_ctrl('search');
// let filter_ctrl = header._table_ctrl.get_filter_ctrl('search');
// _ret.push(filter_ctrl.render());
//
// _ret.push('</div></div>');
@ -1294,7 +1294,7 @@ $app.create_dlg_accounts = function () {
render.acc_info = function (row_id, fields) {
return fields.username;
// var ret = [];
// let ret = [];
//
// ret.push('<span class="user-surname">' + fields.username + '@' + fields.host_ip + '</span>');
// if (fields.router_ip.length > 0)
@ -1330,9 +1330,9 @@ $app.create_dlg_accounts = function () {
};
render.acc_state = function (row_id, fields) {
var _style, _state;
let i, _style, _state;
for (var i = 0; i < $app.obj_states.length; ++i) {
for (i = 0; i < $app.obj_states.length; ++i) {
if ($app.obj_states[i].id === fields.state) {
_style = $app.obj_states[i].style;
_state = $app.obj_states[i].name;
@ -1348,7 +1348,7 @@ $app.create_dlg_accounts = function () {
};
render.make_host_action_btn = function (row_id, fields) {
// var h = [];
// let h = [];
// h.push('<div class="btn-group btn-group-sm">');
// h.push('<button type="button" class="btn btn-no-border dropdown-toggle" data-toggle="dropdown">');
// h.push('<span data-selected-action>操作</span> <i class="fa fa-caret-right"></i></button>');
@ -1367,7 +1367,7 @@ $app.create_dlg_accounts = function () {
// return h.join('');
var ret = [];
let ret = [];
ret.push('<div class="btn-group btn-group-sm" role="group">');
ret.push('<btn class="btn btn-primary" data-action="edit" data-id="' + fields.id + '"><i class="fa fa-edit"></i> 编辑</btn>');
@ -1398,8 +1398,8 @@ $app.create_dlg_accounts = function () {
};
dlg.check_acc_all_selected = function (cb_stack) {
var _all_checked = true;
var _objs = $('#' + $app.table_acc.dom_id + ' tbody').find('[data-check-box]');
let _all_checked = true;
let _objs = $('#' + $app.table_acc.dom_id + ' tbody').find('[data-check-box]');
if (_objs.length === 0) {
_all_checked = false;
} else {
@ -1426,7 +1426,7 @@ $app.create_dlg_accounts = function () {
};
$app.create_dlg_edit_account = function () {
var dlg = {};
let dlg = {};
dlg.dom_id = 'dlg-edit-account';
dlg.host_row_id = -1;
dlg.host = null;
@ -1460,6 +1460,8 @@ $app.create_dlg_edit_account = function () {
prompt_password: $('#account-password-prompt'),
btn_show_password: $('#btn-show-account-password'),
btn_show_password_icon: $('#btn-show-account-password i'),
btn_clear_password: $('#btn-clear-password'),
block_clear_password: $('#block-clear-password'),
btn_test: $('#btn-edit-account-test'),
btn_save: $('#btn-edit-account-save')
};
@ -1481,6 +1483,24 @@ $app.create_dlg_edit_account = function () {
}
});
dlg.dom.btn_clear_password.click(function () {
$tp.ajax_post_json('/asset/clear-account-password', {
host_id: dlg.host.id,
acc_id: dlg.field_id
},
function (ret) {
if (ret.code === TPE_OK) {
$tp.notify_success('远程账号预设密码清除成功!');
} else {
$tp.notify_error('远程账号预设密码清除失败:' + tp_error_msg(ret.code, ret.message));
}
},
function () {
$tp.notify_error('网络故障,远程账号预设密码清除失败!');
}
);
});
cb_stack.exec();
};
@ -1492,6 +1512,7 @@ $app.create_dlg_edit_account = function () {
dlg.account = null;
dlg.field_id = -1;
dlg.dom.dlg_title.html('添加远程账号');
dlg.dom.block_clear_password.hide();
if (dlg.host.os_type === TP_OS_TYPE_LINUX) {
dlg.dom.protocol_type.val(TP_PROTOCOL_TYPE_SSH);
@ -1506,6 +1527,7 @@ $app.create_dlg_edit_account = function () {
dlg.account = account;
dlg.field_id = account.id;
dlg.dom.dlg_title.html('编辑:' + account.username);
dlg.dom.block_clear_password.show();
dlg.dom.username.val(account.username);
@ -1525,7 +1547,7 @@ $app.create_dlg_edit_account = function () {
dlg.on_protocol_change = function () {
dlg.field_protocol = parseInt(dlg.dom.protocol_type.val());
var html = [];
let html = [];
if (dlg.field_protocol === TP_PROTOCOL_TYPE_RDP) {
dlg.dom.block_rdp_param.show();
dlg.dom.block_ssh_param.hide();
@ -1673,11 +1695,12 @@ $app.create_dlg_edit_account = function () {
}
if (dlg.field_auth_type === TP_AUTH_TYPE_PASSWORD) {
if (dlg.field_id === -1 && dlg.field_password.length === 0) {
dlg.dom.password.focus();
$tp.notify_error('请填写登录远程主机的密码!');
return false;
}
// 可以不用设置密码,在远程登录时用户再手动填写。
// if (dlg.field_id === -1 && dlg.field_password.length === 0) {
// dlg.dom.password.focus();
// $tp.notify_error('请填写登录远程主机的密码!');
// return false;
// }
dlg.field_pri_key = '';
} else if (dlg.field_auth_type === TP_AUTH_TYPE_PRIVATE_KEY) {
if (dlg.field_id === -1 && dlg.field_pri_key.length === 0) {
@ -1700,7 +1723,7 @@ $app.create_dlg_edit_account = function () {
if (!dlg.check_input())
return;
var action = (dlg.field_id === -1) ? '添加' : '更新';
let action = (dlg.field_id === -1) ? '添加' : '更新';
// 如果id为-1表示创建否则表示更新
$tp.ajax_post_json('/asset/update-account', {
@ -1726,7 +1749,7 @@ $app.create_dlg_edit_account = function () {
if (dlg.field_id === -1) {
// 新建账号成功了,更新界面上对应主机的账号数
var update_args = {
let update_args = {
acc_count: dlg.host.acc_count + 1
};
$app.table_host.update_row(dlg.host_row_id, update_args);
@ -1750,6 +1773,8 @@ $app.create_dlg_edit_account = function () {
if (!dlg.check_input())
return;
let is_interactive = (dlg.field_password.length === 0);
$assist.do_teleport(
{
mode: 0,
@ -1764,7 +1789,8 @@ $app.create_dlg_edit_account = function () {
password: dlg.field_password,
pri_key: dlg.field_pri_key,
username_prompt: dlg.field_prompt_username,
password_prompt: dlg.field_prompt_password
password_prompt: dlg.field_prompt_password,
is_interactive: is_interactive
},
function () {
// func_success

View File

@ -4,12 +4,10 @@ $app.on_init = function (cb_stack) {
$app.dom = {
btn_sel_group: $('#btn-sel-group button')
, btn_refresh_host: $('#btn-refresh-host')
// , group_list_for_sel: $('#btn-sel-group ul')
// , group_selected: $('#group-selected')
};
// console.log($app.options);
if(!$app.options.core_cfg.detected) {
if (!$app.options.core_cfg.detected) {
$tp.notify_error('核心服务未启动,无法进行远程连接!');
cb_stack.exec();
return;
@ -27,17 +25,10 @@ $app.on_init = function (cb_stack) {
//===================================
$app.create_controls = function (cb_stack) {
// var html = [];
// $.each($app.options.host_groups, function (i, item) {
// html.push('<li><a href="javascript:;" data-tp-selector="' + item.id + '" data-name="' + item.name + '"><i class="fa fa-caret-right fa-fw"></i> ' + item.name + '</a></li>');
// });
// $app.dom.group_list_for_sel.append($(html.join('')));
//
//-------------------------------
// 资产列表表格
//-------------------------------
var table_host_options = {
let table_host_options = {
dom_id: 'table-host',
data_source: {
type: 'ajax-post',
@ -130,13 +121,14 @@ $app.create_controls = function (cb_stack) {
$app.on_table_host_cell_created = function (tbl, row_id, col_key, cell_obj) {
if (col_key === 'action') {
// 绑定系统选择框事件
cell_obj.find('[data-action]').click(function (e) {
var action = $(this).attr('data-action');
var protocol_sub_type = $(this).attr('data-sub-protocol');
var uni_id = $(this).attr('data-id');
var acc_id = parseInt($(this).attr('data-acc-id'));
var host_id = parseInt($(this).attr('data-host-id'));
let action = $(this).attr('data-action');
let protocol_sub_type = $(this).attr('data-sub-protocol');
let uni_id = $(this).attr('data-id');
let acc_id = parseInt($(this).attr('data-acc-id'));
let host_id = parseInt($(this).attr('data-host-id'));
if (action === 'rdp') {
$app.connect_remote(uni_id, acc_id, host_id, TP_PROTOCOL_TYPE_RDP, TP_PROTOCOL_TYPE_RDP_DESKTOP);
@ -146,6 +138,8 @@ $app.on_table_host_cell_created = function (tbl, row_id, col_key, cell_obj) {
$app.connect_remote(uni_id, acc_id, host_id, TP_PROTOCOL_TYPE_SSH, protocol_sub_type);
} else if (action === 'telnet') {
$app.connect_remote(uni_id, acc_id, host_id, TP_PROTOCOL_TYPE_TELNET, TP_PROTOCOL_TYPE_TELNET_SHELL);
} else if (action === 'get_config') {
$app.get_remote_connection_config(acc_id, host_id);
}
});
}
@ -154,12 +148,12 @@ $app.on_table_host_cell_created = function (tbl, row_id, col_key, cell_obj) {
$app.on_table_host_render_created = function (render) {
render.filter_state = function (header, title, col) {
var _ret = ['<div class="tp-table-filter tp-table-filter-' + col.cell_align + '">'];
let _ret = ['<div class="tp-table-filter tp-table-filter-' + col.cell_align + '">'];
_ret.push('<div class="tp-table-filter-inner">');
_ret.push('<div class="search-title">' + title + '</div>');
// 表格内嵌过滤器的DOM实体在这时生成
var filter_ctrl = header._table_ctrl.get_filter_ctrl('state');
let filter_ctrl = header._table_ctrl.get_filter_ctrl('state');
_ret.push(filter_ctrl.render());
_ret.push('</div></div>');
@ -168,12 +162,12 @@ $app.on_table_host_render_created = function (render) {
};
render.filter_search = function (header, title, col) {
var _ret = ['<div class="tp-table-filter tp-table-filter-input">'];
let _ret = ['<div class="tp-table-filter tp-table-filter-input">'];
_ret.push('<div class="tp-table-filter-inner">');
_ret.push('<div class="search-title">' + title + '</div>');
// 表格内嵌过滤器的DOM实体在这时生成
var filter_ctrl = header._table_ctrl.get_filter_ctrl('search');
let filter_ctrl = header._table_ctrl.get_filter_ctrl('search');
_ret.push(filter_ctrl.render());
_ret.push('</div></div>');
@ -182,7 +176,7 @@ $app.on_table_host_render_created = function (render) {
};
render.host_info = function (row_id, fields) {
var title, sub_title;
let title, sub_title;
title = fields.h_name;
sub_title = fields.ip;
@ -193,77 +187,112 @@ $app.on_table_host_render_created = function (render) {
// title = fields.a_name + '@' + title;
var desc = [];
// let desc = [];
if (fields.router_ip.length > 0) {
sub_title += ',由 ' + fields.router_ip + ':' + fields.router_port + ' 路由';
}
var ret = [];
if (desc.length > 0) {
ret.push('<div><a class="host-name host-name-desc" data-toggle="popover" data-placement="right"');
ret.push(' data-html="true"');
ret.push(' data-content="' + desc.join('') + '"');
ret.push('>' + title + '</a>');
} else {
ret.push('<div><span class="host-name">' + title + '</span>');
}
let ret = [];
// if (desc.length > 0) {
// ret.push('<div><a class="host-name host-name-desc" data-toggle="popover" data-placement="right"');
// ret.push(' data-html="true"');
// ret.push(' data-content="' + desc.join('') + '"');
// ret.push('>' + title + '</a>');
// } else {
// ret.push('<div><span class="host-name">' + title + '</span>');
// }
ret.push('<div><span class="host-name">' + title + '</span>');
ret.push('</div><div class="host-ip" href="javascript:;" data-host-desc="' + sub_title + '">' + sub_title + '</div>');
return ret.join('');
};
render.account = function (row_id, fields) {
var h = [];
for (var i = 0; i < fields.accs.length; ++i) {
var acc = fields.accs[i];
h.push('<div class="remote-info-group" id =' + "account-id-" + acc.id + '"><ul>');
let h = [];
// console.log('acc', fields);
if (fields.h_state !== TP_STATE_NORMAL || (fields.gh_state !== TP_STATE_NORMAL && fields.gh_state !== 0)) {
// 1. 主机已经被禁用,不显示相关账号。
// 2. 主机所在分组已经被禁用,不显示相关账号。
return;
}
for (let i = 0; i < fields.accs.length; ++i) {
let acc = fields.accs[i];
h.push('<div class="remote-info-group"><ul>');
h.push('<li>' + acc.a_name + '</li>');
h.push('</ul></div>');
}
return h.join('');
};
render.action = function (row_id, fields) {
// console.log(fields);
var h = [];
for (var i = 0; i < fields.accs.length; ++i) {
var acc = fields.accs[i];
var act_btn = [];
// console.log('action', fields);
let is_disabled = false;
let disable_msg = '';
if (fields.h_state !== TP_STATE_NORMAL) {
is_disabled = true;
disable_msg = '无可用远程连接,主机已被禁用';
}
if (fields.gh_state !== TP_STATE_NORMAL && fields.gh_state !== 0) {
is_disabled = true;
disable_msg = '无可用远程连接,主机所在分组已被禁用';
}
if (is_disabled) {
let h = [];
h.push('<div><div class="remote-action-group"><div class="btn-group btn-group-sm">');
h.push('<button type="button" class="btn btn-disabled" disabled><i class="fa fa-ban fa-fw"></i> ');
h.push(disable_msg);
h.push('</button></div></div>');
return h.join('');
}
let h = [];
for (let i = 0; i < fields.accs.length; ++i) {
let acc = fields.accs[i];
let act_btn = [];
is_disabled = false;
disable_msg = '';
var disabled = '';
if (acc.a_state !== TP_STATE_NORMAL)
disabled = '账号已禁用';
if (disabled.length === 0 && (acc.policy_auth_type === TP_POLICY_AUTH_USER_gACC || acc.policy_auth_type === TP_POLICY_AUTH_gUSER_gACC) && acc.ga_state !== TP_STATE_NORMAL)
disabled = '账号所在组已禁用';
if (disabled.length === 0 && fields.h_state !== TP_STATE_NORMAL)
disabled = '主机已禁用';
if (disabled.length === 0 && (acc.policy_auth_type === TP_POLICY_AUTH_USER_gHOST || acc.policy_auth_type === TP_POLICY_AUTH_gUSER_gHOST) && fields.gh_state !== TP_STATE_NORMAL)
disabled = '主机所在组已禁用';
disable_msg = '账号已被禁用';
if (disable_msg.length === 0 && (acc.policy_auth_type === TP_POLICY_AUTH_USER_gACC || acc.policy_auth_type === TP_POLICY_AUTH_gUSER_gACC) && acc.ga_state !== TP_STATE_NORMAL)
disable_msg = '账号所在分组已被禁用';
// if (disable_msg.length === 0 && fields.h_state !== TP_STATE_NORMAL)
// disable_msg = '主机已被禁用';
// if (disable_msg.length === 0 && (acc.policy_auth_type === TP_POLICY_AUTH_USER_gHOST || acc.policy_auth_type === TP_POLICY_AUTH_gUSER_gHOST) && fields.gh_state !== TP_STATE_NORMAL)
// disable_msg = '主机所在组已被禁用';
if (disabled.length > 0) {
act_btn.push('<li class="remote-action-state state-disabled">');
act_btn.push('<i class="fa fa-ban fa-fw"></i> ' + disabled);
act_btn.push('</li>');
} else {
if (acc.protocol_type === TP_PROTOCOL_TYPE_RDP) {
if (disable_msg.length > 0)
is_disabled = true;
if (acc.protocol_type === TP_PROTOCOL_TYPE_RDP) {
if (!is_disabled) {
if (!$app.options.core_cfg.rdp.enable) {
act_btn.push('<li class="remote-action-state state-disabled">');
act_btn.push('<i class="fa fa-ban fa-fw"></i> RDP协议未启用');
act_btn.push('</li>');
is_disabled = true;
disable_msg = 'RDP协议未启用';
} else {
if ((acc.policy_.flag_rdp & TP_FLAG_RDP_DESKTOP) !== 0) {
act_btn.push('<div class="btn-group btn-group-sm">');
act_btn.push('<button type="button" class="btn btn-primary" data-action="rdp" data-id="' + acc.uni_id + '" data-acc-id="' + acc.a_id + '" data-host-id="' + acc.h_id + '" data-sub-protocol="' + TP_PROTOCOL_TYPE_RDP_DESKTOP + '"><i class="fa fa-desktop fa-fw"></i> RDP</button>');
act_btn.push('<a href="javascript:;" class="btn btn-primary dropdown-toggle" data-action="rdp-option" data-id="' + acc.uni_id + '" data-acc-id="' + acc.a_id + '" data-host-id="' + acc.h_id + '" data-sub-protocol="' + TP_PROTOCOL_TYPE_RDP_DESKTOP + '">');
act_btn.push('<button type="button" class="btn btn-primary dropdown-toggle" data-action="rdp-option" data-id="' + acc.uni_id + '" data-acc-id="' + acc.a_id + '" data-host-id="' + acc.h_id + '" data-sub-protocol="' + TP_PROTOCOL_TYPE_RDP_DESKTOP + '">');
act_btn.push('<i class="fa fa-cog"></i>');
act_btn.push('</a>');
act_btn.push('</button>');
act_btn.push('</div>');
}
}
} else if (acc.protocol_type === TP_PROTOCOL_TYPE_SSH) {
} else {
disable_msg = 'RPD' + disable_msg;
}
} else if (acc.protocol_type === TP_PROTOCOL_TYPE_SSH) {
if (!is_disabled) {
if (!$app.options.core_cfg.ssh.enable) {
act_btn.push('<li class="remote-action-state state-disabled">');
act_btn.push('<i class="fa fa-ban fa-fw"></i> SSH协议未启用');
act_btn.push('</li>');
is_disabled = true;
disable_msg = 'SSH协议未启用';
} else {
act_btn.push('<div class="btn-group btn-group-sm">');
if ((acc.policy_.flag_ssh & TP_FLAG_SSH_SHELL) !== 0) {
@ -275,23 +304,49 @@ $app.on_table_host_render_created = function (render) {
}
act_btn.push('</div>');
}
} else if (acc.protocol_type === TP_PROTOCOL_TYPE_TELNET) {
} else {
disable_msg = 'SSH' + disable_msg;
}
} else if (acc.protocol_type === TP_PROTOCOL_TYPE_TELNET) {
if (!is_disabled) {
if (!$app.options.core_cfg.telnet.enable) {
act_btn.push('<li class="remote-action-state state-disabled">');
act_btn.push('<i class="fa fa-ban fa-fw"></i> TELNET协议未启用');
act_btn.push('</li>');
is_disabled = true;
disable_msg = 'TELNET协议未启用';
} else {
act_btn.push('<div class="btn-group btn-group-sm">');
act_btn.push('<button type="button" class="btn btn-warning" data-action="telnet" data-id="' + acc.uni_id + '" data-acc-id="' + acc.a_id + '" data-host-id="' + acc.h_id + '" data-sub-protocol="' + TP_PROTOCOL_TYPE_TELNET_SHELL + '"><i class="far fa-keyboard fa-fw"></i> TELNET</button>');
act_btn.push('</div>');
}
} else {
disable_msg = 'TELNET' + disable_msg;
}
}
h.push('<div class="remote-action-group" id =' + "account-id-" + acc.id + '">');
if (disable_msg.length > 0) {
is_disabled = true;
act_btn.push('<div class="btn-group btn-group-sm">');
act_btn.push('<button type="button" class="btn btn-disabled" disabled><i class="fa fa-ban fa-fw"></i> ');
act_btn.push(disable_msg);
act_btn.push('</button>');
act_btn.push('</div>');
}
h.push('<div>');
h.push('<div class="remote-action-group">');
h.push(act_btn.join(''));
h.push('</div>');
if (!is_disabled) {
h.push('<div class="remote-config">');
h.push('<button type="button" class="btn btn-default" data-action="get_config" data-acc-id=' + acc.a_id + ' data-host-id=' + acc.h_id + '><i class="fa fa-key fa-fw"></i> 获取远程连接配置</button>');
h.push('</div>');
}
h.push('</div>');
}
return h.join('');
};
};
@ -310,7 +365,7 @@ $app.on_table_host_header_created = function (header) {
};
$app.create_dlg_rdp_options = function () {
var dlg = {};
let dlg = {};
dlg.dom_id = 'dlg-rdp-options';
dlg.uni_id = '';
dlg.acc_id = 0;
@ -345,10 +400,10 @@ $app.create_dlg_rdp_options = function () {
dlg.dom.btn_connect.click(function () {
dlg.hide();
var _size_obj = $('#' + dlg.dom_id + ' input[name="screen-size"]:checked');
var _console = dlg.dom.console_mode.is(':checked');
var _w = parseInt(_size_obj.attr('data-w'));
var _h = parseInt(_size_obj.attr('data-h'));
let _size_obj = $('#' + dlg.dom_id + ' input[name="screen-size"]:checked');
let _console = dlg.dom.console_mode.is(':checked');
let _w = parseInt(_size_obj.attr('data-w'));
let _h = parseInt(_size_obj.attr('data-h'));
dlg.rdp_w = _w;
dlg.rdp_h = _h;
@ -358,7 +413,7 @@ $app.create_dlg_rdp_options = function () {
$app.connect_remote(dlg.uni_id, dlg.acc_id, dlg.host_id, dlg.protocol_type, dlg.protocol_sub_type);
});
var ops = Cookies.getJSON('rdp_options');
let ops = Cookies.getJSON('rdp_options');
dlg.rdp_w = 0;
dlg.rdp_h = 0;
dlg.rdp_console = false;
@ -374,7 +429,7 @@ $app.create_dlg_rdp_options = function () {
if (_.isUndefined(dlg.rdp_console))
dlg.rdp_console = false;
var ss = [
let ss = [
{w: 800, h: 600},
{w: 1024, h: 768},
{w: 1280, h: 1024},
@ -382,16 +437,16 @@ $app.create_dlg_rdp_options = function () {
{w: 1440, h: 900}
];
var h = [];
let h = [];
h.push('<div class="radio">');
h.push('<div><label><input type="radio" name="screen-size" data-w="0" data-h="0"');
if (dlg.rdp_w === 0 && dlg.rdp_h === 0)
h.push(' checked');
h.push('> 全屏</label></div>');
for (var i = 0; i < ss.length; ++i) {
var _w = ss[i].w;
var _h = ss[i].h;
for (let i = 0; i < ss.length; ++i) {
let _w = ss[i].w;
let _h = ss[i].h;
h.push('<div><label><input type="radio" name="screen-size" data-w="' + _w + '" data-h="' + _h + '"');
if (dlg.rdp_w === _w && dlg.rdp_h === _h)
h.push(' checked');
@ -418,7 +473,7 @@ $app.create_dlg_rdp_options = function () {
dlg.protocol_type = protocol_type;
dlg.protocol_sub_type = protocol_sub_type;
var w = dlg.dom.dialog.width();
let w = dlg.dom.dialog.width();
x -= w / 3;
y -= 12;
dlg.dom.dialog.css({left: x, top: y});
@ -432,36 +487,61 @@ $app.create_dlg_rdp_options = function () {
return dlg;
};
$app.get_remote_connection_config = function (acc_id, host_id) {
console.log(acc_id, host_id);
}
$app.connect_remote = function (uni_id, acc_id, host_id, protocol_type, protocol_sub_type) {
var args = {
let args = {
mode: 1,
auth_id: uni_id,
acc_id: acc_id,
host_id: host_id,
protocol_type: protocol_type,
protocol_sub_type: protocol_sub_type,
rdp_width: $app.dlg_rdp_options.rdp_w,
rdp_height: $app.dlg_rdp_options.rdp_h,
rdp_console: $app.dlg_rdp_options.rdp_console
is_interactive: false,
};
console.log('--s--', args);
if (protocol_type === TP_PROTOCOL_TYPE_RDP) {
args.extends({
rdp_width: $app.dlg_rdp_options.rdp_w,
rdp_height: $app.dlg_rdp_options.rdp_h,
rdp_console: $app.dlg_rdp_options.rdp_console
});
}
if (uni_id === 'none')
args.mode = 2;
$assist.do_teleport(
args,
function () {
// func_success
//$tp.notify_success('远程连接测试通过!');
// 根据acc_id判断此远程账号是否有预设密码如果没有则需要设置interactive模式。
$tp.ajax_post_json('/asset/get-account-interactive-mode',
{acc_id: acc_id},
function (ret) {
console.log('ajax: /asset/get-account-interactive-mode', ret);
if (ret.code === TPE_OK) {
args.is_interactive = ret.data.is_interactive;
console.log('--s--', args);
$assist.do_teleport(
args,
function () {
// func_success
//$tp.notify_success('远程连接测试通过!');
},
function (code, message) {
if (code === TPE_NO_ASSIST)
$assist.alert_assist_not_found(code);
else
$tp.notify_error('远程连接失败:' + tp_error_msg(code, message));
}
);
} else {
$tp.notify_error('无法获取远程账号信息:' + tp_error_msg(ret.code, ret.message));
}
},
function (code, message) {
if (code === TPE_NO_ASSIST)
$assist.alert_assist_not_found(code);
else
$tp.notify_error('远程连接失败:' + tp_error_msg(code, message));
function () {
$tp.notify_error('网络故障,无法获取远程账号信息!');
}
);
};

View File

@ -822,7 +822,7 @@ $app.create_config_integration = function () {
fields: {id: 'id'}
},
{
title: '服务名称',
title: '外部服务名称',
key: 'name',
width: 120,
},
@ -848,7 +848,7 @@ $app.create_config_integration = function () {
title: '',
key: 'action',
align: 'center',
width: 200,
width: 150,
render: 'make_action_btn',
fields: {id: 'id'}
}
@ -920,7 +920,7 @@ $app.create_config_integration = function () {
let ret = [];
ret.push('<div class="btn-group btn-group-sm" role="group">');
ret.push('<btn class="btn btn-primary" data-btn-edit="edit"><i class="fa fa-edit"></i> 编辑</btn>');
ret.push('<btn class="btn btn-danger" data-btn-remove="' + fields.id + '"><i class="fas fa-trash-alt"></i> 删除</btn>');
ret.push('<btn class="btn btn-danger" data-btn-remove="remove"><i class="fas fa-trash-alt"></i> 删除</btn>');
ret.push('</div>');
return ret.join('');
};

View File

@ -532,7 +532,7 @@ $tp.create_table = function (options) {
if (!_tbl.options.columns.hasOwnProperty(i))
continue;
let col = _tbl.options.columns[i];
for (k in kv) {
for (let k in kv) {
if (!kv.hasOwnProperty(k))
continue;

View File

@ -412,7 +412,8 @@ $assist.do_teleport = function (args, func_success, func_error) {
session_id: session_id,
protocol_type: parseInt(args.protocol_type),
protocol_sub_type: parseInt(args.protocol_sub_type),
protocol_flag: parseInt(ret.data.protocol_flag)
protocol_flag: parseInt(ret.data.protocol_flag),
is_interactive: args.is_interactive
};
if (args.protocol_type === TP_PROTOCOL_TYPE_RDP) {

View File

@ -19,7 +19,7 @@ html {
body {
font-family: @font-family-normal;
//font-size: @text-size-normal;
font-size: @text-size-normal;
background-color: @page-bg;
color: @page-color;
}

View File

@ -270,9 +270,9 @@
color: #ac4e43;
position: absolute;
margin-left: -1.2em;
margin-top: 1px;
//margin-top: 1px;
content: "\f069";
font-size: 8px;
//font-size: 8px;
font-family: 'Font Awesome 5 Free';
font-weight: 900;
}
@ -282,6 +282,11 @@
color: #999;
}
.control-desc-sm {
color: #999;
padding-top: 7px;
font-size: @text-size-small;
}
.control-desc-sm-input {
color: #999;
padding-top: 3px;
font-size: @text-size-small;

View File

@ -1,12 +1,13 @@
@charset "utf-8";
.remote-action-group {
display: inline-block;
margin-bottom: 3px;
height: 28px;
.btn-group-sm > .btn {
margin: 0;
padding: 6px 6px;
//padding: 6px 6px;
font-size: 12px;
height: 28px;
min-width: 80px;
@ -14,6 +15,17 @@
&.dropdown-toggle {
min-width: 0;
}
&.btn-disabled {
background-color: @color-bg-ignore;
color: #aaa;
//text-shadow: -1px -1px 1px #fff;
//& > i.fa {
// color: #b53a2f;
// text-shadow: none;
//}
}
}
//& > ul {
@ -59,6 +71,7 @@
//width: 64px;
text-align: center;
white-space: nowrap;
height: 28px;
&.state-disabled {
background-color: @color-bg-ignore;
@ -136,6 +149,7 @@
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
//
//&.remote-action-btn:first-child {
// border: none;
@ -149,6 +163,7 @@
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
//
//&.remote-action-btn:last-child {
// border: none;
@ -159,9 +174,24 @@
//}
}
//}
}
.remote-config {
display: inline-block;
margin-left: 20px;
button {
margin: 0;
//padding: 6px 6px;
font-size: 12px;
height: 28px;
min-width: 80px;
}
}
.remote-info-group {
margin-bottom: 3px;
height: 28px;
@ -177,49 +207,52 @@
position: relative;
display: block;
height: 28px;
padding: 4px 5px;
line-height: 28px;
//padding: 4px 5px;
//background-color: #efefef;
border-top: 1px solid #ccc;
border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
//border-top: 1px solid #ccc;
//border-right: 1px solid #ccc;
//border-bottom: 1px solid #ccc;
border:none;
&.remote-action-btn {
background: none;
padding: 0;
border: none;
}
//&.remote-action-btn {
// background: none;
// padding: 0;
// border: none;
//}
//
//&.remote-action-input {
// background: none;
// padding: 4px 0;
//
// select {
// border: none;
// }
//}
&.remote-action-input {
background: none;
padding: 4px 0;
//label {
// padding: 0;
// display: block;
// float: left;
// margin-top: 1px;
// cursor: pointer;
//}
//
//select {
// margin-top: -3px;
//}
select {
border: none;
}
}
label {
padding: 0;
display: block;
float: left;
margin-top: 1px;
cursor: pointer;
}
select {
margin-top: -3px;
}
&:first-child {
border-left: 1px solid #ccc;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
&:last-child {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
//&:first-child {
// border-left: 1px solid #ccc;
// border-top-left-radius: 4px;
// border-bottom-left-radius: 4px;
//}
//
//&:last-child {
// border-top-right-radius: 4px;
// border-bottom-right-radius: 4px;
//}
}
}
}
@ -242,7 +275,8 @@
.title {
background-color: #eee;
padding: 3px 5px;
padding: 5px 5px;
font-weight: bold;
}
.item {

View File

@ -585,9 +585,9 @@ body {
// margin: 0 auto;
//}
//
.form-group .input-group {
margin-bottom: 5px;
}
//.form-group .input-group {
// margin-bottom: 5px;
//}
.op_box {
display: block;

View File

@ -46,7 +46,7 @@
{% block block_body %}
<div class="page-content-inner">
{# ## 防止页面搜索框被自动填充#}
{# ## 防止页面搜索框被自动填充#}
<label style="display:none;"><span></span><input type="text" name="hidden1"></label>
<label style="display:none;"><span></span><input type="password" name="hidden2"></label>
@ -136,12 +136,12 @@
<div class="form-horizontal">
{# ## <div class="form-group form-group-sm">#}
{# ## <label for="edit-host-type" class="col-sm-2 control-label require">主机类型:</label>#}
{# ## <div class="col-sm-6">#}
{# ## <div id="edit-host-type" class="btn-group btn-group-sm"></div>#}
{# ## </div>#}
{# ## </div>#}
{# ## <div class="form-group form-group-sm">#}
{# ## <label for="edit-host-type" class="col-sm-2 control-label require">主机类型:</label>#}
{# ## <div class="col-sm-6">#}
{# ## <div id="edit-host-type" class="btn-group btn-group-sm"></div>#}
{# ## </div>#}
{# ## </div>#}
<div class="form-group form-group-sm">
<label for="edit-host-os-type" class="col-sm-3 control-label require">远程主机系统:</label>
@ -303,18 +303,13 @@
<label class="col-sm-3 control-label" for="account-protocol-port"><strong>端口:</strong></label>
<div class="col-sm-9">
<input id="account-protocol-port" type="text" class="form-control" placeholder=""/>
{# ## <p id="account-protocol-port-static" class="form-control-static mono" style="color:#0a6aa1;font-weight:bold;display:none;"></p>#}
</div>
</div>
<div class="form-group form-group-sm">
<label class="col-sm-3 control-label" for="account-auth-type"><strong>认证方式:</strong></label>
<div class="col-sm-9">
<select id="account-auth-type" class="form-control">
<option value="1">用户名/密码 认证</option>
<option value="2">SSH私钥 认证</option>
<option value="0">无需认证</option>
</select>
<select id="account-auth-type" class="form-control"></select>
</div>
</div>
@ -358,8 +353,13 @@
<input id="account-password" type="password" class="form-control" placeholder="登录远程主机的密码">
<span class="input-group-btn"><button class="btn btn-sm btn-default" type="button" id="btn-show-account-password"><i class="fa fa-eye fa-fw"></i></button></span>
</div>
<div class="control-desc-sm-input">
<span>如不填写密码,则会在远程连接时要求用户手动输入。</span>
<span id="block-clear-password">如果已设置了密码,可<a href="javascript:" id="btn-clear-password">点击此处清除</a></span>
</div>
</div>
</div>
</div>
<div id="block-sshkey" style="display:none;">

View File

@ -172,7 +172,7 @@
placeholder="用户账号,也就是用户登录名"/>
</div>
<div class="col-sm-5">
<div class="control-desc">英文字符和数字最大32字符</div>
<div class="control-desc-sm">英文字符和数字最大32字符</div>
</div>
</div>
@ -189,7 +189,7 @@
<input id="edit-user-email" type="text" class="form-control" placeholder="电子邮箱地址"/>
</div>
<div class="col-sm-5">
<div class="control-desc">用于激活账号、重置密码。</div>
<div class="control-desc-sm">用于激活账号、重置密码。</div>
</div>
</div>
@ -224,7 +224,7 @@
</div>
</div>
<div class="col-sm-5">
<div class="control-desc">开始</div>
<div class="control-desc-sm">开始时间</div>
</div>
</div>
<div class="form-group form-group-sm">
@ -237,7 +237,7 @@
</div>
</div>
<div class="col-sm-5">
<div class="control-desc">结束</div>
<div class="control-desc-sm">结束时间</div>
</div>
</div>
@ -444,7 +444,7 @@
placeholder="LDAP服务器IP或域名"/>
</div>
<div class="col-sm-6">
<label class="form-check-label"><input id="edit-ldap-ssl" type="checkbox" class="form-check-input"/> 使用 SSL</label>
<label class="control-label"><input id="edit-ldap-ssl" type="checkbox"/> 使用 SSL</label>
</div>
</div>
@ -503,7 +503,7 @@
<label for="edit-ldap-base-dn" class="col-sm-2 control-label require">用户基准DN</label>
<div class="col-sm-9">
<input id="edit-ldap-base-dn" type="text" class="form-control" placeholder=""/>
<div class="control-desc-sm">限制用户DN的范围例如 <span class="important">ou=dev,ou=company,ou=com</span>
<div class="control-desc-sm-input">限制用户DN的范围例如 <span class="important">ou=dev,ou=company,ou=com</span>
</div>
</div>
</div>
@ -513,7 +513,7 @@
<div class="col-sm-9">
<input id="edit-ldap-filter" type="text" class="form-control" placeholder=""
value="(&(objectClass=person))"/>
<div class="control-desc-sm">列举用户时的过滤器,例如 <span class="important">(&(objectClass=person))</span>
<div class="control-desc-sm-input">列举用户时的过滤器,例如 <span class="important">(&(objectClass=person))</span>
</div>
</div>
</div>

View File

@ -109,7 +109,7 @@ class TPAssistBridge(object):
return assist_info
def handle_assist_message(self, msg_req: AssistMessage):
log.v('add message, cmd_id={}\n'.format(msg_req.cmd_id))
# log.v('add message, cmd_id={}\n'.format(msg_req.cmd_id))
self._commands[msg_req.cmd_id] = msg_req
def on_web_client_connect(self, msg_req: AssistMessage, s_id: str, param: dict) -> None:

View File

@ -126,6 +126,10 @@ controllers = [
(r'/asset/account-group/(.*)', account.AccGroupInfoHandler),
# - [json] 添加/更新 远程账号
(r'/asset/update-account', account.DoUpdateAccountHandler),
# - [json] 清除 远程账号的预设密码
(r'/asset/clear-account-password', account.DoClearAccountPasswordHandler),
# - [json] 查询 远程账号是否有预设密码
(r'/asset/get-account-interactive-mode', account.DoGetAccountInteractiveModeHandler),
# - [json] 禁用/解禁/删除 远程账号
(r'/asset/update-accounts', account.DoUpdateAccountsHandler),
# - [json] 获取账号列表

View File

@ -233,15 +233,15 @@ class DoUpdateAccountHandler(TPBaseJsonHandler):
if acc_id == -1:
# 新增账号
if param['auth_type'] == TP_AUTH_TYPE_PASSWORD and len(param['password']) == 0:
return self.write_json(TPE_PARAM)
elif param['auth_type'] == TP_AUTH_TYPE_PRIVATE_KEY and len(param['pri_key']) == 0:
# if param['auth_type'] == TP_AUTH_TYPE_PASSWORD and len(param['password']) == 0:
# return self.write_json(TPE_PARAM)
if param['auth_type'] == TP_AUTH_TYPE_PRIVATE_KEY and len(param['pri_key']) == 0:
return self.write_json(TPE_PARAM)
if param['auth_type'] == TP_AUTH_TYPE_PASSWORD and len(param['password']) > 0:
code, ret_data = yield core_service_async_enc(param['password'])
if code != TPE_OK:
return self.write_json(code)
return self.write_json(code, '无法加密存储密码!')
else:
param['password'] = ret_data
elif param['auth_type'] == TP_AUTH_TYPE_PRIVATE_KEY and len(param['pri_key']) > 0:
@ -260,6 +260,60 @@ class DoUpdateAccountHandler(TPBaseJsonHandler):
self.write_json(err, data=info)
class DoClearAccountPasswordHandler(TPBaseJsonHandler):
@tornado.gen.coroutine
def post(self):
ret = self.check_privilege(TP_PRIVILEGE_ACCOUNT)
if ret != TPE_OK:
return
args = self.get_argument('args', None)
if args is None:
return self.write_json(TPE_PARAM)
try:
args = json.loads(args)
except:
return self.write_json(TPE_JSON_FORMAT)
try:
host_id = int(args['host_id'])
acc_id = int(args['acc_id'])
except:
log.e('\n')
return self.write_json(TPE_PARAM)
err = account.clear_account_password(self, host_id, acc_id)
self.write_json(err)
class DoGetAccountInteractiveModeHandler(TPBaseJsonHandler):
@tornado.gen.coroutine
def post(self):
ret = self.check_privilege(TP_PRIVILEGE_OPS)
if ret != TPE_OK:
return
args = self.get_argument('args', None)
if args is None:
return self.write_json(TPE_PARAM)
try:
args = json.loads(args)
except:
return self.write_json(TPE_JSON_FORMAT)
try:
acc_id = int(args['acc_id'])
except:
log.e('\n')
return self.write_json(TPE_PARAM)
err, password = account.get_account_password(acc_id)
if err != TPE_OK:
return self.write_json(err)
self.write_json(TPE_OK, data={'is_interactive': True if len(password) == 0 else False})
class DoUpdateAccountsHandler(TPBaseJsonHandler):
@tornado.gen.coroutine
def post(self):

View File

@ -421,9 +421,9 @@ class DoGetSessionIDHandler(TPBaseJsonHandler):
conn_info['_enc'] = 0
if acc_id == -1:
if auth_type == TP_AUTH_TYPE_PASSWORD and len(password) == 0:
return self.write_json(TPE_PARAM)
elif auth_type == TP_AUTH_TYPE_PRIVATE_KEY and len(pri_key) == 0:
# if auth_type == TP_AUTH_TYPE_PASSWORD and len(password) == 0:
# return self.write_json(TPE_PARAM)
if auth_type == TP_AUTH_TYPE_PRIVATE_KEY and len(pri_key) == 0:
return self.write_json(TPE_PARAM)
else:
if (auth_type == TP_AUTH_TYPE_PASSWORD and len(password) == 0) or (auth_type == TP_AUTH_TYPE_PRIVATE_KEY and len(pri_key) == 0):

View File

@ -61,7 +61,7 @@ class AssistHandler(tornado.websocket.WebSocketHandler):
'method': msg.method,
'param': param
}
log.w('send ws request: {}\n'.format(json_encode(data)))
log.d('send ws request: {}\n'.format(json_encode(data)))
self.write_message(json_encode(data))
def send_response(self, msg: AssistMessage, code, message='', data=None):
@ -75,7 +75,7 @@ class AssistHandler(tornado.websocket.WebSocketHandler):
'message': message,
'data': data
}
log.w('send ws response: {}\n'.format(json_encode(ret)))
log.d('send ws response: {}\n'.format(json_encode(ret)))
self.write_message(json_encode(ret))
def set_assist_id(self, assist_id: int) -> None:

View File

@ -296,6 +296,32 @@ def add_account(handler, host_id, args):
return TPE_OK, _id
def clear_account_password(handler, host_id, acc_id):
db = get_db()
sql = 'UPDATE `{tp}acc` SET `password`="" WHERE `id`={ph} AND `host_id`={ph}'.format(tp=db.table_prefix, ph=db.place_holder)
db_ret = db.exec(sql, (acc_id, host_id))
if not db_ret:
return TPE_DATABASE
return TPE_OK
def get_account_password(acc_id):
db = get_db()
s = SQL(db)
s.select_from('acc', ['password'], alt_name='a')
s.where('a.id={ph}'.format(ph=db.place_holder))
err = s.query((acc_id, ))
if err != TPE_OK:
return err, None
if len(s.recorder) != 1:
return TPE_DATABASE, None
# s.recorder[0]['_host'] = sh.recorder[0]
return TPE_OK, s.recorder[0]['password']
def update_account(handler, host_id, acc_id, args):
"""
更新一个远程账号