From 7fa5c8936b069af0f28f880f7295e6e864cb99f3 Mon Sep 17 00:00:00 2001 From: horizonlin Date: Tue, 11 Dec 2018 14:09:18 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0urlprotocol=E5=90=AF=E5=8A=A8?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加urlprotocol启动方法 --- client/tp_assist_win/ts_http_rpc.cpp | 158 +++++++++++++++++++++------ 1 file changed, 122 insertions(+), 36 deletions(-) diff --git a/client/tp_assist_win/ts_http_rpc.cpp b/client/tp_assist_win/ts_http_rpc.cpp index 6238c89..85b557a 100644 --- a/client/tp_assist_win/ts_http_rpc.cpp +++ b/client/tp_assist_win/ts_http_rpc.cpp @@ -16,22 +16,22 @@ /* 1. -SecureCRT֧ñǩҳı⣬в /N "tab name"Ϳ +SecureCRT支持设置标签页的标题,命令行参数 /N "tab name"就可以 Example: To launch a new Telnet session, displaying the name "Houston, TX" on the tab, use the following: /T /N "Houston, TX" /TELNET 192.168.0.6 2. -SecureCRTŵһڵIJͬǩҳУʹò /T +多次启动的SecureCRT放到一个窗口的不同标签页中,使用参数: /T SecureCRT.exe /T /N "TP#ssh://192.168.1.3" /SSH2 /L root /PASSWORD 1234 120.26.109.25 3. -telnetͻ˵ +telnet客户端的启动: putty.exe telnet://administrator@127.0.0.1:52389 -SecureCRTҪ +如果是SecureCRT,则需要 SecureCRT.exe /T /N "TP#telnet://192.168.1.3" /SCRIPT X:\path\to\startup.vbs /TELNET 127.0.0.1 52389 -Уstartup.vbsΪ ----------ļʼ--------- +其中,startup.vbs的内容为: +---------文件开始--------- #$language = "VBScript" #$interface = "1.0" Sub main @@ -40,11 +40,11 @@ Sub main crt.Screen.Send "SESSION-ID" & VbCr crt.Screen.Synchronous = False End Sub ----------ļ--------- +---------文件结束--------- -4. ΪputtyĴڱǩʾIPԳӳɹ˷ +4. 为了让putty的窗口标签显示正常的IP,可以尝试在连接成功后,主动向服务端发送下列命令: PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@192.168.1.2: \w\a\]$PS1" -ֹˣubuntuԣ֪Ƿܹ֧еLinuxSecureCRTԴ˱ʾԡ +手工测试了,ubuntu服务器可以,不知道是否能够支持所有的Linux。SecureCRT对此表示忽略。 */ //#define RDP_CLIENT_SYSTEM_BUILTIN @@ -203,6 +203,40 @@ bool calc_psw51b(const char* password, std::string& ret) return true; } +bool isDegital(std::string str) { + for (int i = 0; i < str.size(); i++) { + if (str.at(i) == '-' && str.size() > 1) // 有可能出现负数 + continue; + if (str.at(i) > '9' || str.at(i) < '0') + return false; + } + return true; +} + +std::string strtolower(std::string str) { + for (int i = 0; i < str.size(); i++) + { + str[i] = tolower(str[i]); + } + return str; +} + +void SplitString(const std::string& s, std::vector& v, const std::string& c) +{ + std::string::size_type pos1, pos2; + pos2 = s.find(c); + pos1 = 0; + while (std::string::npos != pos2) + { + v.push_back(s.substr(pos1, pos2 - pos1)); + + pos1 = pos2 + c.size(); + pos2 = s.find(c, pos1); + } + if (pos1 != s.length()) + v.push_back(s.substr(pos1)); +} + TsHttpRpc::TsHttpRpc() { m_stop = false; @@ -317,7 +351,7 @@ void TsHttpRpc::_mg_event_handler(struct mg_connection *nc, int ev, void *ev_dat if (uri == "/") { - ex_wstr page = L"Teleport\n\n
Teleportֹ
"; + ex_wstr page = L"Teleport助手\n\n
Teleport助手工作正常!
"; ex_wstr2astr(page, ret_buf, EX_CODEPAGE_UTF8); mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n%s", ret_buf.size() - 1, &ret_buf[0]); @@ -424,7 +458,7 @@ int TsHttpRpc::_parse_request(struct http_message* req, ex_astr& func_cmd, ex_as ex_astrs strs; - size_t pos_start = 1; // һֽڣһ '/' + size_t pos_start = 1; // 跳过第一个字节,一定是 '/' size_t i = 0; for (i = pos_start; i < req->uri.len; ++i) @@ -437,7 +471,7 @@ int TsHttpRpc::_parse_request(struct http_message* req, ex_astr& func_cmd, ex_as tmp_uri.assign(req->uri.p + pos_start, i - pos_start); strs.push_back(tmp_uri); } - pos_start = i + 1; // ǰҵķָ + pos_start = i + 1; // 跳过当前找到的分隔符 } } if (pos_start < req->uri.len) @@ -485,7 +519,7 @@ int TsHttpRpc::_parse_request(struct http_message* req, ex_astr& func_cmd, ex_as if (func_args.length() > 0) { - // url-decode + // 将参数进行 url-decode 解码 int len = func_args.length() * 2; ex_chars sztmp; sztmp.resize(len); @@ -536,7 +570,7 @@ void TsHttpRpc::_process_js_request(const ex_astr& func_cmd, const ex_astr& func void TsHttpRpc::_create_json_ret(ex_astr& buf, int errcode) { - // أ {"code":123} + // 返回: {"code":123} Json::FastWriter jr_writer; Json::Value jr_root; @@ -551,13 +585,65 @@ void TsHttpRpc::_create_json_ret(ex_astr& buf, Json::Value& jr_root) buf = jr_writer.write(jr_root); } +void TsHttpRpc::_rpc_func_url_protocol(const ex_astr& args, ex_astr& buf) +{ + //处理urlprotocol调用访式 + // 将参数进行 url-decode 解码 + std::string func_args = args; + if (func_args.length() > 0) + { + int len = func_args.length() * 2; + ex_chars sztmp; + sztmp.resize(len); + memset(&sztmp[0], 0, len); + if (-1 == ts_url_decode(func_args.c_str(), func_args.length(), &sztmp[0], len, 0)) + return ; + + func_args = &sztmp[0]; + } + EXLOGD(("%s\n"), func_args.c_str()); + //处理传参过来的teleport://{}/,只保留参数部份 + std::string urlproto_appname = TP_URLPROTO_APP_NAME; + urlproto_appname += "://{"; + func_args.erase(0, urlproto_appname.length());//去除第一个URLPROTO_APP_NAME以及://字符 + int pos = func_args.length() - 1; + if (func_args.substr(pos, 1) == "/") + func_args.erase(pos - 1, 2);//去除最后一个}/字符 + else + func_args.erase(pos, 1); + + //由于命令行、ie浏览器参数传递时会把原来json结构中的"号去掉,需要重新格式化参数为json格式 + if (func_args.find("\"", 0) == std::string::npos) { + std::vector strv; + SplitString(func_args, strv, ","); + func_args = ""; + for (std::vector::size_type i = 0; i < strv.size(); i++) { + std::vector strv1; + SplitString(strv[i], strv1, ":"); + strv1[0] = "\"" + strv1[0] + "\""; + if (!isDegital(strv1[1]) && strtolower(strv1[1]) != "true" && strtolower(strv1[1]) != "false") + strv1[1] = "\"" + strv1[1] + "\""; + + strv[i] = strv1[0] + ":" + strv1[1]; + if (i == 0) + func_args = strv[i]; + else + func_args += "," + strv[i]; + } + } + func_args = "{" + func_args + "}"; + EXLOGD(("%s\n"), func_args.c_str()); + //调用TsHttpRpc类里的_rpc_func_run_client启动客户端 + _rpc_func_run_client(func_args, buf); +} + void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf) { - // Σ{"ip":"192.168.5.11","port":22,"uname":"root","uauth":"abcdefg","authmode":1,"protocol":2} + // 入参:{"ip":"192.168.5.11","port":22,"uname":"root","uauth":"abcdefg","authmode":1,"protocol":2} // authmode: 1=password, 2=private-key // protocol: 1=rdp, 2=ssh - // SSHأ {"code":0, "data":{"sid":"0123abcde"}} - // RDPأ {"code":0, "data":{"sid":"0123abcde0A"}} + // SSH返回: {"code":0, "data":{"sid":"0123abcde"}} + // RDP返回: {"code":0, "data":{"sid":"0123abcde0A"}} Json::Reader jreader; Json::Value jsRoot; @@ -573,7 +659,7 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf) return; } - // жϲǷȷ + // 判断参数是否正确 if (!jsRoot["teleport_ip"].isString() || !jsRoot["teleport_port"].isNumeric() || !jsRoot["remote_host_ip"].isString() || !jsRoot["session_id"].isString() || !jsRoot["protocol_type"].isNumeric() || !jsRoot["protocol_sub_type"].isNumeric() @@ -688,7 +774,7 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf) int iHeight = GetSystemMetrics(SM_CYSCREEN); if (rdp_w == 0 || rdp_h == 0) { - //ȫ + //全屏 width = iWidth; higth = iHeight; display = 2; @@ -763,7 +849,7 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf) fclose(f); ex_astr2wstr(sz_file_name, tmp_rdp_file); - // 滻 + // 变量替换 ex_replace_all(w_exe_path, _T("{tmp_rdp_file}"), tmp_rdp_file); } else if (g_cfg.rdp_name == L"freerdp") { @@ -773,7 +859,7 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf) ex_wstr w_screen; if (rdp_w == 0 || rdp_h == 0) { - //ȫ + //全屏 w_screen = _T("/f"); } else { @@ -800,10 +886,10 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf) w_sid = L"02" + w_sid; - w_exe_path += L" /gdi:sw"; // ʹȾgdi:hwʹӲ٣ǻֺܶڿ飨¼طʱģ - w_exe_path += L" -grab-keyboard"; // [new style] ֹFreeRDPʧȥؼӦСһFreeRDPڣòƲã + w_exe_path += L" /gdi:sw"; // 使用软件渲染,gdi:hw使用硬件加速,但是会出现很多黑块(录像回放时又是正常的!) + w_exe_path += L" -grab-keyboard"; // [new style] 防止启动FreeRDP后,失去本地键盘响应,必须得先最小化一下FreeRDP窗口(不过貌似不起作用) - // 滻 + // 变量替换 ex_replace_all(w_exe_path, _T("{size}"), w_screen); if (flag_console && rdp_console) @@ -899,7 +985,7 @@ void TsHttpRpc::_rpc_func_rdp_play(const ex_astr& func_args, ex_astr& buf) return; } - // жϲǷȷ + // 判断参数是否正确 if (!jsRoot["rid"].isInt() || !jsRoot["web"].isString() || !jsRoot["sid"].isString() @@ -924,9 +1010,9 @@ void TsHttpRpc::_rpc_func_rdp_play(const ex_astr& func_args, ex_astr& buf) char cmd_args[1024] = { 0 }; ex_strformat(cmd_args, 1023, "%d \"%s\" \"%09d-%s-%s-%s-%s\"", rid, a_sid.c_str(), rid, a_user.c_str(), a_acc.c_str(), a_host.c_str(), a_start.c_str()); - // TODO: ϲӦǰתΪIPIJӦý͸ɲԼȥ - // ڸFreeRDPIJʱΪ˴ӷļʹMongoose⣬⣨ò첽ѯDNS⣩ - // ʱֽIPת + // TODO: 理论上不应该由助手来提前做域名转为IP这样的操作,而是应该讲域名发送给播放器,由播放器自己去处理 + // 但是在改造FreeRDP制作的播放器时,为了从服务器上下载文件,使用了Mongoose库,如果传入的是域名,会出现问题(貌似是异步查询DNS的问题) + // 所以暂时先由助手进行域名IP转换。 { unsigned int port_i = 0; struct mg_str scheme, query, fragment, user_info, host, path; @@ -942,7 +1028,7 @@ void TsHttpRpc::_rpc_func_rdp_play(const ex_astr& func_args, ex_astr& buf) ex_astr _scheme; _scheme.assign(scheme.p, scheme.len); - // hostתΪIP + // 将host从域名转换为IP ex_astr str_tp_host; str_tp_host.assign(host.p, host.len); struct hostent *tp_host = gethostbyname(str_tp_host.c_str()); @@ -1052,7 +1138,7 @@ void TsHttpRpc::_rpc_func_file_action(const ex_astr& func_args, ex_astr& buf) { _create_json_ret(buf, TPE_JSON_FORMAT); return; } - // жϲǷȷ + // 判断参数是否正确 if (!jsRoot["action"].isNumeric()) { _create_json_ret(buf, TPE_PARAM); @@ -1077,9 +1163,9 @@ void TsHttpRpc::_rpc_func_file_action(const ex_astr& func_args, ex_astr& buf) { ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); - ofn.lpstrTitle = _T("ѡļ"); + ofn.lpstrTitle = _T("选择文件"); ofn.hwndOwner = hParent; - ofn.lpstrFilter = _T("ִг (*.exe)\0*.exe\0"); + ofn.lpstrFilter = _T("可执行程序 (*.exe)\0*.exe\0"); ofn.lpstrFile = wszReturnPath; ofn.nMaxFile = MAX_PATH; ofn.lpstrInitialDir = wsDefaultPath.c_str(); @@ -1102,12 +1188,12 @@ void TsHttpRpc::_rpc_func_file_action(const ex_astr& func_args, ex_astr& buf) { ZeroMemory(&bi, sizeof(BROWSEINFO)); bi.hwndOwner = NULL; bi.pidlRoot = NULL; - bi.pszDisplayName = wszReturnPath; //˲ΪNULLʾԻ - bi.lpszTitle = _T("ѡĿ¼"); + bi.pszDisplayName = wszReturnPath; //此参数如为NULL则不能显示对话框 + bi.lpszTitle = _T("选择目录"); bi.ulFlags = BIF_RETURNONLYFSDIRS; bi.lpfn = NULL; - bi.iImage = 0; //ʼڲbi - LPITEMIDLIST pIDList = SHBrowseForFolder(&bi);//ʾѡԻ + bi.iImage = 0; //初始化入口参数bi结束 + LPITEMIDLIST pIDList = SHBrowseForFolder(&bi);//调用显示选择对话框 if (pIDList) { ret = true;